// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). // this is a simple micro-benchmark for compare ribbon filter vs. other filter // for more comprehensive, please check the dedicate util/filter_bench. #include "benchmark/benchmark.h" #include "table/block_based/filter_policy_internal.h" #include "table/block_based/mock_block_based_table.h" namespace ROCKSDB_NAMESPACE { struct KeyMaker { explicit KeyMaker(size_t avg_size) : smallest_size_(avg_size), buf_size_(avg_size + 11), // pad to vary key size and alignment buf_(new char[buf_size_]) { memset(buf_.get(), 0, buf_size_); assert(smallest_size_ > 8); } size_t smallest_size_; size_t buf_size_; std::unique_ptr buf_; // Returns a unique(-ish) key based on the given parameter values. Each // call returns a Slice from the same buffer so previously returned // Slices should be considered invalidated. Slice Get(uint32_t filter_num, uint32_t val_num) const { size_t start = val_num % 4; size_t len = smallest_size_; // To get range [avg_size - 2, avg_size + 2] // use range [smallest_size, smallest_size + 4] len += FastRange32((val_num >> 5) * 1234567891, 5); char *data = buf_.get() + start; // Populate key data such that all data makes it into a key of at // least 8 bytes. We also don't want all the within-filter key // variance confined to a contiguous 32 bits, because then a 32 bit // hash function can "cheat" the false positive rate by // approximating a perfect hash. EncodeFixed32(data, val_num); EncodeFixed32(data + 4, filter_num + val_num); // ensure clearing leftovers from different alignment EncodeFixed32(data + 8, 0); return {data, len}; } }; // benchmark arguments: // 0. filter impl (like filter_bench -impl) // 1. filter config bits_per_key // 2. average data key length // 3. data entry number static void CustomArguments(benchmark::internal::Benchmark *b) { for (int filter_impl : {0, 2, 3}) { for (int bits_per_key : {10, 20}) { for (int key_len_avg : {10, 100}) { for (int64_t entry_num : {1 << 10, 1 << 20}) { b->Args({filter_impl, bits_per_key, key_len_avg, entry_num}); } } } } b->ArgNames({"filter_impl", "bits_per_key", "key_len_avg", "entry_num"}); } static void FilterBuild(benchmark::State &state) { // setup data auto filter = BloomLikeFilterPolicy::Create( BloomLikeFilterPolicy::GetAllFixedImpls().at(state.range(0)), static_cast(state.range(1))); auto tester = new mock::MockBlockBasedTableTester(filter); KeyMaker km(state.range(2)); std::unique_ptr owner; const int64_t kEntryNum = state.range(3); auto rnd = Random32(12345); uint32_t filter_num = rnd.Next(); // run the test for (auto _ : state) { std::unique_ptr builder(tester->GetBuilder()); for (uint32_t i = 0; i < kEntryNum; i++) { builder->AddKey(km.Get(filter_num, i)); } auto ret = builder->Finish(&owner); state.counters["size"] = static_cast(ret.size()); } } BENCHMARK(FilterBuild)->Apply(CustomArguments); static void FilterQueryPositive(benchmark::State &state) { // setup data auto filter = BloomLikeFilterPolicy::Create( BloomLikeFilterPolicy::GetAllFixedImpls().at(state.range(0)), static_cast(state.range(1))); auto tester = new mock::MockBlockBasedTableTester(filter); KeyMaker km(state.range(2)); std::unique_ptr owner; const int64_t kEntryNum = state.range(3); auto rnd = Random32(12345); uint32_t filter_num = rnd.Next(); std::unique_ptr builder(tester->GetBuilder()); for (uint32_t i = 0; i < kEntryNum; i++) { builder->AddKey(km.Get(filter_num, i)); } auto data = builder->Finish(&owner); auto reader = filter->GetFilterBitsReader(data); // run test uint32_t i = 0; for (auto _ : state) { i++; i = i % kEntryNum; reader->MayMatch(km.Get(filter_num, i)); } } BENCHMARK(FilterQueryPositive)->Apply(CustomArguments); static void FilterQueryNegative(benchmark::State &state) { // setup data auto filter = BloomLikeFilterPolicy::Create( BloomLikeFilterPolicy::GetAllFixedImpls().at(state.range(0)), static_cast(state.range(1))); auto tester = new mock::MockBlockBasedTableTester(filter); KeyMaker km(state.range(2)); std::unique_ptr owner; const int64_t kEntryNum = state.range(3); auto rnd = Random32(12345); uint32_t filter_num = rnd.Next(); std::unique_ptr builder(tester->GetBuilder()); for (uint32_t i = 0; i < kEntryNum; i++) { builder->AddKey(km.Get(filter_num, i)); } auto data = builder->Finish(&owner); auto reader = filter->GetFilterBitsReader(data); // run test uint32_t i = 0; double fp_cnt = 0; for (auto _ : state) { i++; auto result = reader->MayMatch(km.Get(filter_num + 1, i)); if (result) { fp_cnt++; } } state.counters["FP %"] = benchmark::Counter(fp_cnt * 100, benchmark::Counter::kAvgIterations); } BENCHMARK(FilterQueryNegative)->Apply(CustomArguments); } // namespace ROCKSDB_NAMESPACE BENCHMARK_MAIN();