Summary: It is a very simple benchmark to measure a Table implementation's Get() and iterator performance if all the data is in memory. Test Plan: N/A Reviewers: dhruba, haobo, kailiu Reviewed By: haobo CC: leveldb Differential Revision: https://reviews.facebook.net/D13743main
parent
8cbe5bb56b
commit
7caadf2e52
@ -0,0 +1,162 @@ |
||||
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
#include <gflags/gflags.h> |
||||
|
||||
#include "rocksdb/db.h" |
||||
#include "rocksdb/table.h" |
||||
#include "db/db_impl.h" |
||||
#include "table/block_based_table_factory.h" |
||||
#include "util/histogram.h" |
||||
#include "util/testharness.h" |
||||
#include "util/testutil.h" |
||||
|
||||
namespace rocksdb { |
||||
// Make a key that i determines the first 4 characters and j determines the
|
||||
// last 4 characters.
|
||||
static std::string MakeKey(int i, int j) { |
||||
char buf[100]; |
||||
snprintf(buf, sizeof(buf), "%04d__key___%04d ", i, j); |
||||
return std::string(buf); |
||||
} |
||||
|
||||
static bool DummySaveValue(void* arg, const Slice& ikey, const Slice& v, |
||||
bool didIO) { |
||||
return false; |
||||
} |
||||
|
||||
// A very simple benchmark that.
|
||||
// Create a table with roughly numKey1 * numKey2 keys,
|
||||
// where there are numKey1 prefixes of the key, each has numKey2 number of
|
||||
// distinguished key, differing in the suffix part.
|
||||
// If if_query_empty_keys = false, query the existing keys numKey1 * numKey2
|
||||
// times randomly.
|
||||
// If if_query_empty_keys = true, query numKey1 * numKey2 random empty keys.
|
||||
// Print out the total time.
|
||||
//
|
||||
// If for_terator=true, instead of just query one key each time, it queries
|
||||
// a range sharing the same prefix.
|
||||
void TableReaderBenchmark(Options& opts, EnvOptions& env_options, |
||||
ReadOptions& read_options, TableFactory* tf, |
||||
int num_keys1, int num_keys2, int num_iter, |
||||
bool if_query_empty_keys, bool for_iterator) { |
||||
std::string file_name = test::TmpDir() |
||||
+ "/rocksdb_table_reader_benchmark"; |
||||
ReadOptions ro; |
||||
unique_ptr<WritableFile> file; |
||||
Env* env = Env::Default(); |
||||
env->NewWritableFile(file_name, &file, env_options); |
||||
TableBuilder* tb = tf->GetTableBuilder(opts, file.get(), |
||||
CompressionType::kNoCompression); |
||||
|
||||
// Populate slightly more than 1M keys
|
||||
for (int i = 0; i < num_keys1; i++) { |
||||
for (int j = 0; j < num_keys2; j++) { |
||||
std::string key = MakeKey(i * 2, j); |
||||
tb->Add(key, key); |
||||
} |
||||
} |
||||
tb->Finish(); |
||||
file->Close(); |
||||
|
||||
unique_ptr<TableReader> table_reader; |
||||
unique_ptr<RandomAccessFile> raf; |
||||
Status s = env->NewRandomAccessFile(file_name, &raf, env_options); |
||||
uint64_t file_size; |
||||
env->GetFileSize(file_name, &file_size); |
||||
s = tf->GetTableReader(opts, env_options, std::move(raf), file_size, |
||||
&table_reader); |
||||
|
||||
Random rnd(301); |
||||
HistogramImpl hist; |
||||
|
||||
void* arg = nullptr; |
||||
for (int it = 0; it < num_iter; it++) { |
||||
for (int i = 0; i < num_keys1; i++) { |
||||
for (int j = 0; j < num_keys2; j++) { |
||||
int r1 = rnd.Uniform(num_keys1) * 2; |
||||
int r2 = rnd.Uniform(num_keys2); |
||||
if (!for_iterator) { |
||||
if (if_query_empty_keys) { |
||||
r1++; |
||||
r2 = num_keys2 * 2 - r2; |
||||
} |
||||
// Query one existing key;
|
||||
std::string key = MakeKey(r1, r2); |
||||
uint64_t start_micros = env->NowMicros(); |
||||
s = table_reader->Get(ro, key, arg, DummySaveValue, nullptr); |
||||
hist.Add(env->NowMicros() - start_micros); |
||||
} else { |
||||
int r2_len = rnd.Uniform(num_keys2) + 1; |
||||
if (r2_len + r2 > num_keys2) { |
||||
r2_len = num_keys2 - r2; |
||||
} |
||||
std::string start_key = MakeKey(r1, r2); |
||||
std::string end_key = MakeKey(r1, r2 + r2_len); |
||||
uint64_t first_part_time = 0; |
||||
uint64_t start_micros = env->NowMicros(); |
||||
Iterator* iter = table_reader->NewIterator(read_options); |
||||
int count = 0; |
||||
for(iter->Seek(start_key); iter->Valid(); iter->Next()) { |
||||
// verify key;
|
||||
first_part_time = env->NowMicros() - start_micros; |
||||
assert(Slice(MakeKey(r1, r2 + count)) == iter->key()); |
||||
start_micros = env->NowMicros(); |
||||
if (++count >= r2_len) { |
||||
break; |
||||
} |
||||
} |
||||
if (count != r2_len) { |
||||
fprintf( |
||||
stderr, "Iterator cannot iterate expected number of entries. " |
||||
"Expected %d but got %d\n", r2_len, count); |
||||
assert(false); |
||||
} |
||||
delete iter; |
||||
hist.Add(first_part_time + env->NowMicros() - start_micros); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
fprintf( |
||||
stderr, |
||||
"===================================================" |
||||
"====================================================\n" |
||||
"InMemoryTableSimpleBenchmark: %20s num_key1: %5d " |
||||
"num_key2: %5d %10s\n" |
||||
"===================================================" |
||||
"====================================================" |
||||
"\nHistogram (unit: nanoseconds): \n%s", |
||||
tf->Name(), num_keys1, num_keys2, |
||||
for_iterator? "iterator" : (if_query_empty_keys ? "empty" : "non_empty"), |
||||
hist.ToString().c_str()); |
||||
env->DeleteFile(file_name); |
||||
} |
||||
} // namespace rocksdb
|
||||
|
||||
DEFINE_bool(query_empty, false, "query non-existing keys instead of existing " |
||||
"ones."); |
||||
DEFINE_int32(num_keys1, 4096, "number of distinguish prefix of keys"); |
||||
DEFINE_int32(num_keys2, 512, "number of distinguish keys for each prefix"); |
||||
DEFINE_int32(iter, 3, "query non-existing keys instead of existing ones"); |
||||
DEFINE_bool(iterator, false, "For test iterator"); |
||||
|
||||
int main(int argc, char** argv) { |
||||
google::SetUsageMessage(std::string("\nUSAGE:\n") + std::string(argv[0]) + |
||||
" [OPTIONS]..."); |
||||
google::ParseCommandLineFlags(&argc, &argv, true); |
||||
|
||||
rocksdb::TableFactory* tf; |
||||
rocksdb::Options options; |
||||
rocksdb::ReadOptions ro; |
||||
rocksdb::EnvOptions env_options; |
||||
tf = new rocksdb::BlockBasedTableFactory(); |
||||
TableReaderBenchmark(options, env_options, ro, tf, FLAGS_num_keys1, |
||||
FLAGS_num_keys2, FLAGS_iter, FLAGS_query_empty, |
||||
FLAGS_iterator); |
||||
delete tf; |
||||
return 0; |
||||
} |
Loading…
Reference in new issue