[lld][WebAssembly] Reinstate mistakenly disabled test. NFC
[llvm-project.git] / libcxx / benchmarks / map.bench.cpp
blobdd1884f65032e5bff6e6b5ab2c1169d9391e99a1
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<
54 std::vector<typename std::map<uint64_t, int64_t>::const_iterator> >
55 Hints;
58 enum class Shuffle { None, Keys, Hints };
60 TestSets makeTestingSets(size_t MapSize, Mode mode, Shuffle shuffle,
61 size_t max_maps) {
63 * The shuffle does not retain the random number generator to use the same
64 * set of random numbers for every iteration.
66 TestSets R;
68 int MapCount = std::min(max_maps, 1000000 / MapSize);
70 for (uint64_t I = 0; I < MapSize; ++I) {
71 R.Keys.push_back(mode == Mode::Hit ? 2 * I + 2 : 2 * I + 1);
73 if (shuffle == Shuffle::Keys)
74 std::shuffle(R.Keys.begin(), R.Keys.end(), std::mt19937());
76 for (int M = 0; M < MapCount; ++M) {
77 auto& map = R.Maps.emplace_back();
78 auto& hints = R.Hints.emplace_back();
79 for (uint64_t I = 0; I < MapSize; ++I) {
80 hints.push_back(map.insert(std::make_pair(2 * I + 2, 0)).first);
82 if (shuffle == Shuffle::Hints)
83 std::shuffle(hints.begin(), hints.end(), std::mt19937());
86 return R;
89 struct Base {
90 size_t MapSize;
91 Base(size_t T) : MapSize(T) {}
93 std::string baseName() const { return "_MapSize=" + std::to_string(MapSize); }
96 //*******************************************************************|
97 // Member functions |
98 //*******************************************************************|
100 struct ConstructorDefault {
101 void run(benchmark::State& State) const {
102 for (auto _ : State) {
103 benchmark::DoNotOptimize(std::map<uint64_t, int64_t>());
107 std::string name() const { return "BM_ConstructorDefault"; }
110 struct ConstructorIterator : Base {
111 using Base::Base;
113 void run(benchmark::State& State) const {
114 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
115 auto& Map = Data.Maps.front();
116 while (State.KeepRunningBatch(MapSize)) {
117 #ifndef VALIDATE
118 benchmark::DoNotOptimize(
119 std::map<uint64_t, int64_t>(Map.begin(), Map.end()));
120 #else
121 std::map<uint64_t, int64_t> M{Map.begin(), Map.end()};
122 if (M != Map)
123 State.SkipWithError("Map copy not identical");
124 #endif
128 std::string name() const { return "BM_ConstructorIterator" + baseName(); }
131 struct ConstructorCopy : Base {
132 using Base::Base;
134 void run(benchmark::State& State) const {
135 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
136 auto& Map = Data.Maps.front();
137 while (State.KeepRunningBatch(MapSize)) {
138 #ifndef VALIDATE
139 std::map<uint64_t, int64_t> M(Map);
140 benchmark::DoNotOptimize(M);
141 #else
142 std::map<uint64_t, int64_t> M(Map);
143 if (M != Map)
144 State.SkipWithError("Map copy not identical");
145 #endif
149 std::string name() const { return "BM_ConstructorCopy" + baseName(); }
152 struct ConstructorMove : Base {
153 using Base::Base;
155 void run(benchmark::State& State) const {
156 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
157 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
158 for (auto& Map : Data.Maps) {
159 std::map<uint64_t, int64_t> M(std::move(Map));
160 benchmark::DoNotOptimize(M);
162 State.PauseTiming();
163 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
164 State.ResumeTiming();
168 std::string name() const { return "BM_ConstructorMove" + baseName(); }
171 //*******************************************************************|
172 // Capacity |
173 //*******************************************************************|
175 struct Empty : Base {
176 using Base::Base;
178 void run(benchmark::State& State) const {
179 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
180 auto& Map = Data.Maps.front();
181 for (auto _ : State) {
182 #ifndef VALIDATE
183 benchmark::DoNotOptimize(Map.empty());
184 #else
185 if (Map.empty())
186 State.SkipWithError("Map contains an invalid number of elements.");
187 #endif
191 std::string name() const { return "BM_Empty" + baseName(); }
194 struct Size : Base {
195 using Base::Base;
197 void run(benchmark::State& State) const {
198 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
199 auto& Map = Data.Maps.front();
200 for (auto _ : State) {
201 #ifndef VALIDATE
202 benchmark::DoNotOptimize(Map.size());
203 #else
204 if (Map.size() != MapSize)
205 State.SkipWithError("Map contains an invalid number of elements.");
206 #endif
210 std::string name() const { return "BM_Size" + baseName(); }
213 //*******************************************************************|
214 // Modifiers |
215 //*******************************************************************|
217 struct Clear : Base {
218 using Base::Base;
220 void run(benchmark::State& State) const {
221 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
222 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
223 for (auto& Map : Data.Maps) {
224 Map.clear();
225 benchmark::DoNotOptimize(Map);
227 State.PauseTiming();
228 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
229 State.ResumeTiming();
233 std::string name() const { return "BM_Clear" + baseName(); }
236 template <class Mode, class Order>
237 struct Insert : Base {
238 using Base::Base;
240 void run(benchmark::State& State) const {
241 auto Data = makeTestingSets(
242 MapSize, Mode(),
243 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
244 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
245 for (auto& Map : Data.Maps) {
246 for (auto K : Data.Keys) {
247 #ifndef VALIDATE
248 benchmark::DoNotOptimize(Map.insert(std::make_pair(K, 1)));
249 #else
250 bool Inserted = Map.insert(std::make_pair(K, 1)).second;
251 if (Mode() == ::Mode::Hit) {
252 if (Inserted)
253 State.SkipWithError("Inserted a duplicate element");
254 } else {
255 if (!Inserted)
256 State.SkipWithError("Failed to insert e new element");
258 #endif
262 State.PauseTiming();
263 Data = makeTestingSets(MapSize, Mode(),
264 Order::value == ::Order::Random ? Shuffle::Keys
265 : Shuffle::None,
266 1000);
267 State.ResumeTiming();
271 std::string name() const {
272 return "BM_Insert" + baseName() + Mode::name() + Order::name();
276 template <class Mode, class Hint>
277 struct InsertHint : Base {
278 using Base::Base;
280 template < ::Hint hint>
281 typename std::enable_if<hint == ::Hint::Correct>::type
282 run(benchmark::State& State) const {
283 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
284 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
285 for (size_t I = 0; I < Data.Maps.size(); ++I) {
286 auto& Map = Data.Maps[I];
287 auto H = Data.Hints[I].begin();
288 for (auto K : Data.Keys) {
289 #ifndef VALIDATE
290 benchmark::DoNotOptimize(Map.insert(*H, std::make_pair(K, 1)));
291 #else
292 auto Inserted = Map.insert(*H, std::make_pair(K, 1));
293 if (Mode() == ::Mode::Hit) {
294 if (Inserted != *H)
295 State.SkipWithError("Inserted a duplicate element");
296 } else {
297 if (++Inserted != *H)
298 State.SkipWithError("Failed to insert a new element");
300 #endif
301 ++H;
305 State.PauseTiming();
306 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
307 State.ResumeTiming();
311 template < ::Hint hint>
312 typename std::enable_if<hint != ::Hint::Correct>::type
313 run(benchmark::State& State) const {
314 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
315 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
316 for (size_t I = 0; I < Data.Maps.size(); ++I) {
317 auto& Map = Data.Maps[I];
318 auto Third = *(Data.Hints[I].begin() + 2);
319 for (auto K : Data.Keys) {
320 auto Itor = hint == ::Hint::Begin
321 ? Map.begin()
322 : hint == ::Hint::Third ? Third : Map.end();
323 #ifndef VALIDATE
324 benchmark::DoNotOptimize(Map.insert(Itor, std::make_pair(K, 1)));
325 #else
326 size_t Size = Map.size();
327 Map.insert(Itor, std::make_pair(K, 1));
328 if (Mode() == ::Mode::Hit) {
329 if (Size != Map.size())
330 State.SkipWithError("Inserted a duplicate element");
331 } else {
332 if (Size + 1 != Map.size())
333 State.SkipWithError("Failed to insert a new element");
335 #endif
339 State.PauseTiming();
340 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
341 State.ResumeTiming();
345 void run(benchmark::State& State) const {
346 static constexpr auto h = Hint();
347 run<h>(State);
350 std::string name() const {
351 return "BM_InsertHint" + baseName() + Mode::name() + Hint::name();
355 template <class Mode, class Order>
356 struct InsertAssign : Base {
357 using Base::Base;
359 void run(benchmark::State& State) const {
360 auto Data = makeTestingSets(
361 MapSize, Mode(),
362 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
363 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
364 for (auto& Map : Data.Maps) {
365 for (auto K : Data.Keys) {
366 #ifndef VALIDATE
367 benchmark::DoNotOptimize(Map.insert_or_assign(K, 1));
368 #else
369 bool Inserted = Map.insert_or_assign(K, 1).second;
370 if (Mode() == ::Mode::Hit) {
371 if (Inserted)
372 State.SkipWithError("Inserted a duplicate element");
373 } else {
374 if (!Inserted)
375 State.SkipWithError("Failed to insert e new element");
377 #endif
381 State.PauseTiming();
382 Data = makeTestingSets(MapSize, Mode(),
383 Order::value == ::Order::Random ? Shuffle::Keys
384 : Shuffle::None,
385 1000);
386 State.ResumeTiming();
390 std::string name() const {
391 return "BM_InsertAssign" + baseName() + Mode::name() + Order::name();
395 template <class Mode, class Hint>
396 struct InsertAssignHint : Base {
397 using Base::Base;
399 template < ::Hint hint>
400 typename std::enable_if<hint == ::Hint::Correct>::type
401 run(benchmark::State& State) const {
402 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
403 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
404 for (size_t I = 0; I < Data.Maps.size(); ++I) {
405 auto& Map = Data.Maps[I];
406 auto H = Data.Hints[I].begin();
407 for (auto K : Data.Keys) {
408 #ifndef VALIDATE
409 benchmark::DoNotOptimize(Map.insert_or_assign(*H, K, 1));
410 #else
411 auto Inserted = Map.insert_or_assign(*H, K, 1);
412 if (Mode() == ::Mode::Hit) {
413 if (Inserted != *H)
414 State.SkipWithError("Inserted a duplicate element");
415 } else {
416 if (++Inserted != *H)
417 State.SkipWithError("Failed to insert a new element");
419 #endif
420 ++H;
424 State.PauseTiming();
425 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
426 State.ResumeTiming();
430 template < ::Hint hint>
431 typename std::enable_if<hint != ::Hint::Correct>::type
432 run(benchmark::State& State) const {
433 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
434 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
435 for (size_t I = 0; I < Data.Maps.size(); ++I) {
436 auto& Map = Data.Maps[I];
437 auto Third = *(Data.Hints[I].begin() + 2);
438 for (auto K : Data.Keys) {
439 auto Itor = hint == ::Hint::Begin
440 ? Map.begin()
441 : hint == ::Hint::Third ? Third : Map.end();
442 #ifndef VALIDATE
443 benchmark::DoNotOptimize(Map.insert_or_assign(Itor, K, 1));
444 #else
445 size_t Size = Map.size();
446 Map.insert_or_assign(Itor, K, 1);
447 if (Mode() == ::Mode::Hit) {
448 if (Size != Map.size())
449 State.SkipWithError("Inserted a duplicate element");
450 } else {
451 if (Size + 1 != Map.size())
452 State.SkipWithError("Failed to insert a new element");
454 #endif
458 State.PauseTiming();
459 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
460 State.ResumeTiming();
464 void run(benchmark::State& State) const {
465 static constexpr auto h = Hint();
466 run<h>(State);
469 std::string name() const {
470 return "BM_InsertAssignHint" + baseName() + Mode::name() + Hint::name();
474 template <class Mode, class Order>
475 struct Emplace : Base {
476 using Base::Base;
478 void run(benchmark::State& State) const {
480 auto Data = makeTestingSets(
481 MapSize, Mode(),
482 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
483 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
484 for (auto& Map : Data.Maps) {
485 for (auto K : Data.Keys) {
486 #ifndef VALIDATE
487 benchmark::DoNotOptimize(Map.emplace(K, 1));
488 #else
489 bool Inserted = Map.emplace(K, 1).second;
490 if (Mode() == ::Mode::Hit) {
491 if (Inserted)
492 State.SkipWithError("Emplaced a duplicate element");
493 } else {
494 if (!Inserted)
495 State.SkipWithError("Failed to emplace a new element");
497 #endif
501 State.PauseTiming();
502 Data = makeTestingSets(MapSize, Mode(),
503 Order::value == ::Order::Random ? Shuffle::Keys
504 : Shuffle::None,
505 1000);
506 State.ResumeTiming();
510 std::string name() const {
511 return "BM_Emplace" + baseName() + Mode::name() + Order::name();
515 template <class Mode, class Hint>
516 struct EmplaceHint : Base {
517 using Base::Base;
519 template < ::Hint hint>
520 typename std::enable_if<hint == ::Hint::Correct>::type
521 run(benchmark::State& State) const {
522 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
523 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
524 for (size_t I = 0; I < Data.Maps.size(); ++I) {
525 auto& Map = Data.Maps[I];
526 auto H = Data.Hints[I].begin();
527 for (auto K : Data.Keys) {
528 #ifndef VALIDATE
529 benchmark::DoNotOptimize(Map.emplace_hint(*H, K, 1));
530 #else
531 auto Inserted = Map.emplace_hint(*H, K, 1);
532 if (Mode() == ::Mode::Hit) {
533 if (Inserted != *H)
534 State.SkipWithError("Emplaced a duplicate element");
535 } else {
536 if (++Inserted != *H)
537 State.SkipWithError("Failed to emplace a new element");
539 #endif
540 ++H;
544 State.PauseTiming();
545 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
546 State.ResumeTiming();
550 template < ::Hint hint>
551 typename std::enable_if<hint != ::Hint::Correct>::type
552 run(benchmark::State& State) const {
553 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
554 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
555 for (size_t I = 0; I < Data.Maps.size(); ++I) {
556 auto& Map = Data.Maps[I];
557 auto Third = *(Data.Hints[I].begin() + 2);
558 for (auto K : Data.Keys) {
559 auto Itor = hint == ::Hint::Begin
560 ? Map.begin()
561 : hint == ::Hint::Third ? Third : Map.end();
562 #ifndef VALIDATE
563 benchmark::DoNotOptimize(Map.emplace_hint(Itor, K, 1));
564 #else
565 size_t Size = Map.size();
566 Map.emplace_hint(Itor, K, 1);
567 if (Mode() == ::Mode::Hit) {
568 if (Size != Map.size())
569 State.SkipWithError("Emplaced a duplicate element");
570 } else {
571 if (Size + 1 != Map.size())
572 State.SkipWithError("Failed to emplace a new element");
574 #endif
578 State.PauseTiming();
579 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
580 State.ResumeTiming();
584 void run(benchmark::State& State) const {
585 static constexpr auto h = Hint();
586 run<h>(State);
589 std::string name() const {
590 return "BM_EmplaceHint" + baseName() + Mode::name() + Hint::name();
594 template <class Mode, class Order>
595 struct TryEmplace : Base {
596 using Base::Base;
598 void run(benchmark::State& State) const {
600 auto Data = makeTestingSets(
601 MapSize, Mode(),
602 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
603 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
604 for (auto& Map : Data.Maps) {
605 for (auto K : Data.Keys) {
606 #ifndef VALIDATE
607 benchmark::DoNotOptimize(Map.try_emplace(K, 1));
608 #else
609 bool Inserted = Map.try_emplace(K, 1).second;
610 if (Mode() == ::Mode::Hit) {
611 if (Inserted)
612 State.SkipWithError("Emplaced a duplicate element");
613 } else {
614 if (!Inserted)
615 State.SkipWithError("Failed to emplace a new element");
617 #endif
621 State.PauseTiming();
622 Data = makeTestingSets(MapSize, Mode(),
623 Order::value == ::Order::Random ? Shuffle::Keys
624 : Shuffle::None,
625 1000);
626 State.ResumeTiming();
630 std::string name() const {
631 return "BM_TryEmplace" + baseName() + Mode::name() + Order::name();
635 template <class Mode, class Hint>
636 struct TryEmplaceHint : Base {
637 using Base::Base;
639 template < ::Hint hint>
640 typename std::enable_if<hint == ::Hint::Correct>::type
641 run(benchmark::State& State) const {
642 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
643 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
644 for (size_t I = 0; I < Data.Maps.size(); ++I) {
645 auto& Map = Data.Maps[I];
646 auto H = Data.Hints[I].begin();
647 for (auto K : Data.Keys) {
648 #ifndef VALIDATE
649 benchmark::DoNotOptimize(Map.try_emplace(*H, K, 1));
650 #else
651 auto Inserted = Map.try_emplace(*H, K, 1);
652 if (Mode() == ::Mode::Hit) {
653 if (Inserted != *H)
654 State.SkipWithError("Emplaced a duplicate element");
655 } else {
656 if (++Inserted != *H)
657 State.SkipWithError("Failed to emplace a new element");
659 #endif
660 ++H;
664 State.PauseTiming();
665 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
666 State.ResumeTiming();
670 template < ::Hint hint>
671 typename std::enable_if<hint != ::Hint::Correct>::type
672 run(benchmark::State& State) const {
673 auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
674 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
675 for (size_t I = 0; I < Data.Maps.size(); ++I) {
676 auto& Map = Data.Maps[I];
677 auto Third = *(Data.Hints[I].begin() + 2);
678 for (auto K : Data.Keys) {
679 auto Itor = hint == ::Hint::Begin
680 ? Map.begin()
681 : hint == ::Hint::Third ? Third : Map.end();
682 #ifndef VALIDATE
683 benchmark::DoNotOptimize(Map.try_emplace(Itor, K, 1));
684 #else
685 size_t Size = Map.size();
686 Map.try_emplace(Itor, K, 1);
687 if (Mode() == ::Mode::Hit) {
688 if (Size != Map.size())
689 State.SkipWithError("Emplaced a duplicate element");
690 } else {
691 if (Size + 1 != Map.size())
692 State.SkipWithError("Failed to emplace a new element");
694 #endif
698 State.PauseTiming();
699 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
700 State.ResumeTiming();
704 void run(benchmark::State& State) const {
705 static constexpr auto h = Hint();
706 run<h>(State);
709 std::string name() const {
710 return "BM_TryEmplaceHint" + baseName() + Mode::name() + Hint::name();
714 template <class Mode, class Order>
715 struct Erase : Base {
716 using Base::Base;
718 void run(benchmark::State& State) const {
719 auto Data = makeTestingSets(
720 MapSize, Mode(),
721 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
722 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
723 for (auto& Map : Data.Maps) {
724 for (auto K : Data.Keys) {
725 #ifndef VALIDATE
726 benchmark::DoNotOptimize(Map.erase(K));
727 #else
728 size_t I = Map.erase(K);
729 if (Mode() == ::Mode::Hit) {
730 if (I == 0)
731 State.SkipWithError("Did not find the existing element");
732 } else {
733 if (I == 1)
734 State.SkipWithError("Did find the non-existing element");
736 #endif
740 State.PauseTiming();
741 Data = makeTestingSets(MapSize, Mode(),
742 Order::value == ::Order::Random ? Shuffle::Keys
743 : Shuffle::None,
744 1000);
745 State.ResumeTiming();
749 std::string name() const {
750 return "BM_Erase" + baseName() + Mode::name() + Order::name();
754 template <class Order>
755 struct EraseIterator : Base {
756 using Base::Base;
758 void run(benchmark::State& State) const {
759 auto Data = makeTestingSets(
760 MapSize, Mode::Hit,
761 Order::value == ::Order::Random ? Shuffle::Hints : Shuffle::None, 1000);
762 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
763 for (size_t I = 0; I < Data.Maps.size(); ++I) {
764 auto& Map = Data.Maps[I];
765 for (auto H : Data.Hints[I]) {
766 benchmark::DoNotOptimize(Map.erase(H));
768 #ifdef VALIDATE
769 if (!Map.empty())
770 State.SkipWithError("Did not erase the entire map");
771 #endif
774 State.PauseTiming();
775 Data = makeTestingSets(MapSize, Mode::Hit,
776 Order::value == ::Order::Random ? Shuffle::Hints
777 : Shuffle::None,
778 1000);
779 State.ResumeTiming();
783 std::string name() const {
784 return "BM_EraseIterator" + baseName() + Order::name();
788 struct EraseRange : Base {
789 using Base::Base;
791 void run(benchmark::State& State) const {
792 auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
793 while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
794 for (auto& Map : Data.Maps) {
795 #ifndef VALIDATE
796 benchmark::DoNotOptimize(Map.erase(Map.begin(), Map.end()));
797 #else
798 Map.erase(Map.begin(), Map.end());
799 if (!Map.empty())
800 State.SkipWithError("Did not erase the entire map");
801 #endif
804 State.PauseTiming();
805 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
806 State.ResumeTiming();
810 std::string name() const { return "BM_EraseRange" + baseName(); }
813 //*******************************************************************|
814 // Lookup |
815 //*******************************************************************|
817 template <class Mode, class Order>
818 struct Count : Base {
819 using Base::Base;
821 void run(benchmark::State& State) const {
822 auto Data = makeTestingSets(
823 MapSize, Mode(),
824 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
825 auto& Map = Data.Maps.front();
826 while (State.KeepRunningBatch(MapSize)) {
827 for (auto K : Data.Keys) {
828 #ifndef VALIDATE
829 benchmark::DoNotOptimize(Map.count(K));
830 #else
831 size_t I = Map.count(K);
832 if (Mode() == ::Mode::Hit) {
833 if (I == 0)
834 State.SkipWithError("Did not find the existing element");
835 } else {
836 if (I == 1)
837 State.SkipWithError("Did find the non-existing element");
839 #endif
844 std::string name() const {
845 return "BM_Count" + baseName() + Mode::name() + Order::name();
849 template <class Mode, class Order>
850 struct Find : Base {
851 using Base::Base;
853 void run(benchmark::State& State) const {
854 auto Data = makeTestingSets(
855 MapSize, Mode(),
856 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
857 auto& Map = Data.Maps.front();
858 while (State.KeepRunningBatch(MapSize)) {
859 for (auto K : Data.Keys) {
860 #ifndef VALIDATE
861 benchmark::DoNotOptimize(Map.find(K));
862 #else
863 auto Itor = Map.find(K);
864 if (Mode() == ::Mode::Hit) {
865 if (Itor == Map.end())
866 State.SkipWithError("Did not find the existing element");
867 } else {
868 if (Itor != Map.end())
869 State.SkipWithError("Did find the non-existing element");
871 #endif
876 std::string name() const {
877 return "BM_Find" + baseName() + Mode::name() + Order::name();
881 template <class Mode, class Order>
882 struct EqualRange : Base {
883 using Base::Base;
885 void run(benchmark::State& State) const {
886 auto Data = makeTestingSets(
887 MapSize, Mode(),
888 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
889 auto& Map = Data.Maps.front();
890 while (State.KeepRunningBatch(MapSize)) {
891 for (auto K : Data.Keys) {
892 #ifndef VALIDATE
893 benchmark::DoNotOptimize(Map.equal_range(K));
894 #else
895 auto Range = Map.equal_range(K);
896 if (Mode() == ::Mode::Hit) {
897 // Adjust validation for the last element.
898 auto Key = K;
899 if (Range.second == Map.end() && K == 2 * MapSize) {
900 --Range.second;
901 Key -= 2;
903 if (Range.first == Map.end() || Range.first->first != K ||
904 Range.second == Map.end() || Range.second->first - 2 != Key)
905 State.SkipWithError("Did not find the existing element");
906 } else {
907 if (Range.first == Map.end() || Range.first->first - 1 != K ||
908 Range.second == Map.end() || Range.second->first - 1 != K)
909 State.SkipWithError("Did find the non-existing element");
911 #endif
916 std::string name() const {
917 return "BM_EqualRange" + baseName() + Mode::name() + Order::name();
921 template <class Mode, class Order>
922 struct LowerBound : Base {
923 using Base::Base;
925 void run(benchmark::State& State) const {
926 auto Data = makeTestingSets(
927 MapSize, Mode(),
928 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
929 auto& Map = Data.Maps.front();
930 while (State.KeepRunningBatch(MapSize)) {
931 for (auto K : Data.Keys) {
932 #ifndef VALIDATE
933 benchmark::DoNotOptimize(Map.lower_bound(K));
934 #else
935 auto Itor = Map.lower_bound(K);
936 if (Mode() == ::Mode::Hit) {
937 if (Itor == Map.end() || Itor->first != K)
938 State.SkipWithError("Did not find the existing element");
939 } else {
940 if (Itor == Map.end() || Itor->first - 1 != K)
941 State.SkipWithError("Did find the non-existing element");
943 #endif
948 std::string name() const {
949 return "BM_LowerBound" + baseName() + Mode::name() + Order::name();
953 template <class Mode, class Order>
954 struct UpperBound : Base {
955 using Base::Base;
957 void run(benchmark::State& State) const {
958 auto Data = makeTestingSets(
959 MapSize, Mode(),
960 Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
961 auto& Map = Data.Maps.front();
962 while (State.KeepRunningBatch(MapSize)) {
963 for (auto K : Data.Keys) {
964 #ifndef VALIDATE
965 benchmark::DoNotOptimize(Map.upper_bound(K));
966 #else
967 std::map<uint64_t, int64_t>::iterator Itor = Map.upper_bound(K);
968 if (Mode() == ::Mode::Hit) {
969 // Adjust validation for the last element.
970 auto Key = K;
971 if (Itor == Map.end() && K == 2 * MapSize) {
972 --Itor;
973 Key -= 2;
975 if (Itor == Map.end() || Itor->first - 2 != Key)
976 State.SkipWithError("Did not find the existing element");
977 } else {
978 if (Itor == Map.end() || Itor->first - 1 != K)
979 State.SkipWithError("Did find the non-existing element");
981 #endif
986 std::string name() const {
987 return "BM_UpperBound" + baseName() + Mode::name() + Order::name();
991 } // namespace
993 int main(int argc, char** argv) {
994 benchmark::Initialize(&argc, argv);
995 if (benchmark::ReportUnrecognizedArguments(argc, argv))
996 return 1;
998 #ifdef VALIDATE
999 const std::vector<size_t> MapSize{10};
1000 #else
1001 const std::vector<size_t> MapSize{10, 100, 1000, 10000, 100000, 1000000};
1002 #endif
1004 // Member functions
1005 makeCartesianProductBenchmark<ConstructorDefault>();
1006 makeCartesianProductBenchmark<ConstructorIterator>(MapSize);
1007 makeCartesianProductBenchmark<ConstructorCopy>(MapSize);
1008 makeCartesianProductBenchmark<ConstructorMove>(MapSize);
1010 // Capacity
1011 makeCartesianProductBenchmark<Empty>(MapSize);
1012 makeCartesianProductBenchmark<Size>(MapSize);
1014 // Modifiers
1015 makeCartesianProductBenchmark<Clear>(MapSize);
1016 makeCartesianProductBenchmark<Insert, AllModes, AllOrders>(MapSize);
1017 makeCartesianProductBenchmark<InsertHint, AllModes, AllHints>(MapSize);
1018 makeCartesianProductBenchmark<InsertAssign, AllModes, AllOrders>(MapSize);
1019 makeCartesianProductBenchmark<InsertAssignHint, AllModes, AllHints>(MapSize);
1021 makeCartesianProductBenchmark<Emplace, AllModes, AllOrders>(MapSize);
1022 makeCartesianProductBenchmark<EmplaceHint, AllModes, AllHints>(MapSize);
1023 makeCartesianProductBenchmark<TryEmplace, AllModes, AllOrders>(MapSize);
1024 makeCartesianProductBenchmark<TryEmplaceHint, AllModes, AllHints>(MapSize);
1025 makeCartesianProductBenchmark<Erase, AllModes, AllOrders>(MapSize);
1026 makeCartesianProductBenchmark<EraseIterator, AllOrders>(MapSize);
1027 makeCartesianProductBenchmark<EraseRange>(MapSize);
1029 // Lookup
1030 makeCartesianProductBenchmark<Count, AllModes, AllOrders>(MapSize);
1031 makeCartesianProductBenchmark<Find, AllModes, AllOrders>(MapSize);
1032 makeCartesianProductBenchmark<EqualRange, AllModes, AllOrders>(MapSize);
1033 makeCartesianProductBenchmark<LowerBound, AllModes, AllOrders>(MapSize);
1034 makeCartesianProductBenchmark<UpperBound, AllModes, AllOrders>(MapSize);
1036 benchmark::RunSpecifiedBenchmarks();