From 094dc8e73a4602ff63392a19f57717e2ff5fe69f Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 13 Jul 2024 14:55:40 -0700 Subject: [PATCH] [benchmarks] Do everything on the heap to avoid stack overflows --- test/benchmarks/map_clear.cpp | 28 ++++++++++++++++++++-------- test/benchmarks/map_copy.cpp | 34 +++++++++++++++++++++++++--------- test/benchmarks/map_lookup.cpp | 16 ++++++++++++---- test/benchmarks/map_utils.hpp | 12 +++++------- 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/test/benchmarks/map_clear.cpp b/test/benchmarks/map_clear.cpp index 696a2497..28cb884f 100644 --- a/test/benchmarks/map_clear.cpp +++ b/test/benchmarks/map_clear.cpp @@ -1,5 +1,6 @@ #include "fixed_containers/fixed_map.hpp" #include "fixed_containers/fixed_unordered_map.hpp" +#include "fixed_containers/memory.hpp" #include @@ -7,6 +8,7 @@ #include #include #include +#include #include namespace fixed_containers @@ -18,7 +20,8 @@ template void benchmark_map_copy(benchmark::State& state) { const int64_t nelem = state.range(0); - MapType instance = {}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); using KeyType = typename MapType::key_type; for (int64_t i = 0; i < nelem; i++) @@ -26,9 +29,11 @@ void benchmark_map_copy(benchmark::State& state) instance.try_emplace(static_cast(i)); } + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{instance}; + memory::destroy_and_construct_at_address_of(instance2, instance); benchmark::DoNotOptimize(instance2); } } @@ -37,16 +42,19 @@ template void benchmark_map_copy_then_clear(benchmark::State& state) { using KeyType = typename MapType::key_type; - MapType instance{}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); const int64_t nelem = state.range(0); for (int64_t i = 0; i < nelem; i++) { instance.try_emplace(static_cast(i)); } + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{instance}; + memory::destroy_and_construct_at_address_of(instance2, instance); instance2.clear(); benchmark::DoNotOptimize(instance2); } @@ -56,17 +64,20 @@ template void benchmark_map_copy_then_reconstruct(benchmark::State& state) { using KeyType = typename MapType::key_type; - MapType instance{}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); const int64_t nelem = state.range(0); for (int64_t i = 0; i < nelem; i++) { instance.try_emplace(static_cast(i)); } + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{instance}; - instance2 = {}; + memory::destroy_and_construct_at_address_of(instance2, instance); + memory::destroy_and_construct_at_address_of(instance2); benchmark::DoNotOptimize(instance2); } } @@ -74,7 +85,8 @@ void benchmark_map_copy_then_reconstruct(benchmark::State& state) template void benchmark_array_clear(benchmark::State& state) { - ArrType instance{}; + const std::unique_ptr instance_ptr = std::make_unique(); + ArrType& instance = *instance_ptr.get(); for (auto _ : state) { diff --git a/test/benchmarks/map_copy.cpp b/test/benchmarks/map_copy.cpp index 4685ceac..2761693e 100644 --- a/test/benchmarks/map_copy.cpp +++ b/test/benchmarks/map_copy.cpp @@ -2,10 +2,13 @@ #include "../mock_testing_types.hpp" #include "fixed_containers/fixed_unordered_map.hpp" +#include "fixed_containers/memory.hpp" #include +#include #include +#include namespace fixed_containers { @@ -16,7 +19,8 @@ template void benchmark_map_copy_fresh(benchmark::State& state) { const int64_t nelem = state.range(0); - MapType instance = {}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); using KeyType = typename MapType::key_type; for (int64_t i = 0; i < nelem; i++) @@ -24,9 +28,11 @@ void benchmark_map_copy_fresh(benchmark::State& state) instance.try_emplace(static_cast(i)); } + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{instance}; + memory::destroy_and_construct_at_address_of(instance2, instance); benchmark::DoNotOptimize(instance2); } } @@ -35,17 +41,19 @@ template void benchmark_map_iterate_copy_fresh(benchmark::State& state) { const int64_t nelem = state.range(0); - MapType instance = {}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); using KeyType = typename MapType::key_type; for (int64_t i = 0; i < nelem; i++) { instance.try_emplace(static_cast(i)); } - + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{}; + memory::destroy_and_construct_at_address_of(instance2); for (auto elem : instance) { instance2.try_emplace(elem.first, elem.second); @@ -58,7 +66,9 @@ template void benchmark_map_copy_shuffled(benchmark::State& state) { const int64_t nelem = state.range(0); - auto instance = map_benchmarks::make_shuffled_map(); + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); + map_benchmarks::make_shuffled_map(instance); using KeyType = typename MapType::key_type; for (int64_t i = 0; i < nelem; i++) @@ -66,9 +76,11 @@ void benchmark_map_copy_shuffled(benchmark::State& state) instance.try_emplace(static_cast(i)); } + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{instance}; + memory::destroy_and_construct_at_address_of(instance2, instance); benchmark::DoNotOptimize(instance2); } } @@ -77,7 +89,9 @@ template void benchmark_map_iterate_copy_shuffled(benchmark::State& state) { const int64_t nelem = state.range(0); - auto instance = map_benchmarks::make_shuffled_map(); + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); + map_benchmarks::make_shuffled_map(instance); using KeyType = typename MapType::key_type; for (int64_t i = 0; i < nelem; i++) @@ -85,9 +99,11 @@ void benchmark_map_iterate_copy_shuffled(benchmark::State& state) instance.try_emplace(static_cast(i)); } + const std::unique_ptr instance_ptr2 = std::make_unique(); + MapType& instance2 = *instance_ptr2.get(); for (auto _ : state) { - MapType instance2{}; + memory::destroy_and_construct_at_address_of(instance2); for (auto elem : instance) { instance2.try_emplace(elem.first, elem.second); diff --git a/test/benchmarks/map_lookup.cpp b/test/benchmarks/map_lookup.cpp index 2f15dbf9..38ee67c6 100644 --- a/test/benchmarks/map_lookup.cpp +++ b/test/benchmarks/map_lookup.cpp @@ -5,8 +5,10 @@ #include +#include #include #include +#include #include namespace fixed_containers @@ -17,7 +19,8 @@ template void benchmark_map_lookup_fresh(benchmark::State& state) { using KeyType = typename MapType::key_type; - MapType instance{}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); const int64_t nelem = state.range(0); for (int64_t i = 0; i < nelem; i++) { @@ -38,7 +41,9 @@ template void benchmark_map_lookup_shuffled(benchmark::State& state) { using KeyType = typename MapType::key_type; - auto instance = map_benchmarks::make_shuffled_map(); + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); + map_benchmarks::make_shuffled_map(instance); const int64_t nelem = state.range(0); for (int64_t i = 0; i < nelem; i++) { @@ -59,7 +64,8 @@ template void benchmark_map_iterate_fresh(benchmark::State& state) { using KeyType = typename MapType::key_type; - MapType instance{}; + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); const int64_t nelem = state.range(0); for (int64_t i = 0; i < nelem; i++) { @@ -79,7 +85,9 @@ template void benchmark_map_iterate_shuffled(benchmark::State& state) { using KeyType = typename MapType::key_type; - auto instance = map_benchmarks::make_shuffled_map(); + const std::unique_ptr instance_ptr = std::make_unique(); + MapType& instance = *instance_ptr.get(); + map_benchmarks::make_shuffled_map(instance); const int64_t nelem = state.range(0); for (int64_t i = 0; i < nelem; i++) { diff --git a/test/benchmarks/map_utils.hpp b/test/benchmarks/map_utils.hpp index 52df78b0..a939599f 100644 --- a/test/benchmarks/map_utils.hpp +++ b/test/benchmarks/map_utils.hpp @@ -7,7 +7,7 @@ namespace fixed_containers::map_benchmarks { template -[[maybe_unused]] static void del(MapType& map, int64_t divisor) +constexpr void del(MapType& map, int64_t divisor) { auto iter = map.begin(); while (iter != map.end()) @@ -24,7 +24,7 @@ template } template -[[maybe_unused]] static void replace_low(MapType& map, std::size_t divisor) +constexpr void replace_low(MapType& map, std::size_t divisor) { using KeyType = typename MapType::key_type; for (std::size_t i = 0; i < map.max_size(); i += divisor) @@ -34,7 +34,7 @@ template } template -[[maybe_unused]] static void replace_high(MapType& map, std::size_t divisor) +constexpr void replace_high(MapType& map, std::size_t divisor) { using KeyType = typename MapType::key_type; // find the largest multiple smaller than `n` @@ -49,10 +49,10 @@ template // create a "well-used" map, so that new elements will be inserted into dispersed spots in the map // instead of spots with good memory locality template -[[maybe_unused]] static MapType make_shuffled_map() +constexpr void make_shuffled_map(MapType& instance) { using KeyType = typename MapType::key_type; - MapType instance{}; + instance.clear(); // fill the map completely for (std::size_t i = 0; i < instance.max_size(); i++) { @@ -83,8 +83,6 @@ template del(instance, 1023); del(instance, 15); del(instance, 1); - - return instance; } } // namespace fixed_containers::map_benchmarks