[RocksDB] Expose thread local perf counter for low overhead, per call level performance statistics.
Summary: As title. No locking/atomic is needed due to thread local. There is also no need to modify the existing client interface, in order to expose related counters. perf_context_test shows a simple example of retrieving the number of user key comparison done for each put and get call. More counters could be added later. Sample output ./perf_context_test 1000000 ==== Test PerfContextTest.KeyComparisonCount Inserting 1000000 key/value pairs ... total user key comparison get: 43446523 total user key comparison put: 8017877 max user key comparison get: 88939 avg user key comparison get:43 Basically, the current skiplist does well on average, but could perform poorly in extreme cases. Test Plan: run perf_context_test <total number of entries to put/get> Reviewers: dhruba Differential Revision: https://reviews.facebook.net/D12225
This commit is contained in:
parent
a8f47a4006
commit
d9dd2a1926
3
Makefile
3
Makefile
@ -210,6 +210,9 @@ crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
|||||||
db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||||
$(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
$(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
||||||
|
|
||||||
|
perf_context_test: db/perf_context_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||||
|
$(CXX) db/perf_context_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
ttl_test: utilities/ttl/ttl_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
ttl_test: utilities/ttl/ttl_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||||
$(CXX) utilities/ttl/ttl_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
$(CXX) utilities/ttl/ttl_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "db/dbformat.h"
|
#include "db/dbformat.h"
|
||||||
#include "port/port.h"
|
#include "port/port.h"
|
||||||
#include "util/coding.h"
|
#include "util/coding.h"
|
||||||
|
#include "include/leveldb/perf_context.h"
|
||||||
|
|
||||||
namespace leveldb {
|
namespace leveldb {
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
|
|||||||
// decreasing sequence number
|
// decreasing sequence number
|
||||||
// decreasing type (though sequence# should be enough to disambiguate)
|
// decreasing type (though sequence# should be enough to disambiguate)
|
||||||
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
||||||
|
perf_context.user_key_comparison_count++;
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
|
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
|
||||||
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
|
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
|
||||||
|
12
db/perf_context.cc
Normal file
12
db/perf_context.cc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "include/leveldb/perf_context.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace leveldb {
|
||||||
|
|
||||||
|
void PerfContext::Reset() {
|
||||||
|
user_key_comparison_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__thread PerfContext perf_context;
|
||||||
|
|
||||||
|
}
|
81
db/perf_context_test.cc
Normal file
81
db/perf_context_test.cc
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "leveldb/db.h"
|
||||||
|
#include "leveldb/perf_context.h"
|
||||||
|
#include "util/testharness.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace leveldb {
|
||||||
|
|
||||||
|
// Path to the database on file system
|
||||||
|
const std::string kDbName = test::TmpDir() + "/perf_context_test";
|
||||||
|
|
||||||
|
std::shared_ptr<DB> OpenDb() {
|
||||||
|
DB* db;
|
||||||
|
Options options;
|
||||||
|
options.create_if_missing = true;
|
||||||
|
options.write_buffer_size = 1000000000; // give it a big memtable
|
||||||
|
Status s = DB::Open(options, kDbName, &db);
|
||||||
|
ASSERT_OK(s);
|
||||||
|
return std::shared_ptr<DB>(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PerfContextTest { };
|
||||||
|
|
||||||
|
int kTotalKeys = 100;
|
||||||
|
|
||||||
|
TEST(PerfContextTest, KeyComparisonCount) {
|
||||||
|
|
||||||
|
DestroyDB(kDbName, Options()); // Start this test with a fresh DB
|
||||||
|
|
||||||
|
auto db = OpenDb();
|
||||||
|
|
||||||
|
WriteOptions write_options;
|
||||||
|
ReadOptions read_options;
|
||||||
|
|
||||||
|
uint64_t total_user_key_comparison_get = 0;
|
||||||
|
uint64_t total_user_key_comparison_put = 0;
|
||||||
|
uint64_t max_user_key_comparison_get = 0;
|
||||||
|
|
||||||
|
std::cout << "Inserting " << kTotalKeys << " key/value pairs\n...\n";
|
||||||
|
|
||||||
|
for (int i = 0; i < kTotalKeys; ++i) {
|
||||||
|
std::string key = "k" + std::to_string(i);
|
||||||
|
std::string value = "v" + std::to_string(i);
|
||||||
|
|
||||||
|
perf_context.Reset();
|
||||||
|
db->Put(write_options, key, value);
|
||||||
|
total_user_key_comparison_put += perf_context.user_key_comparison_count;
|
||||||
|
|
||||||
|
perf_context.Reset();
|
||||||
|
db->Get(read_options, key, &value);
|
||||||
|
total_user_key_comparison_get += perf_context.user_key_comparison_count;
|
||||||
|
max_user_key_comparison_get =
|
||||||
|
std::max(max_user_key_comparison_get,
|
||||||
|
perf_context.user_key_comparison_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "total user key comparison get: "
|
||||||
|
<< total_user_key_comparison_get << "\n"
|
||||||
|
<< "total user key comparison put: "
|
||||||
|
<< total_user_key_comparison_put << "\n"
|
||||||
|
<< "max user key comparison get: "
|
||||||
|
<< max_user_key_comparison_get << "\n"
|
||||||
|
<< "avg user key comparison get:"
|
||||||
|
<< total_user_key_comparison_get/kTotalKeys << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
leveldb::kTotalKeys = std::stoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
leveldb::test::RunAllTests();
|
||||||
|
return 0;
|
||||||
|
}
|
24
include/leveldb/perf_context.h
Normal file
24
include/leveldb/perf_context.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef STORAGE_LEVELDB_INCLUDE_PERF_CONTEXT_H
|
||||||
|
#define STORAGE_LEVELDB_INCLUDE_PERF_CONTEXT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace leveldb {
|
||||||
|
|
||||||
|
// A thread local context for gathering performance counter efficiently
|
||||||
|
// and transparently.
|
||||||
|
|
||||||
|
struct PerfContext {
|
||||||
|
|
||||||
|
void Reset(); // reset all performance counters to zero
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t user_key_comparison_count; // total number of user key comparisons
|
||||||
|
};
|
||||||
|
|
||||||
|
extern __thread PerfContext perf_context;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user