1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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.
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"};
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.
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());
88 Base(size_t T
) : MapSize(T
) {}
90 std::string
baseName() const { return "_MapSize=" + std::to_string(MapSize
); }
93 //*******************************************************************|
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
{
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
)) {
115 benchmark::DoNotOptimize(std::map
<uint64_t, int64_t>(Map
.begin(), Map
.end()));
117 std::map
<uint64_t, int64_t> M
{Map
.begin(), Map
.end()};
119 State
.SkipWithError("Map copy not identical");
124 std::string
name() const { return "BM_ConstructorIterator" + baseName(); }
127 struct ConstructorCopy
: 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
)) {
135 std::map
<uint64_t, int64_t> M(Map
);
136 benchmark::DoNotOptimize(M
);
138 std::map
<uint64_t, int64_t> M(Map
);
140 State
.SkipWithError("Map copy not identical");
145 std::string
name() const { return "BM_ConstructorCopy" + baseName(); }
148 struct ConstructorMove
: 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
);
159 Data
= makeTestingSets(MapSize
, Mode::Hit
, Shuffle::None
, 1000);
160 State
.ResumeTiming();
164 std::string
name() const { return "BM_ConstructorMove" + baseName(); }
167 //*******************************************************************|
169 //*******************************************************************|
171 struct Empty
: 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
) {
179 benchmark::DoNotOptimize(Map
.empty());
182 State
.SkipWithError("Map contains an invalid number of elements.");
187 std::string
name() const { return "BM_Empty" + baseName(); }
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
) {
198 benchmark::DoNotOptimize(Map
.size());
200 if (Map
.size() != MapSize
)
201 State
.SkipWithError("Map contains an invalid number of elements.");
206 std::string
name() const { return "BM_Size" + baseName(); }
209 //*******************************************************************|
211 //*******************************************************************|
213 struct Clear
: 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
) {
221 benchmark::DoNotOptimize(Map
);
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
{
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
) {
242 benchmark::DoNotOptimize(Map
.insert(std::make_pair(K
, 1)));
244 bool Inserted
= Map
.insert(std::make_pair(K
, 1)).second
;
245 if (Mode() == ::Mode::Hit
) {
247 State
.SkipWithError("Inserted a duplicate element");
250 State
.SkipWithError("Failed to insert e new element");
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
{
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
) {
278 benchmark::DoNotOptimize(Map
.insert(*H
, std::make_pair(K
, 1)));
280 auto Inserted
= Map
.insert(*H
, std::make_pair(K
, 1));
281 if (Mode() == ::Mode::Hit
) {
283 State
.SkipWithError("Inserted a duplicate element");
285 if (++Inserted
!= *H
)
286 State
.SkipWithError("Failed to insert a new element");
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();
309 benchmark::DoNotOptimize(Map
.insert(Itor
, std::make_pair(K
, 1)));
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");
317 if (Size
+ 1 != Map
.size())
318 State
.SkipWithError("Failed to insert a new element");
325 Data
= makeTestingSets(MapSize
, Mode(), Shuffle::None
, 1000);
326 State
.ResumeTiming();
330 void run(benchmark::State
& State
) const {
331 static constexpr auto h
= Hint();
335 std::string
name() const { return "BM_InsertHint" + baseName() + Mode::name() + Hint::name(); }
338 template <class Mode
, class Order
>
339 struct InsertAssign
: 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
) {
348 benchmark::DoNotOptimize(Map
.insert_or_assign(K
, 1));
350 bool Inserted
= Map
.insert_or_assign(K
, 1).second
;
351 if (Mode() == ::Mode::Hit
) {
353 State
.SkipWithError("Inserted a duplicate element");
356 State
.SkipWithError("Failed to insert e new element");
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
{
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
) {
384 benchmark::DoNotOptimize(Map
.insert_or_assign(*H
, K
, 1));
386 auto Inserted
= Map
.insert_or_assign(*H
, K
, 1);
387 if (Mode() == ::Mode::Hit
) {
389 State
.SkipWithError("Inserted a duplicate element");
391 if (++Inserted
!= *H
)
392 State
.SkipWithError("Failed to insert a new element");
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();
415 benchmark::DoNotOptimize(Map
.insert_or_assign(Itor
, K
, 1));
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");
423 if (Size
+ 1 != Map
.size())
424 State
.SkipWithError("Failed to insert a new element");
431 Data
= makeTestingSets(MapSize
, Mode(), Shuffle::None
, 1000);
432 State
.ResumeTiming();
436 void run(benchmark::State
& State
) const {
437 static constexpr auto h
= Hint();
441 std::string
name() const { return "BM_InsertAssignHint" + baseName() + Mode::name() + Hint::name(); }
444 template <class Mode
, class Order
>
445 struct Emplace
: 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
) {
454 benchmark::DoNotOptimize(Map
.emplace(K
, 1));
456 bool Inserted
= Map
.emplace(K
, 1).second
;
457 if (Mode() == ::Mode::Hit
) {
459 State
.SkipWithError("Emplaced a duplicate element");
462 State
.SkipWithError("Failed to emplace a new element");
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
{
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
) {
490 benchmark::DoNotOptimize(Map
.emplace_hint(*H
, K
, 1));
492 auto Inserted
= Map
.emplace_hint(*H
, K
, 1);
493 if (Mode() == ::Mode::Hit
) {
495 State
.SkipWithError("Emplaced a duplicate element");
497 if (++Inserted
!= *H
)
498 State
.SkipWithError("Failed to emplace a new element");
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();
521 benchmark::DoNotOptimize(Map
.emplace_hint(Itor
, K
, 1));
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");
529 if (Size
+ 1 != Map
.size())
530 State
.SkipWithError("Failed to emplace a new element");
537 Data
= makeTestingSets(MapSize
, Mode(), Shuffle::None
, 1000);
538 State
.ResumeTiming();
542 void run(benchmark::State
& State
) const {
543 static constexpr auto h
= Hint();
547 std::string
name() const { return "BM_EmplaceHint" + baseName() + Mode::name() + Hint::name(); }
550 template <class Mode
, class Order
>
551 struct TryEmplace
: 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
) {
560 benchmark::DoNotOptimize(Map
.try_emplace(K
, 1));
562 bool Inserted
= Map
.try_emplace(K
, 1).second
;
563 if (Mode() == ::Mode::Hit
) {
565 State
.SkipWithError("Emplaced a duplicate element");
568 State
.SkipWithError("Failed to emplace a new element");
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
{
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
) {
596 benchmark::DoNotOptimize(Map
.try_emplace(*H
, K
, 1));
598 auto Inserted
= Map
.try_emplace(*H
, K
, 1);
599 if (Mode() == ::Mode::Hit
) {
601 State
.SkipWithError("Emplaced a duplicate element");
603 if (++Inserted
!= *H
)
604 State
.SkipWithError("Failed to emplace a new element");
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();
627 benchmark::DoNotOptimize(Map
.try_emplace(Itor
, K
, 1));
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");
635 if (Size
+ 1 != Map
.size())
636 State
.SkipWithError("Failed to emplace a new element");
643 Data
= makeTestingSets(MapSize
, Mode(), Shuffle::None
, 1000);
644 State
.ResumeTiming();
648 void run(benchmark::State
& State
) const {
649 static constexpr auto h
= Hint();
653 std::string
name() const { return "BM_TryEmplaceHint" + baseName() + Mode::name() + Hint::name(); }
656 template <class Mode
, class Order
>
657 struct Erase
: 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
) {
666 benchmark::DoNotOptimize(Map
.erase(K
));
668 size_t I
= Map
.erase(K
);
669 if (Mode() == ::Mode::Hit
) {
671 State
.SkipWithError("Did not find the existing element");
674 State
.SkipWithError("Did find the non-existing element");
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
{
693 void run(benchmark::State
& State
) const {
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
));
704 State
.SkipWithError("Did not erase the entire map");
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
{
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
) {
726 benchmark::DoNotOptimize(Map
.erase(Map
.begin(), Map
.end()));
728 Map
.erase(Map
.begin(), Map
.end());
730 State
.SkipWithError("Did not erase the entire map");
735 Data
= makeTestingSets(MapSize
, Mode::Hit
, Shuffle::None
, 1000);
736 State
.ResumeTiming();
740 std::string
name() const { return "BM_EraseRange" + baseName(); }
743 //*******************************************************************|
745 //*******************************************************************|
747 template <class Mode
, class Order
>
748 struct Count
: 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
) {
757 benchmark::DoNotOptimize(Map
.count(K
));
759 size_t I
= Map
.count(K
);
760 if (Mode() == ::Mode::Hit
) {
762 State
.SkipWithError("Did not find the existing element");
765 State
.SkipWithError("Did find the non-existing element");
772 std::string
name() const { return "BM_Count" + baseName() + Mode::name() + Order::name(); }
775 template <class Mode
, class Order
>
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
) {
785 benchmark::DoNotOptimize(Map
.find(K
));
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");
792 if (Itor
!= Map
.end())
793 State
.SkipWithError("Did find the non-existing element");
800 std::string
name() const { return "BM_Find" + baseName() + Mode::name() + Order::name(); }
803 template <class Mode
, class Order
>
804 struct EqualRange
: 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
) {
813 benchmark::DoNotOptimize(Map
.equal_range(K
));
815 auto Range
= Map
.equal_range(K
);
816 if (Mode() == ::Mode::Hit
) {
817 // Adjust validation for the last element.
819 if (Range
.second
== Map
.end() && K
== 2 * MapSize
) {
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");
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");
836 std::string
name() const { return "BM_EqualRange" + baseName() + Mode::name() + Order::name(); }
839 template <class Mode
, class Order
>
840 struct LowerBound
: 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
) {
849 benchmark::DoNotOptimize(Map
.lower_bound(K
));
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");
856 if (Itor
== Map
.end() || Itor
->first
- 1 != K
)
857 State
.SkipWithError("Did find the non-existing element");
864 std::string
name() const { return "BM_LowerBound" + baseName() + Mode::name() + Order::name(); }
867 template <class Mode
, class Order
>
868 struct UpperBound
: 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
) {
877 benchmark::DoNotOptimize(Map
.upper_bound(K
));
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.
883 if (Itor
== Map
.end() && K
== 2 * MapSize
) {
887 if (Itor
== Map
.end() || Itor
->first
- 2 != Key
)
888 State
.SkipWithError("Did not find the existing element");
890 if (Itor
== Map
.end() || Itor
->first
- 1 != K
)
891 State
.SkipWithError("Did find the non-existing element");
898 std::string
name() const { return "BM_UpperBound" + baseName() + Mode::name() + Order::name(); }
903 int main(int argc
, char** argv
) {
904 benchmark::Initialize(&argc
, argv
);
905 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
909 const std::vector
<size_t> MapSize
{10};
911 const std::vector
<size_t> MapSize
{10, 100, 1000, 10000, 100000, 1000000};
915 makeCartesianProductBenchmark
<ConstructorDefault
>();
916 makeCartesianProductBenchmark
<ConstructorIterator
>(MapSize
);
917 makeCartesianProductBenchmark
<ConstructorCopy
>(MapSize
);
918 makeCartesianProductBenchmark
<ConstructorMove
>(MapSize
);
921 makeCartesianProductBenchmark
<Empty
>(MapSize
);
922 makeCartesianProductBenchmark
<Size
>(MapSize
);
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
);
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();