[flang][runtime] Make defined formatted I/O process format elementally (#74150)
[llvm-project.git] / libcxx / benchmarks / map.bench.cpp
blob255164b22aa807f3808cfc0543492438676eea96
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include <algorithm>
10 #include <cstdint>
11 #include <map>
12 #include <random>
13 #include <vector>
15 #include "CartesianBenchmarks.h"
16 #include "benchmark/benchmark.h"
17 #include "test_macros.h"
19 // When VALIDATE is defined the benchmark will run to validate the benchmarks.
20 // The time taken by several operations depend on whether or not an element
21 // exists. To avoid errors in the benchmark these operations have a validation
22 // mode to test the benchmark. Since they are not meant to be benchmarked the
23 // number of sizes tested is limited to 1.
24 // #define VALIDATE
26 namespace {
28 enum class Mode { Hit, Miss };
30 struct AllModes : EnumValuesAsTuple<AllModes, Mode, 2> {
31 static constexpr const char* Names[] = {"ExistingElement", "NewElement"};
34 // The positions of the hints to pick:
35 // - Begin picks the first item. The item cannot be put before this element.
36 // - Thrid picks the third item. This is just an element with a valid entry
37 // before and after it.
38 // - Correct contains the correct hint.
39 // - End contains a hint to the end of the map.
40 enum class Hint { Begin, Third, Correct, End };
41 struct AllHints : EnumValuesAsTuple<AllHints, Hint, 4> {
42 static constexpr const char* Names[] = {"Begin", "Third", "Correct", "End"};
45 enum class Order { Sorted, Random };
46 struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 2> {
47 static constexpr const char* Names[] = {"Sorted", "Random"};
50 struct TestSets {
51 std::vector<uint64_t> Keys;
52 std::vector<std::map<uint64_t, int64_t> > Maps;
53 std::vector<std::vector<typename std::map<uint64_t, int64_t>::const_iterator> > Hints;
56 enum class Shuffle { None, Keys, Hints };
58 TestSets makeTestingSets(size_t MapSize, Mode mode, Shuffle shuffle, size_t max_maps) {
60 * The shuffle does not retain the random number generator to use the same
61 * set of random numbers for every iteration.
63 TestSets R;
65 int MapCount = std::min(max_maps, 1000000 / MapSize);
67 for (uint64_t I = 0; I < MapSize; ++I) {
68 R.Keys.push_back(mode == Mode::Hit ? 2 * I + 2 : 2 * I + 1);
70 if (shuffle == Shuffle::Keys)
71 std::shuffle(R.Keys.begin(), R.Keys.end(), std::mt19937());
73 for (int M = 0; M < MapCount; ++M) {
74 auto& map = R.Maps.emplace_back();
75 auto& hints = R.Hints.emplace_back();
76 for (uint64_t I = 0; I < MapSize; ++I) {
77 hints.push_back(map.insert(std::make_pair(2 * I + 2, 0)).first);
79 if (shuffle == Shuffle::Hints)
80 std::shuffle(hints.begin(), hints.end(), std::mt19937());
83 return R;
86 struct Base {
87 size_t MapSize;
88 Base(size_t T) : MapSize(T) {}
90 std::string baseName() const { return "_MapSize=" + std::to_string(MapSize); }
93 //*******************************************************************|
94 // Member functions |
95 //*******************************************************************|
97 struct ConstructorDefault {
98 void run(benchmark::State& State) const {
99 for (auto _ : State) {
100 benchmark::DoNotOptimize(std::map<uint64_t, int64_t>());
104 std::string name() const { return "BM_ConstructorDefault"; }
107 struct ConstructorIterator : Base {
108 using Base::Base;
110 void run(benchmark::State& State) const {
111 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
112 auto& Map = Data.Maps.front();
113 while (State.KeepRunningBatch(MapSize)) {
114 #ifndef VALIDATE
115 benchmark::DoNotOptimize(std::map<uint64_t, int64_t>(Map.begin(), Map.end()));
116 #else
117 std::map<uint64_t, int64_t> M{Map.begin(), Map.end()};
118 if (M != Map)
119 State.SkipWithError("Map copy not identical");
120 #endif
124 std::string name() const { return "BM_ConstructorIterator" + baseName(); }
127 struct ConstructorCopy : Base {
128 using Base::Base;
130 void run(benchmark::State& State) const {
131 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
132 auto& Map = Data.Maps.front();
133 while (State.KeepRunningBatch(MapSize)) {
134 #ifndef VALIDATE
135 std::map<uint64_t, int64_t> M(Map);
136 benchmark::DoNotOptimize(M);
137 #else
138 std::map<uint64_t, int64_t> M(Map);
139 if (M != Map)
140 State.SkipWithError("Map copy not identical");
141 #endif
145 std::string name() const { return "BM_ConstructorCopy" + baseName(); }
148 struct ConstructorMove : Base {
149 using Base::Base;
151 void run(benchmark::State& State) const {
152 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
153 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
154 for (auto& Map : Data.Maps) {
155 std::map<uint64_t, int64_t> M(std::move(Map));
156 benchmark::DoNotOptimize(M);
158 State.PauseTiming();
159 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
160 State.ResumeTiming();
164 std::string name() const { return "BM_ConstructorMove" + baseName(); }
167 //*******************************************************************|
168 // Capacity |
169 //*******************************************************************|
171 struct Empty : Base {
172 using Base::Base;
174 void run(benchmark::State& State) const {
175 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
176 auto& Map = Data.Maps.front();
177 for (auto _ : State) {
178 #ifndef VALIDATE
179 benchmark::DoNotOptimize(Map.empty());
180 #else
181 if (Map.empty())
182 State.SkipWithError("Map contains an invalid number of elements.");
183 #endif
187 std::string name() const { return "BM_Empty" + baseName(); }
190 struct Size : Base {
191 using Base::Base;
193 void run(benchmark::State& State) const {
194 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
195 auto& Map = Data.Maps.front();
196 for (auto _ : State) {
197 #ifndef VALIDATE
198 benchmark::DoNotOptimize(Map.size());
199 #else
200 if (Map.size() != MapSize)
201 State.SkipWithError("Map contains an invalid number of elements.");
202 #endif
206 std::string name() const { return "BM_Size" + baseName(); }
209 //*******************************************************************|
210 // Modifiers |
211 //*******************************************************************|
213 struct Clear : Base {
214 using Base::Base;
216 void run(benchmark::State& State) const {
217 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
218 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
219 for (auto& Map : Data.Maps) {
220 Map.clear();
221 benchmark::DoNotOptimize(Map);
223 State.PauseTiming();
224 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
225 State.ResumeTiming();
229 std::string name() const { return "BM_Clear" + baseName(); }
232 template <class Mode, class Order>
233 struct Insert : Base {
234 using Base::Base;
236 void run(benchmark::State& State) const {
237 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
238 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
239 for (auto& Map : Data.Maps) {
240 for (auto K : Data.Keys) {
241 #ifndef VALIDATE
242 benchmark::DoNotOptimize(Map.insert(std::make_pair(K, 1)));
243 #else
244 bool Inserted = Map.insert(std::make_pair(K, 1)).second;
245 if (Mode() == ::Mode::Hit) {
246 if (Inserted)
247 State.SkipWithError("Inserted a duplicate element");
248 } else {
249 if (!Inserted)
250 State.SkipWithError("Failed to insert e new element");
252 #endif
256 State.PauseTiming();
257 Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
258 State.ResumeTiming();
262 std::string name() const { return "BM_Insert" + baseName() + Mode::name() + Order::name(); }
265 template <class Mode, class Hint>
266 struct InsertHint : Base {
267 using Base::Base;
269 template < ::Hint hint>
270 typename std::enable_if<hint == ::Hint::Correct>::type run(benchmark::State& State) const {
271 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
272 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
273 for (size_t I = 0; I < Data.Maps.size(); ++I) {
274 auto& Map = Data.Maps[I];
275 auto H = Data.Hints[I].begin();
276 for (auto K : Data.Keys) {
277 #ifndef VALIDATE
278 benchmark::DoNotOptimize(Map.insert(*H, std::make_pair(K, 1)));
279 #else
280 auto Inserted = Map.insert(*H, std::make_pair(K, 1));
281 if (Mode() == ::Mode::Hit) {
282 if (Inserted != *H)
283 State.SkipWithError("Inserted a duplicate element");
284 } else {
285 if (++Inserted != *H)
286 State.SkipWithError("Failed to insert a new element");
288 #endif
289 ++H;
293 State.PauseTiming();
294 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
295 State.ResumeTiming();
299 template < ::Hint hint>
300 typename std::enable_if<hint != ::Hint::Correct>::type run(benchmark::State& State) const {
301 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
302 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
303 for (size_t I = 0; I < Data.Maps.size(); ++I) {
304 auto& Map = Data.Maps[I];
305 auto Third = *(Data.Hints[I].begin() + 2);
306 for (auto K : Data.Keys) {
307 auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end();
308 #ifndef VALIDATE
309 benchmark::DoNotOptimize(Map.insert(Itor, std::make_pair(K, 1)));
310 #else
311 size_t Size = Map.size();
312 Map.insert(Itor, std::make_pair(K, 1));
313 if (Mode() == ::Mode::Hit) {
314 if (Size != Map.size())
315 State.SkipWithError("Inserted a duplicate element");
316 } else {
317 if (Size + 1 != Map.size())
318 State.SkipWithError("Failed to insert a new element");
320 #endif
324 State.PauseTiming();
325 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
326 State.ResumeTiming();
330 void run(benchmark::State& State) const {
331 static constexpr auto h = Hint();
332 run<h>(State);
335 std::string name() const { return "BM_InsertHint" + baseName() + Mode::name() + Hint::name(); }
338 template <class Mode, class Order>
339 struct InsertAssign : Base {
340 using Base::Base;
342 void run(benchmark::State& State) const {
343 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
344 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
345 for (auto& Map : Data.Maps) {
346 for (auto K : Data.Keys) {
347 #ifndef VALIDATE
348 benchmark::DoNotOptimize(Map.insert_or_assign(K, 1));
349 #else
350 bool Inserted = Map.insert_or_assign(K, 1).second;
351 if (Mode() == ::Mode::Hit) {
352 if (Inserted)
353 State.SkipWithError("Inserted a duplicate element");
354 } else {
355 if (!Inserted)
356 State.SkipWithError("Failed to insert e new element");
358 #endif
362 State.PauseTiming();
363 Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
364 State.ResumeTiming();
368 std::string name() const { return "BM_InsertAssign" + baseName() + Mode::name() + Order::name(); }
371 template <class Mode, class Hint>
372 struct InsertAssignHint : Base {
373 using Base::Base;
375 template < ::Hint hint>
376 typename std::enable_if<hint == ::Hint::Correct>::type run(benchmark::State& State) const {
377 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
378 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
379 for (size_t I = 0; I < Data.Maps.size(); ++I) {
380 auto& Map = Data.Maps[I];
381 auto H = Data.Hints[I].begin();
382 for (auto K : Data.Keys) {
383 #ifndef VALIDATE
384 benchmark::DoNotOptimize(Map.insert_or_assign(*H, K, 1));
385 #else
386 auto Inserted = Map.insert_or_assign(*H, K, 1);
387 if (Mode() == ::Mode::Hit) {
388 if (Inserted != *H)
389 State.SkipWithError("Inserted a duplicate element");
390 } else {
391 if (++Inserted != *H)
392 State.SkipWithError("Failed to insert a new element");
394 #endif
395 ++H;
399 State.PauseTiming();
400 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
401 State.ResumeTiming();
405 template < ::Hint hint>
406 typename std::enable_if<hint != ::Hint::Correct>::type run(benchmark::State& State) const {
407 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
408 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
409 for (size_t I = 0; I < Data.Maps.size(); ++I) {
410 auto& Map = Data.Maps[I];
411 auto Third = *(Data.Hints[I].begin() + 2);
412 for (auto K : Data.Keys) {
413 auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end();
414 #ifndef VALIDATE
415 benchmark::DoNotOptimize(Map.insert_or_assign(Itor, K, 1));
416 #else
417 size_t Size = Map.size();
418 Map.insert_or_assign(Itor, K, 1);
419 if (Mode() == ::Mode::Hit) {
420 if (Size != Map.size())
421 State.SkipWithError("Inserted a duplicate element");
422 } else {
423 if (Size + 1 != Map.size())
424 State.SkipWithError("Failed to insert a new element");
426 #endif
430 State.PauseTiming();
431 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
432 State.ResumeTiming();
436 void run(benchmark::State& State) const {
437 static constexpr auto h = Hint();
438 run<h>(State);
441 std::string name() const { return "BM_InsertAssignHint" + baseName() + Mode::name() + Hint::name(); }
444 template <class Mode, class Order>
445 struct Emplace : Base {
446 using Base::Base;
448 void run(benchmark::State& State) const {
449 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
450 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
451 for (auto& Map : Data.Maps) {
452 for (auto K : Data.Keys) {
453 #ifndef VALIDATE
454 benchmark::DoNotOptimize(Map.emplace(K, 1));
455 #else
456 bool Inserted = Map.emplace(K, 1).second;
457 if (Mode() == ::Mode::Hit) {
458 if (Inserted)
459 State.SkipWithError("Emplaced a duplicate element");
460 } else {
461 if (!Inserted)
462 State.SkipWithError("Failed to emplace a new element");
464 #endif
468 State.PauseTiming();
469 Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
470 State.ResumeTiming();
474 std::string name() const { return "BM_Emplace" + baseName() + Mode::name() + Order::name(); }
477 template <class Mode, class Hint>
478 struct EmplaceHint : Base {
479 using Base::Base;
481 template < ::Hint hint>
482 typename std::enable_if<hint == ::Hint::Correct>::type run(benchmark::State& State) const {
483 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
484 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
485 for (size_t I = 0; I < Data.Maps.size(); ++I) {
486 auto& Map = Data.Maps[I];
487 auto H = Data.Hints[I].begin();
488 for (auto K : Data.Keys) {
489 #ifndef VALIDATE
490 benchmark::DoNotOptimize(Map.emplace_hint(*H, K, 1));
491 #else
492 auto Inserted = Map.emplace_hint(*H, K, 1);
493 if (Mode() == ::Mode::Hit) {
494 if (Inserted != *H)
495 State.SkipWithError("Emplaced a duplicate element");
496 } else {
497 if (++Inserted != *H)
498 State.SkipWithError("Failed to emplace a new element");
500 #endif
501 ++H;
505 State.PauseTiming();
506 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
507 State.ResumeTiming();
511 template < ::Hint hint>
512 typename std::enable_if<hint != ::Hint::Correct>::type run(benchmark::State& State) const {
513 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
514 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
515 for (size_t I = 0; I < Data.Maps.size(); ++I) {
516 auto& Map = Data.Maps[I];
517 auto Third = *(Data.Hints[I].begin() + 2);
518 for (auto K : Data.Keys) {
519 auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end();
520 #ifndef VALIDATE
521 benchmark::DoNotOptimize(Map.emplace_hint(Itor, K, 1));
522 #else
523 size_t Size = Map.size();
524 Map.emplace_hint(Itor, K, 1);
525 if (Mode() == ::Mode::Hit) {
526 if (Size != Map.size())
527 State.SkipWithError("Emplaced a duplicate element");
528 } else {
529 if (Size + 1 != Map.size())
530 State.SkipWithError("Failed to emplace a new element");
532 #endif
536 State.PauseTiming();
537 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
538 State.ResumeTiming();
542 void run(benchmark::State& State) const {
543 static constexpr auto h = Hint();
544 run<h>(State);
547 std::string name() const { return "BM_EmplaceHint" + baseName() + Mode::name() + Hint::name(); }
550 template <class Mode, class Order>
551 struct TryEmplace : Base {
552 using Base::Base;
554 void run(benchmark::State& State) const {
555 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
556 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
557 for (auto& Map : Data.Maps) {
558 for (auto K : Data.Keys) {
559 #ifndef VALIDATE
560 benchmark::DoNotOptimize(Map.try_emplace(K, 1));
561 #else
562 bool Inserted = Map.try_emplace(K, 1).second;
563 if (Mode() == ::Mode::Hit) {
564 if (Inserted)
565 State.SkipWithError("Emplaced a duplicate element");
566 } else {
567 if (!Inserted)
568 State.SkipWithError("Failed to emplace a new element");
570 #endif
574 State.PauseTiming();
575 Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
576 State.ResumeTiming();
580 std::string name() const { return "BM_TryEmplace" + baseName() + Mode::name() + Order::name(); }
583 template <class Mode, class Hint>
584 struct TryEmplaceHint : Base {
585 using Base::Base;
587 template < ::Hint hint>
588 typename std::enable_if<hint == ::Hint::Correct>::type run(benchmark::State& State) const {
589 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
590 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
591 for (size_t I = 0; I < Data.Maps.size(); ++I) {
592 auto& Map = Data.Maps[I];
593 auto H = Data.Hints[I].begin();
594 for (auto K : Data.Keys) {
595 #ifndef VALIDATE
596 benchmark::DoNotOptimize(Map.try_emplace(*H, K, 1));
597 #else
598 auto Inserted = Map.try_emplace(*H, K, 1);
599 if (Mode() == ::Mode::Hit) {
600 if (Inserted != *H)
601 State.SkipWithError("Emplaced a duplicate element");
602 } else {
603 if (++Inserted != *H)
604 State.SkipWithError("Failed to emplace a new element");
606 #endif
607 ++H;
611 State.PauseTiming();
612 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
613 State.ResumeTiming();
617 template < ::Hint hint>
618 typename std::enable_if<hint != ::Hint::Correct>::type run(benchmark::State& State) const {
619 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
620 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
621 for (size_t I = 0; I < Data.Maps.size(); ++I) {
622 auto& Map = Data.Maps[I];
623 auto Third = *(Data.Hints[I].begin() + 2);
624 for (auto K : Data.Keys) {
625 auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end();
626 #ifndef VALIDATE
627 benchmark::DoNotOptimize(Map.try_emplace(Itor, K, 1));
628 #else
629 size_t Size = Map.size();
630 Map.try_emplace(Itor, K, 1);
631 if (Mode() == ::Mode::Hit) {
632 if (Size != Map.size())
633 State.SkipWithError("Emplaced a duplicate element");
634 } else {
635 if (Size + 1 != Map.size())
636 State.SkipWithError("Failed to emplace a new element");
638 #endif
642 State.PauseTiming();
643 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
644 State.ResumeTiming();
648 void run(benchmark::State& State) const {
649 static constexpr auto h = Hint();
650 run<h>(State);
653 std::string name() const { return "BM_TryEmplaceHint" + baseName() + Mode::name() + Hint::name(); }
656 template <class Mode, class Order>
657 struct Erase : Base {
658 using Base::Base;
660 void run(benchmark::State& State) const {
661 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
662 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
663 for (auto& Map : Data.Maps) {
664 for (auto K : Data.Keys) {
665 #ifndef VALIDATE
666 benchmark::DoNotOptimize(Map.erase(K));
667 #else
668 size_t I = Map.erase(K);
669 if (Mode() == ::Mode::Hit) {
670 if (I == 0)
671 State.SkipWithError("Did not find the existing element");
672 } else {
673 if (I == 1)
674 State.SkipWithError("Did find the non-existing element");
676 #endif
680 State.PauseTiming();
681 Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
682 State.ResumeTiming();
686 std::string name() const { return "BM_Erase" + baseName() + Mode::name() + Order::name(); }
689 template <class Order>
690 struct EraseIterator : Base {
691 using Base::Base;
693 void run(benchmark::State& State) const {
694 auto Data =
695 makeTestingSets(MapSize, Mode::Hit, Order::value == ::Order::Random ? Shuffle::Hints : Shuffle::None, 1000);
696 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
697 for (size_t I = 0; I < Data.Maps.size(); ++I) {
698 auto& Map = Data.Maps[I];
699 for (auto H : Data.Hints[I]) {
700 benchmark::DoNotOptimize(Map.erase(H));
702 #ifdef VALIDATE
703 if (!Map.empty())
704 State.SkipWithError("Did not erase the entire map");
705 #endif
708 State.PauseTiming();
709 Data =
710 makeTestingSets(MapSize, Mode::Hit, Order::value == ::Order::Random ? Shuffle::Hints : Shuffle::None, 1000);
711 State.ResumeTiming();
715 std::string name() const { return "BM_EraseIterator" + baseName() + Order::name(); }
718 struct EraseRange : Base {
719 using Base::Base;
721 void run(benchmark::State& State) const {
722 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
723 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
724 for (auto& Map : Data.Maps) {
725 #ifndef VALIDATE
726 benchmark::DoNotOptimize(Map.erase(Map.begin(), Map.end()));
727 #else
728 Map.erase(Map.begin(), Map.end());
729 if (!Map.empty())
730 State.SkipWithError("Did not erase the entire map");
731 #endif
734 State.PauseTiming();
735 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
736 State.ResumeTiming();
740 std::string name() const { return "BM_EraseRange" + baseName(); }
743 //*******************************************************************|
744 // Lookup |
745 //*******************************************************************|
747 template <class Mode, class Order>
748 struct Count : Base {
749 using Base::Base;
751 void run(benchmark::State& State) const {
752 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
753 auto& Map = Data.Maps.front();
754 while (State.KeepRunningBatch(MapSize)) {
755 for (auto K : Data.Keys) {
756 #ifndef VALIDATE
757 benchmark::DoNotOptimize(Map.count(K));
758 #else
759 size_t I = Map.count(K);
760 if (Mode() == ::Mode::Hit) {
761 if (I == 0)
762 State.SkipWithError("Did not find the existing element");
763 } else {
764 if (I == 1)
765 State.SkipWithError("Did find the non-existing element");
767 #endif
772 std::string name() const { return "BM_Count" + baseName() + Mode::name() + Order::name(); }
775 template <class Mode, class Order>
776 struct Find : Base {
777 using Base::Base;
779 void run(benchmark::State& State) const {
780 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
781 auto& Map = Data.Maps.front();
782 while (State.KeepRunningBatch(MapSize)) {
783 for (auto K : Data.Keys) {
784 #ifndef VALIDATE
785 benchmark::DoNotOptimize(Map.find(K));
786 #else
787 auto Itor = Map.find(K);
788 if (Mode() == ::Mode::Hit) {
789 if (Itor == Map.end())
790 State.SkipWithError("Did not find the existing element");
791 } else {
792 if (Itor != Map.end())
793 State.SkipWithError("Did find the non-existing element");
795 #endif
800 std::string name() const { return "BM_Find" + baseName() + Mode::name() + Order::name(); }
803 template <class Mode, class Order>
804 struct EqualRange : Base {
805 using Base::Base;
807 void run(benchmark::State& State) const {
808 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
809 auto& Map = Data.Maps.front();
810 while (State.KeepRunningBatch(MapSize)) {
811 for (auto K : Data.Keys) {
812 #ifndef VALIDATE
813 benchmark::DoNotOptimize(Map.equal_range(K));
814 #else
815 auto Range = Map.equal_range(K);
816 if (Mode() == ::Mode::Hit) {
817 // Adjust validation for the last element.
818 auto Key = K;
819 if (Range.second == Map.end() && K == 2 * MapSize) {
820 --Range.second;
821 Key -= 2;
823 if (Range.first == Map.end() || Range.first->first != K || Range.second == Map.end() ||
824 Range.second->first - 2 != Key)
825 State.SkipWithError("Did not find the existing element");
826 } else {
827 if (Range.first == Map.end() || Range.first->first - 1 != K || Range.second == Map.end() ||
828 Range.second->first - 1 != K)
829 State.SkipWithError("Did find the non-existing element");
831 #endif
836 std::string name() const { return "BM_EqualRange" + baseName() + Mode::name() + Order::name(); }
839 template <class Mode, class Order>
840 struct LowerBound : Base {
841 using Base::Base;
843 void run(benchmark::State& State) const {
844 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
845 auto& Map = Data.Maps.front();
846 while (State.KeepRunningBatch(MapSize)) {
847 for (auto K : Data.Keys) {
848 #ifndef VALIDATE
849 benchmark::DoNotOptimize(Map.lower_bound(K));
850 #else
851 auto Itor = Map.lower_bound(K);
852 if (Mode() == ::Mode::Hit) {
853 if (Itor == Map.end() || Itor->first != K)
854 State.SkipWithError("Did not find the existing element");
855 } else {
856 if (Itor == Map.end() || Itor->first - 1 != K)
857 State.SkipWithError("Did find the non-existing element");
859 #endif
864 std::string name() const { return "BM_LowerBound" + baseName() + Mode::name() + Order::name(); }
867 template <class Mode, class Order>
868 struct UpperBound : Base {
869 using Base::Base;
871 void run(benchmark::State& State) const {
872 auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
873 auto& Map = Data.Maps.front();
874 while (State.KeepRunningBatch(MapSize)) {
875 for (auto K : Data.Keys) {
876 #ifndef VALIDATE
877 benchmark::DoNotOptimize(Map.upper_bound(K));
878 #else
879 std::map<uint64_t, int64_t>::iterator Itor = Map.upper_bound(K);
880 if (Mode() == ::Mode::Hit) {
881 // Adjust validation for the last element.
882 auto Key = K;
883 if (Itor == Map.end() && K == 2 * MapSize) {
884 --Itor;
885 Key -= 2;
887 if (Itor == Map.end() || Itor->first - 2 != Key)
888 State.SkipWithError("Did not find the existing element");
889 } else {
890 if (Itor == Map.end() || Itor->first - 1 != K)
891 State.SkipWithError("Did find the non-existing element");
893 #endif
898 std::string name() const { return "BM_UpperBound" + baseName() + Mode::name() + Order::name(); }
901 } // namespace
903 int main(int argc, char** argv) {
904 benchmark::Initialize(&argc, argv);
905 if (benchmark::ReportUnrecognizedArguments(argc, argv))
906 return 1;
908 #ifdef VALIDATE
909 const std::vector<size_t> MapSize{10};
910 #else
911 const std::vector<size_t> MapSize{10, 100, 1000, 10000, 100000, 1000000};
912 #endif
914 // Member functions
915 makeCartesianProductBenchmark<ConstructorDefault>();
916 makeCartesianProductBenchmark<ConstructorIterator>(MapSize);
917 makeCartesianProductBenchmark<ConstructorCopy>(MapSize);
918 makeCartesianProductBenchmark<ConstructorMove>(MapSize);
920 // Capacity
921 makeCartesianProductBenchmark<Empty>(MapSize);
922 makeCartesianProductBenchmark<Size>(MapSize);
924 // Modifiers
925 makeCartesianProductBenchmark<Clear>(MapSize);
926 makeCartesianProductBenchmark<Insert, AllModes, AllOrders>(MapSize);
927 makeCartesianProductBenchmark<InsertHint, AllModes, AllHints>(MapSize);
928 makeCartesianProductBenchmark<InsertAssign, AllModes, AllOrders>(MapSize);
929 makeCartesianProductBenchmark<InsertAssignHint, AllModes, AllHints>(MapSize);
931 makeCartesianProductBenchmark<Emplace, AllModes, AllOrders>(MapSize);
932 makeCartesianProductBenchmark<EmplaceHint, AllModes, AllHints>(MapSize);
933 makeCartesianProductBenchmark<TryEmplace, AllModes, AllOrders>(MapSize);
934 makeCartesianProductBenchmark<TryEmplaceHint, AllModes, AllHints>(MapSize);
935 makeCartesianProductBenchmark<Erase, AllModes, AllOrders>(MapSize);
936 makeCartesianProductBenchmark<EraseIterator, AllOrders>(MapSize);
937 makeCartesianProductBenchmark<EraseRange>(MapSize);
939 // Lookup
940 makeCartesianProductBenchmark<Count, AllModes, AllOrders>(MapSize);
941 makeCartesianProductBenchmark<Find, AllModes, AllOrders>(MapSize);
942 makeCartesianProductBenchmark<EqualRange, AllModes, AllOrders>(MapSize);
943 makeCartesianProductBenchmark<LowerBound, AllModes, AllOrders>(MapSize);
944 makeCartesianProductBenchmark<UpperBound, AllModes, AllOrders>(MapSize);
946 benchmark::RunSpecifiedBenchmarks();