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 //===----------------------------------------------------------------------===//
8
9 #include <algorithm>
10 #include <cstdint>
11 #include <map>
12 #include <random>
13 #include <vector>
14
15 #include "CartesianBenchmarks.h"
16 #include "benchmark/benchmark.h"
17 #include "test_macros.h"
18
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
25
26 namespace {
27
28 enum class Mode { Hit, Miss };
29
30 struct AllModes : EnumValuesAsTuple<AllModes, Mode, 2> {
31 static constexpr const char* Names[] = {"ExistingElement", "NewElement"};
32 };
33
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"};
43 };
44
45 enum class Order { Sorted, Random };
46 struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 2> {
47 static constexpr const char* Names[] = {"Sorted", "Random"};
48 };
49
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;
56 };
57
58 enum class Shuffle { None, Keys, Hints };
59
makeTestingSets(size_t MapSize,Mode mode,Shuffle shuffle,size_t max_maps)60 TestSets makeTestingSets(size_t MapSize, Mode mode, Shuffle shuffle,
61 size_t max_maps) {
62 /*
63 * The shuffle does not retain the random number generator to use the same
64 * set of random numbers for every iteration.
65 */
66 TestSets R;
67
68 int MapCount = std::min(max_maps, 1000000 / MapSize);
69
70 for (uint64_t I = 0; I < MapSize; ++I) {
71 R.Keys.push_back(mode == Mode::Hit ? 2 * I + 2 : 2 * I + 1);
72 }
73 if (shuffle == Shuffle::Keys)
74 std::shuffle(R.Keys.begin(), R.Keys.end(), std::mt19937());
75
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);
81 }
82 if (shuffle == Shuffle::Hints)
83 std::shuffle(hints.begin(), hints.end(), std::mt19937());
84 }
85
86 return R;
87 }
88
89 struct Base {
90 size_t MapSize;
Base__anon3e7b95e90111::Base91 Base(size_t T) : MapSize(T) {}
92
baseName__anon3e7b95e90111::Base93 std::string baseName() const { return "_MapSize=" + std::to_string(MapSize); }
94 };
95
96 //*******************************************************************|
97 // Member functions |
98 //*******************************************************************|
99
100 struct ConstructorDefault {
run__anon3e7b95e90111::ConstructorDefault101 void run(benchmark::State& State) const {
102 for (auto _ : State) {
103 benchmark::DoNotOptimize(std::map<uint64_t, int64_t>());
104 }
105 }
106
name__anon3e7b95e90111::ConstructorDefault107 std::string name() const { return "BM_ConstructorDefault"; }
108 };
109
110 struct ConstructorIterator : Base {
111 using Base::Base;
112
run__anon3e7b95e90111::ConstructorIterator113 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
125 }
126 }
127
name__anon3e7b95e90111::ConstructorIterator128 std::string name() const { return "BM_ConstructorIterator" + baseName(); }
129 };
130
131 struct ConstructorCopy : Base {
132 using Base::Base;
133
run__anon3e7b95e90111::ConstructorCopy134 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
146 }
147 }
148
name__anon3e7b95e90111::ConstructorCopy149 std::string name() const { return "BM_ConstructorCopy" + baseName(); }
150 };
151
152 struct ConstructorMove : Base {
153 using Base::Base;
154
run__anon3e7b95e90111::ConstructorMove155 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);
161 }
162 State.PauseTiming();
163 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
164 State.ResumeTiming();
165 }
166 }
167
name__anon3e7b95e90111::ConstructorMove168 std::string name() const { return "BM_ConstructorMove" + baseName(); }
169 };
170
171 //*******************************************************************|
172 // Capacity |
173 //*******************************************************************|
174
175 struct Empty : Base {
176 using Base::Base;
177
run__anon3e7b95e90111::Empty178 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
188 }
189 }
190
name__anon3e7b95e90111::Empty191 std::string name() const { return "BM_Empty" + baseName(); }
192 };
193
194 struct Size : Base {
195 using Base::Base;
196
run__anon3e7b95e90111::Size197 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
207 }
208 }
209
name__anon3e7b95e90111::Size210 std::string name() const { return "BM_Size" + baseName(); }
211 };
212
213 //*******************************************************************|
214 // Modifiers |
215 //*******************************************************************|
216
217 struct Clear : Base {
218 using Base::Base;
219
run__anon3e7b95e90111::Clear220 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);
226 }
227 State.PauseTiming();
228 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
229 State.ResumeTiming();
230 }
231 }
232
name__anon3e7b95e90111::Clear233 std::string name() const { return "BM_Clear" + baseName(); }
234 };
235
236 template <class Mode, class Order>
237 struct Insert : Base {
238 using Base::Base;
239
run__anon3e7b95e90111::Insert240 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");
257 }
258 #endif
259 }
260 }
261
262 State.PauseTiming();
263 Data = makeTestingSets(MapSize, Mode(),
264 Order::value == ::Order::Random ? Shuffle::Keys
265 : Shuffle::None,
266 1000);
267 State.ResumeTiming();
268 }
269 }
270
name__anon3e7b95e90111::Insert271 std::string name() const {
272 return "BM_Insert" + baseName() + Mode::name() + Order::name();
273 }
274 };
275
276 template <class Mode, class Hint>
277 struct InsertHint : Base {
278 using Base::Base;
279
280 template < ::Hint hint>
281 typename std::enable_if<hint == ::Hint::Correct>::type
run__anon3e7b95e90111::InsertHint282 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");
299 }
300 #endif
301 ++H;
302 }
303 }
304
305 State.PauseTiming();
306 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
307 State.ResumeTiming();
308 }
309 }
310
311 template < ::Hint hint>
312 typename std::enable_if<hint != ::Hint::Correct>::type
run__anon3e7b95e90111::InsertHint313 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");
334 }
335 #endif
336 }
337 }
338
339 State.PauseTiming();
340 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
341 State.ResumeTiming();
342 }
343 }
344
run__anon3e7b95e90111::InsertHint345 void run(benchmark::State& State) const {
346 static constexpr auto h = Hint();
347 run<h>(State);
348 }
349
name__anon3e7b95e90111::InsertHint350 std::string name() const {
351 return "BM_InsertHint" + baseName() + Mode::name() + Hint::name();
352 }
353 };
354
355 template <class Mode, class Order>
356 struct InsertAssign : Base {
357 using Base::Base;
358
run__anon3e7b95e90111::InsertAssign359 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");
376 }
377 #endif
378 }
379 }
380
381 State.PauseTiming();
382 Data = makeTestingSets(MapSize, Mode(),
383 Order::value == ::Order::Random ? Shuffle::Keys
384 : Shuffle::None,
385 1000);
386 State.ResumeTiming();
387 }
388 }
389
name__anon3e7b95e90111::InsertAssign390 std::string name() const {
391 return "BM_InsertAssign" + baseName() + Mode::name() + Order::name();
392 }
393 };
394
395 template <class Mode, class Hint>
396 struct InsertAssignHint : Base {
397 using Base::Base;
398
399 template < ::Hint hint>
400 typename std::enable_if<hint == ::Hint::Correct>::type
run__anon3e7b95e90111::InsertAssignHint401 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");
418 }
419 #endif
420 ++H;
421 }
422 }
423
424 State.PauseTiming();
425 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
426 State.ResumeTiming();
427 }
428 }
429
430 template < ::Hint hint>
431 typename std::enable_if<hint != ::Hint::Correct>::type
run__anon3e7b95e90111::InsertAssignHint432 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");
453 }
454 #endif
455 }
456 }
457
458 State.PauseTiming();
459 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
460 State.ResumeTiming();
461 }
462 }
463
run__anon3e7b95e90111::InsertAssignHint464 void run(benchmark::State& State) const {
465 static constexpr auto h = Hint();
466 run<h>(State);
467 }
468
name__anon3e7b95e90111::InsertAssignHint469 std::string name() const {
470 return "BM_InsertAssignHint" + baseName() + Mode::name() + Hint::name();
471 }
472 };
473
474 template <class Mode, class Order>
475 struct Emplace : Base {
476 using Base::Base;
477
run__anon3e7b95e90111::Emplace478 void run(benchmark::State& State) const {
479
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");
496 }
497 #endif
498 }
499 }
500
501 State.PauseTiming();
502 Data = makeTestingSets(MapSize, Mode(),
503 Order::value == ::Order::Random ? Shuffle::Keys
504 : Shuffle::None,
505 1000);
506 State.ResumeTiming();
507 }
508 }
509
name__anon3e7b95e90111::Emplace510 std::string name() const {
511 return "BM_Emplace" + baseName() + Mode::name() + Order::name();
512 }
513 };
514
515 template <class Mode, class Hint>
516 struct EmplaceHint : Base {
517 using Base::Base;
518
519 template < ::Hint hint>
520 typename std::enable_if<hint == ::Hint::Correct>::type
run__anon3e7b95e90111::EmplaceHint521 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");
538 }
539 #endif
540 ++H;
541 }
542 }
543
544 State.PauseTiming();
545 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
546 State.ResumeTiming();
547 }
548 }
549
550 template < ::Hint hint>
551 typename std::enable_if<hint != ::Hint::Correct>::type
run__anon3e7b95e90111::EmplaceHint552 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");
573 }
574 #endif
575 }
576 }
577
578 State.PauseTiming();
579 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
580 State.ResumeTiming();
581 }
582 }
583
run__anon3e7b95e90111::EmplaceHint584 void run(benchmark::State& State) const {
585 static constexpr auto h = Hint();
586 run<h>(State);
587 }
588
name__anon3e7b95e90111::EmplaceHint589 std::string name() const {
590 return "BM_EmplaceHint" + baseName() + Mode::name() + Hint::name();
591 }
592 };
593
594 template <class Mode, class Order>
595 struct TryEmplace : Base {
596 using Base::Base;
597
run__anon3e7b95e90111::TryEmplace598 void run(benchmark::State& State) const {
599
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");
616 }
617 #endif
618 }
619 }
620
621 State.PauseTiming();
622 Data = makeTestingSets(MapSize, Mode(),
623 Order::value == ::Order::Random ? Shuffle::Keys
624 : Shuffle::None,
625 1000);
626 State.ResumeTiming();
627 }
628 }
629
name__anon3e7b95e90111::TryEmplace630 std::string name() const {
631 return "BM_TryEmplace" + baseName() + Mode::name() + Order::name();
632 }
633 };
634
635 template <class Mode, class Hint>
636 struct TryEmplaceHint : Base {
637 using Base::Base;
638
639 template < ::Hint hint>
640 typename std::enable_if<hint == ::Hint::Correct>::type
run__anon3e7b95e90111::TryEmplaceHint641 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");
658 }
659 #endif
660 ++H;
661 }
662 }
663
664 State.PauseTiming();
665 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
666 State.ResumeTiming();
667 }
668 }
669
670 template < ::Hint hint>
671 typename std::enable_if<hint != ::Hint::Correct>::type
run__anon3e7b95e90111::TryEmplaceHint672 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");
693 }
694 #endif
695 }
696 }
697
698 State.PauseTiming();
699 Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
700 State.ResumeTiming();
701 }
702 }
703
run__anon3e7b95e90111::TryEmplaceHint704 void run(benchmark::State& State) const {
705 static constexpr auto h = Hint();
706 run<h>(State);
707 }
708
name__anon3e7b95e90111::TryEmplaceHint709 std::string name() const {
710 return "BM_TryEmplaceHint" + baseName() + Mode::name() + Hint::name();
711 }
712 };
713
714 template <class Mode, class Order>
715 struct Erase : Base {
716 using Base::Base;
717
run__anon3e7b95e90111::Erase718 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");
735 }
736 #endif
737 }
738 }
739
740 State.PauseTiming();
741 Data = makeTestingSets(MapSize, Mode(),
742 Order::value == ::Order::Random ? Shuffle::Keys
743 : Shuffle::None,
744 1000);
745 State.ResumeTiming();
746 }
747 }
748
name__anon3e7b95e90111::Erase749 std::string name() const {
750 return "BM_Erase" + baseName() + Mode::name() + Order::name();
751 }
752 };
753
754 template <class Order>
755 struct EraseIterator : Base {
756 using Base::Base;
757
run__anon3e7b95e90111::EraseIterator758 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));
767 }
768 #ifdef VALIDATE
769 if (!Map.empty())
770 State.SkipWithError("Did not erase the entire map");
771 #endif
772 }
773
774 State.PauseTiming();
775 Data = makeTestingSets(MapSize, Mode::Hit,
776 Order::value == ::Order::Random ? Shuffle::Hints
777 : Shuffle::None,
778 1000);
779 State.ResumeTiming();
780 }
781 }
782
name__anon3e7b95e90111::EraseIterator783 std::string name() const {
784 return "BM_EraseIterator" + baseName() + Order::name();
785 }
786 };
787
788 struct EraseRange : Base {
789 using Base::Base;
790
run__anon3e7b95e90111::EraseRange791 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
802 }
803
804 State.PauseTiming();
805 Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
806 State.ResumeTiming();
807 }
808 }
809
name__anon3e7b95e90111::EraseRange810 std::string name() const { return "BM_EraseRange" + baseName(); }
811 };
812
813 //*******************************************************************|
814 // Lookup |
815 //*******************************************************************|
816
817 template <class Mode, class Order>
818 struct Count : Base {
819 using Base::Base;
820
run__anon3e7b95e90111::Count821 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");
838 }
839 #endif
840 }
841 }
842 }
843
name__anon3e7b95e90111::Count844 std::string name() const {
845 return "BM_Count" + baseName() + Mode::name() + Order::name();
846 }
847 };
848
849 template <class Mode, class Order>
850 struct Find : Base {
851 using Base::Base;
852
run__anon3e7b95e90111::Find853 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");
870 }
871 #endif
872 }
873 }
874 }
875
name__anon3e7b95e90111::Find876 std::string name() const {
877 return "BM_Find" + baseName() + Mode::name() + Order::name();
878 }
879 };
880
881 template <class Mode, class Order>
882 struct EqualRange : Base {
883 using Base::Base;
884
run__anon3e7b95e90111::EqualRange885 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;
902 }
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");
910 }
911 #endif
912 }
913 }
914 }
915
name__anon3e7b95e90111::EqualRange916 std::string name() const {
917 return "BM_EqualRange" + baseName() + Mode::name() + Order::name();
918 }
919 };
920
921 template <class Mode, class Order>
922 struct LowerBound : Base {
923 using Base::Base;
924
run__anon3e7b95e90111::LowerBound925 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");
942 }
943 #endif
944 }
945 }
946 }
947
name__anon3e7b95e90111::LowerBound948 std::string name() const {
949 return "BM_LowerBound" + baseName() + Mode::name() + Order::name();
950 }
951 };
952
953 template <class Mode, class Order>
954 struct UpperBound : Base {
955 using Base::Base;
956
run__anon3e7b95e90111::UpperBound957 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;
974 }
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");
980 }
981 #endif
982 }
983 }
984 }
985
name__anon3e7b95e90111::UpperBound986 std::string name() const {
987 return "BM_UpperBound" + baseName() + Mode::name() + Order::name();
988 }
989 };
990
991 } // namespace
992
main(int argc,char ** argv)993 int main(int argc, char** argv) {
994 benchmark::Initialize(&argc, argv);
995 if (benchmark::ReportUnrecognizedArguments(argc, argv))
996 return 1;
997
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
1003
1004 // Member functions
1005 makeCartesianProductBenchmark<ConstructorDefault>();
1006 makeCartesianProductBenchmark<ConstructorIterator>(MapSize);
1007 makeCartesianProductBenchmark<ConstructorCopy>(MapSize);
1008 makeCartesianProductBenchmark<ConstructorMove>(MapSize);
1009
1010 // Capacity
1011 makeCartesianProductBenchmark<Empty>(MapSize);
1012 makeCartesianProductBenchmark<Size>(MapSize);
1013
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);
1020
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);
1028
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);
1035
1036 benchmark::RunSpecifiedBenchmarks();
1037 }
1038