From 500c20f7ea2d98dbebf9a5cd0fa4f59dc9b40b37 Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Thu, 10 Feb 2022 22:20:57 +0100 Subject: [PATCH] FlatHashMap: more benchmarks --- tdutils/td/utils/VectorQueue.h | 7 ++ tdutils/test/hashset_benchmark.cpp | 123 ++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/tdutils/td/utils/VectorQueue.h b/tdutils/td/utils/VectorQueue.h index d7e89ff6d..c67a440ca 100644 --- a/tdutils/td/utils/VectorQueue.h +++ b/tdutils/td/utils/VectorQueue.h @@ -31,6 +31,13 @@ class VectorQueue { return std::move(vector_[read_pos_++]); } + template + T pop_rand(RndT &rnd) { + auto i = rnd() % size(); + std::swap(vector_[i], vector_[read_pos_]); + return pop(); + } + void pop_n(size_t n) { read_pos_ += n; try_shrink(); diff --git a/tdutils/test/hashset_benchmark.cpp b/tdutils/test/hashset_benchmark.cpp index f136cf357..1be80bbcc 100644 --- a/tdutils/test/hashset_benchmark.cpp +++ b/tdutils/test/hashset_benchmark.cpp @@ -14,6 +14,7 @@ #include "td/utils/Slice.h" #include "td/utils/Span.h" #include "td/utils/Time.h" +#include "td/utils/VectorQueue.h" #include #include @@ -286,6 +287,106 @@ static void BM_remove_if(benchmark::State &state) { } } +template +static void BM_erase_all_with_begin(benchmark::State &state) { + constexpr size_t N = 100000; + constexpr size_t BATCH_SIZE = N; + + TableT table; + td::Random::Xorshift128plus rnd(123); + while (state.KeepRunningBatch(BATCH_SIZE)) { + for (size_t i = 0; i < BATCH_SIZE; i++) { + table.emplace(rnd() + 1, i); + } + while (!table.empty()) { + table.erase(table.begin()); + } + } +} + +template +static void BM_cache(benchmark::State &state) { + constexpr size_t N = 1000; + constexpr size_t BATCH_SIZE = 1000000; + + TableT table; + td::Random::Xorshift128plus rnd(123); + td::VectorQueue keys; + while (state.KeepRunningBatch(BATCH_SIZE)) { + for (size_t i = 0; i < BATCH_SIZE; i++) { + auto key = rnd() + 1; + keys.push(key); + table.emplace(key, i); + if (table.size() > N) { + table.erase(keys.pop()); + } + } + } +} + +template +static void BM_cache2(benchmark::State &state) { + constexpr size_t N = 1000; + constexpr size_t BATCH_SIZE = 1000000; + + TableT table; + td::Random::Xorshift128plus rnd(123); + td::VectorQueue keys; + while (state.KeepRunningBatch(BATCH_SIZE)) { + for (size_t i = 0; i < BATCH_SIZE; i++) { + auto key = rnd() + 1; + keys.push(key); + table.emplace(key, i); + if (table.size() > N) { + table.erase(keys.pop_rand(rnd)); + } + } + } +} + +template +static void BM_cache3(benchmark::State &state) { + size_t N = state.range(0); + constexpr size_t BATCH_SIZE = 1000000; + + TableT table; + td::Random::Xorshift128plus rnd(123); + td::VectorQueue keys; + size_t step = 20; + while (state.KeepRunningBatch(BATCH_SIZE)) { + for (size_t i = 0; i < BATCH_SIZE; i += step) { + auto key = rnd() + 1; + keys.push(key); + table.emplace(key, i); + + for (size_t j = 1; j < step; j++) { + auto key_to_find = keys.data()[rnd()%keys.size()]; + benchmark::DoNotOptimize(table.find(key_to_find)); + } + + if (table.size() > N) { + table.erase(keys.pop_rand(rnd)); + } + } + } +} +template +static void BM_remove_if_slow(benchmark::State &state) { + constexpr size_t N = 100000; + constexpr size_t BATCH_SIZE = 500000; + + TableT table; + while (state.KeepRunningBatch(BATCH_SIZE)) { + td::Random::Xorshift128plus rnd(123); + for (size_t i = 0; i < BATCH_SIZE; i++) { + table.emplace(rnd() + 1, i); + if (table.size() > N) { + size_t cnt = 0; + td::table_remove_if(table, [&cnt](auto &) { cnt += 2; return cnt <= N; }); + } + } + }} + template static void benchmark_create(td::Slice name) { td::Random::Xorshift128plus rnd(123); @@ -331,7 +432,6 @@ static void benchmark_create(td::Slice name) { //BENCHMARK(BM_Get>)->Range(1, 1 << 26); #define REGISTER_GET_BENCHMARK(HT) BENCHMARK(BM_Get>)->Range(1, 1 << 23); -#define REGISTER_REMOVE_IF_BENCHMARK(HT) BENCHMARK(BM_remove_if>); #define REGISTER_FIND_BENCHMARK(HT) \ BENCHMARK(BM_find_same>) \ @@ -340,15 +440,32 @@ static void benchmark_create(td::Slice name) { ->Repetitions(20) \ ->DisplayAggregatesOnly(true); +#define REGISTER_REMOVE_IF_BENCHMARK(HT) BENCHMARK(BM_remove_if>); #define REGISTER_EMPLACE_BENCHMARK(HT) BENCHMARK(BM_emplace_same>); +#define REGISTER_CACHE_BENCHMARK(HT) BENCHMARK(BM_cache>); +#define REGISTER_CACHE2_BENCHMARK(HT) BENCHMARK(BM_cache2>); +#define REGISTER_CACHE3_BENCHMARK(HT) BENCHMARK(BM_cache3>)->Range(1, 1 << 23); +#define REGISTER_ERASE_ALL_BENCHMARK(HT) BENCHMARK(BM_erase_all_with_begin>); +#define REGISTER_REMOVE_IF_SLOW_BENCHMARK(HT) BENCHMARK(BM_remove_if_slow>); -#define RUN_CREATE_BENCHMARK(HT) benchmark_create>(#HT); +FOR_EACH_TABLE(REGISTER_CACHE3_BENCHMARK) +FOR_EACH_TABLE(REGISTER_CACHE_BENCHMARK) +FOR_EACH_TABLE(REGISTER_CACHE2_BENCHMARK) +FOR_EACH_TABLE(REGISTER_REMOVE_IF_SLOW_BENCHMARK) +FOR_EACH_TABLE(REGISTER_ERASE_ALL_BENCHMARK) +FOR_EACH_TABLE(REGISTER_CACHE_BENCHMARK) FOR_EACH_TABLE(REGISTER_REMOVE_IF_BENCHMARK) -FOR_EACH_TABLE(REGISTER_FIND_BENCHMARK) FOR_EACH_TABLE(REGISTER_EMPLACE_BENCHMARK) FOR_EACH_TABLE(REGISTER_GET_BENCHMARK) +FOR_EACH_TABLE(REGISTER_FIND_BENCHMARK) + + +#define REGISTER_(X) BENCHMARK(X); +#define REGISTER(X) FOR_EACH_TABLE(REGISTER_(X)) + +#define RUN_CREATE_BENCHMARK(HT) benchmark_create>(#HT); int main(int argc, char **argv) { // FOR_EACH_TABLE(RUN_CREATE_BENCHMARK);