Avoid unnecessary big for-loop when reporting ticker stats stored in GetContext (#3490)

Summary:
Currently in `Version::Get` when reporting ticker stats stored in `GetContext`, there is a big for-loop through all `Ticker` which adds unnecessary cost to overall CPU usage. We can optimize by storing only ticker values that are used in `Get()` calls in a new struct `GetContextStats` since only a small fraction of all tickers are used in `Get()` calls. For comparison, with the new approach we only need to visit 17 values while old approach will require visiting 100+ `Ticker`
Pull Request resolved: https://github.com/facebook/rocksdb/pull/3490

Differential Revision: D6969154

Pulled By: miasantreble

fbshipit-source-id: fc27072965a3a94125a3e6883d20dafcf5b84029
main
Zhongyi Xie 6 years ago committed by Facebook Github Bot
parent 6811fb0658
commit f95a5b2464
  1. 15
      db/version_set.cc
  2. 86
      table/block_based_table_reader.cc
  3. 70
      table/get_context.cc
  4. 24
      table/get_context.h

@ -1212,12 +1212,9 @@ void Version::Get(const ReadOptions& read_options, const LookupKey& k,
// report the counters before returning // report the counters before returning
if (get_context.State() != GetContext::kNotFound && if (get_context.State() != GetContext::kNotFound &&
get_context.State() != GetContext::kMerge) { get_context.State() != GetContext::kMerge &&
for (uint32_t t = 0; t < Tickers::TICKER_ENUM_MAX; t++) { db_statistics_ != nullptr) {
if (get_context.tickers_value[t] > 0) { get_context.ReportCounters();
RecordTick(db_statistics_, t, get_context.tickers_value[t]);
}
}
} }
switch (get_context.State()) { switch (get_context.State()) {
case GetContext::kNotFound: case GetContext::kNotFound:
@ -1251,10 +1248,8 @@ void Version::Get(const ReadOptions& read_options, const LookupKey& k,
f = fp.GetNextFile(); f = fp.GetNextFile();
} }
for (uint32_t t = 0; t < Tickers::TICKER_ENUM_MAX; t++) { if (db_statistics_ != nullptr) {
if (get_context.tickers_value[t] > 0) { get_context.ReportCounters();
RecordTick(db_statistics_, t, get_context.tickers_value[t]);
}
} }
if (GetContext::kMerge == get_context.State()) { if (GetContext::kMerge == get_context.State()) {
if (!merge_operator_) { if (!merge_operator_) {

@ -137,6 +137,8 @@ Slice GetCacheKeyFromOffset(const char* cache_key_prefix,
Cache::Handle* GetEntryFromCache(Cache* block_cache, const Slice& key, Cache::Handle* GetEntryFromCache(Cache* block_cache, const Slice& key,
Tickers block_cache_miss_ticker, Tickers block_cache_miss_ticker,
Tickers block_cache_hit_ticker, Tickers block_cache_hit_ticker,
uint64_t* block_cache_miss_stats,
uint64_t* block_cache_hit_stats,
Statistics* statistics, Statistics* statistics,
GetContext* get_context) { GetContext* get_context) {
auto cache_handle = block_cache->Lookup(key, statistics); auto cache_handle = block_cache->Lookup(key, statistics);
@ -144,12 +146,12 @@ Cache::Handle* GetEntryFromCache(Cache* block_cache, const Slice& key,
PERF_COUNTER_ADD(block_cache_hit_count, 1); PERF_COUNTER_ADD(block_cache_hit_count, 1);
if (get_context != nullptr) { if (get_context != nullptr) {
// overall cache hit // overall cache hit
get_context->RecordCounters(BLOCK_CACHE_HIT, 1); get_context->get_context_stats_.num_cache_hit++;
// total bytes read from cache // total bytes read from cache
get_context->RecordCounters(BLOCK_CACHE_BYTES_READ, get_context->get_context_stats_.num_cache_bytes_read +=
block_cache->GetUsage(cache_handle)); block_cache->GetUsage(cache_handle);
// block-type specific cache hit // block-type specific cache hit
get_context->RecordCounters(block_cache_hit_ticker, 1); (*block_cache_hit_stats)++;
} else { } else {
// overall cache hit // overall cache hit
RecordTick(statistics, BLOCK_CACHE_HIT); RecordTick(statistics, BLOCK_CACHE_HIT);
@ -161,9 +163,9 @@ Cache::Handle* GetEntryFromCache(Cache* block_cache, const Slice& key,
} else { } else {
if (get_context != nullptr) { if (get_context != nullptr) {
// overall cache miss // overall cache miss
get_context->RecordCounters(BLOCK_CACHE_MISS, 1); get_context->get_context_stats_.num_cache_miss++;
// block-type specific cache miss // block-type specific cache miss
get_context->RecordCounters(block_cache_miss_ticker, 1); (*block_cache_miss_stats)++;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_MISS); RecordTick(statistics, BLOCK_CACHE_MISS);
RecordTick(statistics, block_cache_miss_ticker); RecordTick(statistics, block_cache_miss_ticker);
@ -1166,8 +1168,16 @@ Status BlockBasedTable::GetDataBlockFromCache(
block->cache_handle = GetEntryFromCache( block->cache_handle = GetEntryFromCache(
block_cache, block_cache_key, block_cache, block_cache_key,
is_index ? BLOCK_CACHE_INDEX_MISS : BLOCK_CACHE_DATA_MISS, is_index ? BLOCK_CACHE_INDEX_MISS : BLOCK_CACHE_DATA_MISS,
is_index ? BLOCK_CACHE_INDEX_HIT : BLOCK_CACHE_DATA_HIT, statistics, is_index ? BLOCK_CACHE_INDEX_HIT : BLOCK_CACHE_DATA_HIT,
get_context); get_context
? (is_index ? &get_context->get_context_stats_.num_cache_index_miss
: &get_context->get_context_stats_.num_cache_data_miss)
: nullptr,
get_context
? (is_index ? &get_context->get_context_stats_.num_cache_index_hit
: &get_context->get_context_stats_.num_cache_data_hit)
: nullptr,
statistics, get_context);
if (block->cache_handle != nullptr) { if (block->cache_handle != nullptr) {
block->value = block->value =
reinterpret_cast<Block*>(block_cache->Value(block->cache_handle)); reinterpret_cast<Block*>(block_cache->Value(block->cache_handle));
@ -1222,24 +1232,26 @@ Status BlockBasedTable::GetDataBlockFromCache(
block_cache->TEST_mark_as_data_block(block_cache_key, charge); block_cache->TEST_mark_as_data_block(block_cache_key, charge);
if (s.ok()) { if (s.ok()) {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1); get_context->get_context_stats_.num_cache_add++;
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, charge); get_context->get_context_stats_.num_cache_bytes_write += charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_ADD); RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge); RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge);
} }
if (is_index) { if (is_index) {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_INDEX_ADD, 1); get_context->get_context_stats_.num_cache_index_add++;
get_context->RecordCounters(BLOCK_CACHE_INDEX_BYTES_INSERT, charge); get_context->get_context_stats_.num_cache_index_bytes_insert +=
charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_INDEX_ADD); RecordTick(statistics, BLOCK_CACHE_INDEX_ADD);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge); RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
} }
} else { } else {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_DATA_ADD, 1); get_context->get_context_stats_.num_cache_data_add++;
get_context->RecordCounters(BLOCK_CACHE_DATA_BYTES_INSERT, charge); get_context->get_context_stats_.num_cache_data_bytes_insert +=
charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_DATA_ADD); RecordTick(statistics, BLOCK_CACHE_DATA_ADD);
RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT, charge); RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT, charge);
@ -1321,24 +1333,25 @@ Status BlockBasedTable::PutDataBlockToCache(
if (s.ok()) { if (s.ok()) {
assert(block->cache_handle != nullptr); assert(block->cache_handle != nullptr);
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1); get_context->get_context_stats_.num_cache_add++;
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, charge); get_context->get_context_stats_.num_cache_bytes_write += charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_ADD); RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge); RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge);
} }
if (is_index) { if (is_index) {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_INDEX_ADD, 1); get_context->get_context_stats_.num_cache_index_add++;
get_context->RecordCounters(BLOCK_CACHE_INDEX_BYTES_INSERT, charge); get_context->get_context_stats_.num_cache_index_bytes_insert +=
charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_INDEX_ADD); RecordTick(statistics, BLOCK_CACHE_INDEX_ADD);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge); RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
} }
} else { } else {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_DATA_ADD, 1); get_context->get_context_stats_.num_cache_data_add++;
get_context->RecordCounters(BLOCK_CACHE_DATA_BYTES_INSERT, charge); get_context->get_context_stats_.num_cache_data_bytes_insert += charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_DATA_ADD); RecordTick(statistics, BLOCK_CACHE_DATA_ADD);
RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT, charge); RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT, charge);
@ -1463,9 +1476,13 @@ BlockBasedTable::CachableEntry<FilterBlockReader> BlockBasedTable::GetFilter(
filter_blk_handle, cache_key); filter_blk_handle, cache_key);
Statistics* statistics = rep_->ioptions.statistics; Statistics* statistics = rep_->ioptions.statistics;
auto cache_handle = auto cache_handle = GetEntryFromCache(
GetEntryFromCache(block_cache, key, BLOCK_CACHE_FILTER_MISS, block_cache, key, BLOCK_CACHE_FILTER_MISS, BLOCK_CACHE_FILTER_HIT,
BLOCK_CACHE_FILTER_HIT, statistics, get_context); get_context ? &get_context->get_context_stats_.num_cache_filter_miss
: nullptr,
get_context ? &get_context->get_context_stats_.num_cache_filter_hit
: nullptr,
statistics, get_context);
FilterBlockReader* filter = nullptr; FilterBlockReader* filter = nullptr;
if (cache_handle != nullptr) { if (cache_handle != nullptr) {
@ -1486,10 +1503,11 @@ BlockBasedTable::CachableEntry<FilterBlockReader> BlockBasedTable::GetFilter(
: Cache::Priority::LOW); : Cache::Priority::LOW);
if (s.ok()) { if (s.ok()) {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1); get_context->get_context_stats_.num_cache_add++;
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, usage); get_context->get_context_stats_.num_cache_bytes_write += usage;
get_context->RecordCounters(BLOCK_CACHE_FILTER_ADD, 1); get_context->get_context_stats_.num_cache_filter_add++;
get_context->RecordCounters(BLOCK_CACHE_FILTER_BYTES_INSERT, usage); get_context->get_context_stats_.num_cache_filter_bytes_insert +=
usage;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_ADD); RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, usage); RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, usage);
@ -1535,9 +1553,13 @@ InternalIterator* BlockBasedTable::NewIndexIterator(
GetCacheKeyFromOffset(rep_->cache_key_prefix, rep_->cache_key_prefix_size, GetCacheKeyFromOffset(rep_->cache_key_prefix, rep_->cache_key_prefix_size,
rep_->dummy_index_reader_offset, cache_key); rep_->dummy_index_reader_offset, cache_key);
Statistics* statistics = rep_->ioptions.statistics; Statistics* statistics = rep_->ioptions.statistics;
auto cache_handle = auto cache_handle = GetEntryFromCache(
GetEntryFromCache(block_cache, key, BLOCK_CACHE_INDEX_MISS, block_cache, key, BLOCK_CACHE_INDEX_MISS, BLOCK_CACHE_INDEX_HIT,
BLOCK_CACHE_INDEX_HIT, statistics, get_context); get_context ? &get_context->get_context_stats_.num_cache_index_miss
: nullptr,
get_context ? &get_context->get_context_stats_.num_cache_index_hit
: nullptr,
statistics, get_context);
if (cache_handle == nullptr && no_io) { if (cache_handle == nullptr && no_io) {
if (input_iter != nullptr) { if (input_iter != nullptr) {
@ -1573,8 +1595,8 @@ InternalIterator* BlockBasedTable::NewIndexIterator(
if (s.ok()) { if (s.ok()) {
if (get_context != nullptr) { if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1); get_context->get_context_stats_.num_cache_add++;
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, charge); get_context->get_context_stats_.num_cache_bytes_write += charge;
} else { } else {
RecordTick(statistics, BLOCK_CACHE_ADD); RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge); RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge);

@ -91,11 +91,73 @@ void GetContext::SaveValue(const Slice& value, SequenceNumber /*seq*/) {
} }
} }
void GetContext::RecordCounters(Tickers ticker, size_t val) { void GetContext::ReportCounters() {
if (ticker == Tickers::TICKER_ENUM_MAX) { if (get_context_stats_.num_cache_hit > 0) {
return; RecordTick(statistics_, BLOCK_CACHE_HIT, get_context_stats_.num_cache_hit);
}
if (get_context_stats_.num_cache_index_hit > 0) {
RecordTick(statistics_, BLOCK_CACHE_INDEX_HIT,
get_context_stats_.num_cache_index_hit);
}
if (get_context_stats_.num_cache_data_hit > 0) {
RecordTick(statistics_, BLOCK_CACHE_DATA_HIT,
get_context_stats_.num_cache_data_hit);
}
if (get_context_stats_.num_cache_filter_hit > 0) {
RecordTick(statistics_, BLOCK_CACHE_FILTER_HIT,
get_context_stats_.num_cache_filter_hit);
}
if (get_context_stats_.num_cache_index_miss > 0) {
RecordTick(statistics_, BLOCK_CACHE_INDEX_MISS,
get_context_stats_.num_cache_index_miss);
}
if (get_context_stats_.num_cache_filter_miss > 0) {
RecordTick(statistics_, BLOCK_CACHE_FILTER_MISS,
get_context_stats_.num_cache_filter_miss);
}
if (get_context_stats_.num_cache_data_miss > 0) {
RecordTick(statistics_, BLOCK_CACHE_DATA_MISS,
get_context_stats_.num_cache_data_miss);
}
if (get_context_stats_.num_cache_bytes_read > 0) {
RecordTick(statistics_, BLOCK_CACHE_BYTES_READ,
get_context_stats_.num_cache_bytes_read);
}
if (get_context_stats_.num_cache_miss > 0) {
RecordTick(statistics_, BLOCK_CACHE_MISS,
get_context_stats_.num_cache_miss);
}
if (get_context_stats_.num_cache_add > 0) {
RecordTick(statistics_, BLOCK_CACHE_ADD, get_context_stats_.num_cache_add);
}
if (get_context_stats_.num_cache_bytes_write > 0) {
RecordTick(statistics_, BLOCK_CACHE_BYTES_WRITE,
get_context_stats_.num_cache_bytes_write);
}
if (get_context_stats_.num_cache_index_add > 0) {
RecordTick(statistics_, BLOCK_CACHE_INDEX_ADD,
get_context_stats_.num_cache_index_add);
}
if (get_context_stats_.num_cache_index_bytes_insert > 0) {
RecordTick(statistics_, BLOCK_CACHE_INDEX_BYTES_INSERT,
get_context_stats_.num_cache_index_bytes_insert);
}
if (get_context_stats_.num_cache_data_add > 0) {
RecordTick(statistics_, BLOCK_CACHE_DATA_ADD,
get_context_stats_.num_cache_data_add);
}
if (get_context_stats_.num_cache_data_bytes_insert > 0) {
RecordTick(statistics_, BLOCK_CACHE_DATA_BYTES_INSERT,
get_context_stats_.num_cache_data_bytes_insert);
}
if (get_context_stats_.num_cache_filter_add > 0) {
RecordTick(statistics_, BLOCK_CACHE_FILTER_ADD,
get_context_stats_.num_cache_filter_add);
}
if (get_context_stats_.num_cache_filter_bytes_insert > 0) {
RecordTick(statistics_, BLOCK_CACHE_FILTER_BYTES_INSERT,
get_context_stats_.num_cache_filter_bytes_insert);
} }
tickers_value[ticker] += static_cast<uint64_t>(val);
} }
bool GetContext::SaveValue(const ParsedInternalKey& parsed_key, bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,

@ -17,6 +17,26 @@ namespace rocksdb {
class MergeContext; class MergeContext;
class PinnedIteratorsManager; class PinnedIteratorsManager;
struct GetContextStats {
uint64_t num_cache_hit = 0;
uint64_t num_cache_index_hit = 0;
uint64_t num_cache_data_hit = 0;
uint64_t num_cache_filter_hit = 0;
uint64_t num_cache_index_miss = 0;
uint64_t num_cache_filter_miss = 0;
uint64_t num_cache_data_miss = 0;
uint64_t num_cache_bytes_read = 0;
uint64_t num_cache_miss = 0;
uint64_t num_cache_add = 0;
uint64_t num_cache_bytes_write = 0;
uint64_t num_cache_index_add = 0;
uint64_t num_cache_index_bytes_insert = 0;
uint64_t num_cache_data_add = 0;
uint64_t num_cache_data_bytes_insert = 0;
uint64_t num_cache_filter_add = 0;
uint64_t num_cache_filter_bytes_insert = 0;
};
class GetContext { class GetContext {
public: public:
enum GetState { enum GetState {
@ -27,7 +47,7 @@ class GetContext {
kMerge, // saver contains the current merge result (the operands) kMerge, // saver contains the current merge result (the operands)
kBlobIndex, kBlobIndex,
}; };
uint64_t tickers_value[Tickers::TICKER_ENUM_MAX] = {0}; GetContextStats get_context_stats_;
GetContext(const Comparator* ucmp, const MergeOperator* merge_operator, GetContext(const Comparator* ucmp, const MergeOperator* merge_operator,
Logger* logger, Statistics* statistics, GetState init_state, Logger* logger, Statistics* statistics, GetState init_state,
@ -77,7 +97,7 @@ class GetContext {
return true; return true;
} }
void RecordCounters(Tickers ticker, size_t val); void ReportCounters();
private: private:
const Comparator* ucmp_; const Comparator* ucmp_;

Loading…
Cancel
Save