From c8d654122161a28409c23a6f1eb3c12ca8637d0b Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Thu, 5 Mar 2026 20:03:26 +0100 Subject: [PATCH] add hashset benchmarks --- .gitignore | 2 + benchmark/state_space.cpp | 121 +++++++++++++++++++++++++++++++++++++- flake.nix | 4 +- 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9fb6965..02f54de 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ cmake-build-release /perf.data /perf.data.old /clusters.puzzle +/benchs.json +/benchs.old.json diff --git a/benchmark/state_space.cpp b/benchmark/state_space.cpp index 62d8ec7..f26beeb 100644 --- a/benchmark/state_space.cpp +++ b/benchmark/state_space.cpp @@ -1,6 +1,10 @@ +// ReSharper disable CppTooWideScope #include "puzzle.hpp" +#include +#include #include +#include static std::vector puzzles = { // 0: RushHour 1 @@ -35,6 +39,113 @@ static std::vector puzzles = { "S:[4x5] G:[1,3] M:[F] B:[{_ 2X2 _ _} {1x1 _ _ 1x1} {1x2 2x1 _ 1x2} {_ 2x1 _ _} {1x1 2x1 _ 1x1}]", }; +template +struct uint_hasher +{ + int64_t nums; + + auto operator()(const std::array& ints) const noexcept -> size_t + { + size_t h = 0; + for (size_t i = 0; i < N; ++i) { + puzzle::hash_combine(h, ints[i]); + } + return h; + } +}; + +template +static auto unordered_set_uint64(benchmark::State& state) -> void +{ + std::random_device random_device; + std::mt19937 generator(random_device()); + std::uniform_int_distribution distribution( + std::numeric_limits::min(), + std::numeric_limits::max() + ); + + std::unordered_set, uint_hasher> set; + std::array ints; + for (size_t i = 0; i < N; ++i) { + ints[i] = distribution(generator); + } + + for (auto _ : state) { + for (size_t i = 0; i < 100000; ++i) { + set.emplace(ints); + } + + benchmark::DoNotOptimize(set); + } +} + +template +static auto unordered_flat_set_uint64(benchmark::State& state) -> void +{ + std::random_device random_device; + std::mt19937 generator(random_device()); + std::uniform_int_distribution distribution( + std::numeric_limits::min(), + std::numeric_limits::max() + ); + + boost::unordered_flat_set, uint_hasher> set; + std::array ints; + for (size_t i = 0; i < N; ++i) { + ints[i] = distribution(generator); + } + + for (auto _ : state) { + for (size_t i = 0; i < 100000; ++i) { + set.emplace(ints); + } + + benchmark::DoNotOptimize(set); + } +} + +static auto unordered_flat_set_block_hasher(benchmark::State& state) -> void +{ + boost::unordered_flat_set set; + const puzzle::block b = puzzle::block(2, 3, 1, 2, true, false); + + for (auto _ : state) { + for (size_t i = 0; i < 100000; ++i) { + set.emplace(b); + } + + benchmark::DoNotOptimize(set); + } +} + +static auto unordered_falt_set_block_hasher2(benchmark::State& state) -> void +{ + boost::unordered_flat_set set; + const puzzle::block b = puzzle::block(2, 3, 1, 2, true, false); + + for (auto _ : state) { + for (size_t i = 0; i < 100000; ++i) { + set.emplace(b); + } + + benchmark::DoNotOptimize(set); + } +} + +static auto unordered_flat_set_puzzle_hasher(benchmark::State& state) -> void +{ + boost::unordered_flat_set set; + const puzzle p = puzzle(puzzles[0]); + + for (auto _ : state) { + for (size_t i = 0; i < 100000; ++i) { + set.emplace(p); + } + + benchmark::DoNotOptimize(set); + } +} + static auto explore_state_space(benchmark::State& state) -> void { const puzzle p = puzzle(puzzles[state.range(0)]); @@ -48,7 +159,6 @@ static auto explore_state_space(benchmark::State& state) -> void static auto explore_rush_hour_puzzle_space(benchmark::State& state) -> void { - // ReSharper disable once CppTooWideScope constexpr uint8_t max_blocks = 5; constexpr uint8_t board_width = 4; @@ -85,6 +195,15 @@ static auto explore_rush_hour_puzzle_space(benchmark::State& state) -> void } } +BENCHMARK(unordered_set_uint64<4>)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_set_uint64<8>)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_set_uint64<16>)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_flat_set_uint64<4>)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_flat_set_uint64<8>)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_flat_set_uint64<16>)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_flat_set_block_hasher)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_falt_set_block_hasher2)->Unit(benchmark::kMicrosecond); +BENCHMARK(unordered_flat_set_puzzle_hasher)->Unit(benchmark::kMicrosecond); BENCHMARK(explore_state_space)->DenseRange(0, puzzles.size() - 1)->Unit(benchmark::kMicrosecond); BENCHMARK(explore_rush_hour_puzzle_space)->Unit(benchmark::kSecond); diff --git a/flake.nix b/flake.nix index 8f88095..1a5dee1 100644 --- a/flake.nix +++ b/flake.nix @@ -113,7 +113,7 @@ rec { abbr -a run "${buildRelease} && ./cmake-build-release/masssprings" abbr -a run-clusters "${buildRelease} && ./cmake-build-release/masssprings --output=clusters.puzzle --space=rh --w=6 --h=6 --gx=4 --gy=2 --blocks=4" abbr -a runtests "${buildDebug} && ./cmake-build-debug/tests" - abbr -a runbenchs "${buildRelease} && sudo cpupower frequency-set --governor performance && ./cmake-build-release/benchmarks; sudo cpupower frequency-set --governor powersave" + abbr -a runbenchs "mv benchs.json benchs.old.json; ${buildRelease} && sudo cpupower frequency-set --governor performance && ./cmake-build-release/benchmarks --benchmark_out=benchs.json --benchmark_out_format=console; sudo cpupower frequency-set --governor powersave" abbr -a rungdb "${buildDebug} && gdb --tui ./cmake-build-debug/masssprings" abbr -a runvalgrind "${buildDebug} && valgrind --leak-check=full --show-reachable=no --show-leak-kinds=definite,indirect,possible --track-origins=no --suppressions=valgrind.supp --log-file=valgrind.log ./cmake-build-debug/masssprings && cat valgrind.log" abbr -a runperf "${buildRelease} && perf record -g ./cmake-build-release/masssprings && hotspot ./perf.data" @@ -394,4 +394,4 @@ rec { }; } ); -} +} \ No newline at end of file