ribbon_bench.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. // this is a simple micro-benchmark for compare ribbon filter vs. other filter
  6. // for more comprehensive, please check the dedicate util/filter_bench.
  7. #include "benchmark/benchmark.h"
  8. #include "table/block_based/filter_policy_internal.h"
  9. #include "table/block_based/mock_block_based_table.h"
  10. namespace ROCKSDB_NAMESPACE {
  11. struct KeyMaker {
  12. explicit KeyMaker(size_t avg_size)
  13. : smallest_size_(avg_size),
  14. buf_size_(avg_size + 11), // pad to vary key size and alignment
  15. buf_(new char[buf_size_]) {
  16. memset(buf_.get(), 0, buf_size_);
  17. assert(smallest_size_ > 8);
  18. }
  19. size_t smallest_size_;
  20. size_t buf_size_;
  21. std::unique_ptr<char[]> buf_;
  22. // Returns a unique(-ish) key based on the given parameter values. Each
  23. // call returns a Slice from the same buffer so previously returned
  24. // Slices should be considered invalidated.
  25. Slice Get(uint32_t filter_num, uint32_t val_num) const {
  26. size_t start = val_num % 4;
  27. size_t len = smallest_size_;
  28. // To get range [avg_size - 2, avg_size + 2]
  29. // use range [smallest_size, smallest_size + 4]
  30. len += FastRange32((val_num >> 5) * 1234567891, 5);
  31. char *data = buf_.get() + start;
  32. // Populate key data such that all data makes it into a key of at
  33. // least 8 bytes. We also don't want all the within-filter key
  34. // variance confined to a contiguous 32 bits, because then a 32 bit
  35. // hash function can "cheat" the false positive rate by
  36. // approximating a perfect hash.
  37. EncodeFixed32(data, val_num);
  38. EncodeFixed32(data + 4, filter_num + val_num);
  39. // ensure clearing leftovers from different alignment
  40. EncodeFixed32(data + 8, 0);
  41. return {data, len};
  42. }
  43. };
  44. // benchmark arguments:
  45. // 0. filter impl (like filter_bench -impl)
  46. // 1. filter config bits_per_key
  47. // 2. average data key length
  48. // 3. data entry number
  49. static void CustomArguments(benchmark::internal::Benchmark *b) {
  50. const auto kImplCount =
  51. static_cast<int>(BloomLikeFilterPolicy::GetAllFixedImpls().size());
  52. for (int filter_impl = 0; filter_impl < kImplCount; ++filter_impl) {
  53. for (int bits_per_key : {10, 20}) {
  54. for (int key_len_avg : {10, 100}) {
  55. for (int64_t entry_num : {1 << 10, 1 << 20}) {
  56. b->Args({filter_impl, bits_per_key, key_len_avg, entry_num});
  57. }
  58. }
  59. }
  60. }
  61. b->ArgNames({"filter_impl", "bits_per_key", "key_len_avg", "entry_num"});
  62. }
  63. static void FilterBuild(benchmark::State &state) {
  64. // setup data
  65. auto filter = BloomLikeFilterPolicy::Create(
  66. BloomLikeFilterPolicy::GetAllFixedImpls().at(state.range(0)),
  67. static_cast<double>(state.range(1)));
  68. auto tester = std::make_unique<mock::MockBlockBasedTableTester>(filter);
  69. KeyMaker km(state.range(2));
  70. std::unique_ptr<const char[]> owner;
  71. const int64_t kEntryNum = state.range(3);
  72. auto rnd = Random32(12345);
  73. uint32_t filter_num = rnd.Next();
  74. // run the test
  75. for (auto _ : state) {
  76. std::unique_ptr<FilterBitsBuilder> builder(tester->GetBuilder());
  77. for (uint32_t i = 0; i < kEntryNum; i++) {
  78. builder->AddKey(km.Get(filter_num, i));
  79. }
  80. auto ret = builder->Finish(&owner);
  81. state.counters["size"] = static_cast<double>(ret.size());
  82. }
  83. }
  84. BENCHMARK(FilterBuild)->Apply(CustomArguments);
  85. static void FilterQueryPositive(benchmark::State &state) {
  86. // setup data
  87. auto filter = BloomLikeFilterPolicy::Create(
  88. BloomLikeFilterPolicy::GetAllFixedImpls().at(state.range(0)),
  89. static_cast<double>(state.range(1)));
  90. auto tester = std::make_unique<mock::MockBlockBasedTableTester>(filter);
  91. KeyMaker km(state.range(2));
  92. std::unique_ptr<const char[]> owner;
  93. const int64_t kEntryNum = state.range(3);
  94. auto rnd = Random32(12345);
  95. uint32_t filter_num = rnd.Next();
  96. std::unique_ptr<FilterBitsBuilder> builder(tester->GetBuilder());
  97. for (uint32_t i = 0; i < kEntryNum; i++) {
  98. builder->AddKey(km.Get(filter_num, i));
  99. }
  100. auto data = builder->Finish(&owner);
  101. std::unique_ptr<FilterBitsReader> reader{filter->GetFilterBitsReader(data)};
  102. // run test
  103. uint32_t i = 0;
  104. for (auto _ : state) {
  105. i++;
  106. i = i % kEntryNum;
  107. reader->MayMatch(km.Get(filter_num, i));
  108. }
  109. }
  110. BENCHMARK(FilterQueryPositive)->Apply(CustomArguments);
  111. static void FilterQueryNegative(benchmark::State &state) {
  112. // setup data
  113. auto filter = BloomLikeFilterPolicy::Create(
  114. BloomLikeFilterPolicy::GetAllFixedImpls().at(state.range(0)),
  115. static_cast<double>(state.range(1)));
  116. auto tester = std::make_unique<mock::MockBlockBasedTableTester>(filter);
  117. KeyMaker km(state.range(2));
  118. std::unique_ptr<const char[]> owner;
  119. const int64_t kEntryNum = state.range(3);
  120. auto rnd = Random32(12345);
  121. uint32_t filter_num = rnd.Next();
  122. std::unique_ptr<FilterBitsBuilder> builder(tester->GetBuilder());
  123. for (uint32_t i = 0; i < kEntryNum; i++) {
  124. builder->AddKey(km.Get(filter_num, i));
  125. }
  126. auto data = builder->Finish(&owner);
  127. std::unique_ptr<FilterBitsReader> reader{filter->GetFilterBitsReader(data)};
  128. // run test
  129. uint32_t i = 0;
  130. double fp_cnt = 0;
  131. for (auto _ : state) {
  132. i++;
  133. auto result = reader->MayMatch(km.Get(filter_num + 1, i));
  134. if (result) {
  135. fp_cnt++;
  136. }
  137. }
  138. state.counters["fp_pct"] =
  139. benchmark::Counter(fp_cnt * 100, benchmark::Counter::kAvgIterations);
  140. }
  141. BENCHMARK(FilterQueryNegative)->Apply(CustomArguments);
  142. } // namespace ROCKSDB_NAMESPACE
  143. BENCHMARK_MAIN();