1818#include < benchmark/benchmark.h>
1919#include < spdlog/spdlog.h>
2020#include < spdlog/sinks/ansicolor_sink.h>
21- #include < random>
2221
2322using namespace improbable ;
2423using namespace improbable ::phtree;
2524using namespace improbable ::phtree::phbenchmark;
2625
2726namespace {
2827
28+ constexpr int UPDATES_PER_ROUND = 1000 ;
29+ constexpr double MOVE_DISTANCE = 10 ;
30+
2931const double GLOBAL_MAX = 10000 ;
3032const double BOX_LEN = 10 ;
3133
@@ -46,25 +48,26 @@ class IndexBenchmark {
4648 benchmark::State& state,
4749 TestGenerator data_type,
4850 int num_entities,
49- int updates_per_round,
50- double move_distance);
51+ int updates_per_round = UPDATES_PER_ROUND ,
52+ double move_distance = MOVE_DISTANCE );
5153
5254 void Benchmark (benchmark::State& state);
5355
5456 private:
5557 void SetupWorld (benchmark::State& state);
56- void BuildUpdate (std::vector<UpdateOp<DIM>>& updates );
57- void UpdateWorld (benchmark::State& state, std::vector<UpdateOp<DIM>>& updates );
58+ void BuildUpdates ( );
59+ void UpdateWorld (benchmark::State& state);
5860
5961 const TestGenerator data_type_;
6062 const int num_entities_;
6163 const int updates_per_round_;
6264 const double move_distance_;
6365
6466 PhTreeBoxD<DIM, scalar_t > tree_;
65- std::default_random_engine random_engine_;
66- std::uniform_real_distribution<> cube_distribution_;
6767 std::vector<PhBoxD<DIM>> boxes_;
68+ std::vector<UpdateOp<DIM>> updates_;
69+ std::default_random_engine random_engine_;
70+ std::uniform_int_distribution<> entity_id_distribution_;
6871};
6972
7073template <dimension_t DIM>
@@ -78,9 +81,10 @@ IndexBenchmark<DIM>::IndexBenchmark(
7881, num_entities_(num_entities)
7982, updates_per_round_(updates_per_round)
8083, move_distance_(move_distance)
81- , random_engine_{1 }
82- , cube_distribution_{0 , GLOBAL_MAX}
83- , boxes_(num_entities) {
84+ , boxes_(num_entities)
85+ , updates_(updates_per_round)
86+ , random_engine_{0 }
87+ , entity_id_distribution_{0 , num_entities - 1 } {
8488 auto console_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();
8589 spdlog::set_default_logger (
8690 std::make_shared<spdlog::logger>(" " , spdlog::sinks_init_list ({console_sink})));
@@ -91,41 +95,12 @@ IndexBenchmark<DIM>::IndexBenchmark(
9195
9296template <dimension_t DIM>
9397void IndexBenchmark<DIM>::Benchmark(benchmark::State& state) {
94- std::vector<UpdateOp<DIM>> updates;
95- updates.reserve (updates_per_round_);
9698 for (auto _ : state) {
9799 state.PauseTiming ();
98- BuildUpdate (updates );
100+ BuildUpdates ( );
99101 state.ResumeTiming ();
100102
101- UpdateWorld (state, updates);
102-
103- state.PauseTiming ();
104- for (auto & update : updates) {
105- boxes_[update.id_ ] = update.new_ ;
106- }
107- state.ResumeTiming ();
108- }
109- }
110-
111- template <dimension_t DIM>
112- void IndexBenchmark<DIM>::BuildUpdate(std::vector<UpdateOp<DIM>>& updates) {
113- // Use Delta to avoid moving points in insertion order (not that it matters for the PH-Tree, but
114- // we may test other trees as well.
115- int box_id_increment = num_entities_ / updates_per_round_; // int division
116- int box_id = 0 ;
117- updates.clear ();
118- for (size_t i = 0 ; i < updates_per_round_; ++i) {
119- assert (box_id >= 0 );
120- assert (box_id < boxes_.size ());
121- auto & old_box = boxes_[box_id];
122- auto update = UpdateOp<DIM>{box_id, old_box, old_box};
123- for (dimension_t d = 0 ; d < DIM; ++d) {
124- update.new_ .min ()[d] += move_distance_;
125- update.new_ .max ()[d] += move_distance_;
126- }
127- updates.emplace_back (update);
128- box_id += box_id_increment;
103+ UpdateWorld (state);
129104 }
130105}
131106
@@ -143,10 +118,24 @@ void IndexBenchmark<DIM>::SetupWorld(benchmark::State& state) {
143118}
144119
145120template <dimension_t DIM>
146- void IndexBenchmark<DIM>::UpdateWorld(
147- benchmark::State& state, std::vector<UpdateOp<DIM>>& updates) {
121+ void IndexBenchmark<DIM>::BuildUpdates() {
122+ for (auto & update : updates_) {
123+ int box_id = entity_id_distribution_ (random_engine_);
124+ update.id_ = box_id;
125+ update.old_ = boxes_[box_id];
126+ for (dimension_t d = 0 ; d < DIM; ++d) {
127+ update.new_ .min ()[d] = update.old_ .min ()[d] + move_distance_;
128+ update.new_ .max ()[d] = update.old_ .max ()[d] + move_distance_;
129+ }
130+ // update reference data
131+ boxes_[box_id] = update.new_ ;
132+ }
133+ }
134+
135+ template <dimension_t DIM>
136+ void IndexBenchmark<DIM>::UpdateWorld(benchmark::State& state) {
148137 size_t initial_tree_size = tree_.size ();
149- for (auto & update : updates ) {
138+ for (auto & update : updates_ ) {
150139 size_t result_erase = tree_.erase (update.old_ );
151140 auto result_emplace = tree_.emplace (update.new_ , update.id_ );
152141 assert (result_erase == 1 );
@@ -155,7 +144,7 @@ void IndexBenchmark<DIM>::UpdateWorld(
155144
156145 // For normal indexes we expect num_entities==size(), but the PhTree<Map<...>> index has
157146 // size() as low as (num_entities-duplicates).
158- if (tree_.size () > num_entities_ || tree_.size () < initial_tree_size - updates_per_round_ ) {
147+ if (tree_.size () > num_entities_ || tree_.size () + updates_per_round_ < initial_tree_size ) {
159148 spdlog::error (" Invalid index size after update: {}/{}" , tree_.size (), num_entities_);
160149 }
161150
@@ -167,35 +156,35 @@ void IndexBenchmark<DIM>::UpdateWorld(
167156
168157template <typename ... Arguments>
169158void PhTree3D (benchmark::State& state, Arguments&&... arguments) {
170- IndexBenchmark<4 > benchmark{state, arguments...};
159+ IndexBenchmark<3 > benchmark{state, arguments...};
171160 benchmark.Benchmark (state);
172161}
173162
174163// index type, scenario name, data_type, num_entities, updates_per_round, move_distance
175164// PhTree3D CUBE
176- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_1K, TestGenerator::CUBE, 1000 , 100 , 10 . )
165+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_1K, TestGenerator::CUBE, 1000 )
177166 ->Unit(benchmark::kMillisecond );
178167
179- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_10K, TestGenerator::CUBE, 10000 , 100 , 10 . )
168+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_10K, TestGenerator::CUBE, 10000 )
180169 ->Unit(benchmark::kMillisecond );
181170
182- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_100K, TestGenerator::CUBE, 100000 , 100 , 10 . )
171+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_100K, TestGenerator::CUBE, 100000 )
183172 ->Unit(benchmark::kMillisecond );
184173
185- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_1M, TestGenerator::CUBE, 1000000 , 100 , 10 . )
174+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CU_100_of_1M, TestGenerator::CUBE, 1000000 )
186175 ->Unit(benchmark::kMillisecond );
187176
188177// PhTree3D CLUSTER
189- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_1K, TestGenerator::CLUSTER, 1000 , 100 , 10 . )
178+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_1K, TestGenerator::CLUSTER, 1000 )
190179 ->Unit(benchmark::kMillisecond );
191180
192- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_10K, TestGenerator::CLUSTER, 10000 , 100 , 10 . )
181+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_10K, TestGenerator::CLUSTER, 10000 )
193182 ->Unit(benchmark::kMillisecond );
194183
195- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_100K, TestGenerator::CLUSTER, 100000 , 100 , 10 . )
184+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_100K, TestGenerator::CLUSTER, 100000 )
196185 ->Unit(benchmark::kMillisecond );
197186
198- BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_1M, TestGenerator::CLUSTER, 1000000 , 100 , 10 . )
187+ BENCHMARK_CAPTURE (PhTree3D, UPDATE_CL_100_of_1M, TestGenerator::CLUSTER, 1000000 )
199188 ->Unit(benchmark::kMillisecond );
200189
201190BENCHMARK_MAIN ();
0 commit comments