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 //===----------------------------------------------------------------------===//
17 #include "CartesianBenchmarks.h"
18 #include "benchmark/benchmark.h"
19 #include "test_macros.h"
23 enum class HitType
{ Hit
, Miss
};
25 struct AllHitTypes
: EnumValuesAsTuple
<AllHitTypes
, HitType
, 2> {
26 static constexpr const char* Names
[] = {"Hit", "Miss"};
29 enum class AccessPattern
{ Ordered
, Random
};
31 struct AllAccessPattern
32 : EnumValuesAsTuple
<AllAccessPattern
, AccessPattern
, 2> {
33 static constexpr const char* Names
[] = {"Ordered", "Random"};
36 void sortKeysBy(std::vector
<uint64_t>& Keys
, AccessPattern AP
) {
37 if (AP
== AccessPattern::Random
) {
40 std::shuffle(std::begin(Keys
), std::end(Keys
), M
);
45 std::vector
<std::set
<uint64_t> > Sets
;
46 std::vector
<uint64_t> Keys
;
49 TestSets
makeTestingSets(size_t TableSize
, size_t NumTables
, HitType Hit
,
50 AccessPattern Access
) {
54 for (uint64_t I
= 0; I
< TableSize
; ++I
) {
55 R
.Sets
[0].insert(2 * I
);
56 R
.Keys
.push_back(Hit
== HitType::Hit
? 2 * I
: 2 * I
+ 1);
58 R
.Sets
.resize(NumTables
, R
.Sets
[0]);
59 sortKeysBy(R
.Keys
, Access
);
67 Base(size_t T
, size_t N
) : TableSize(T
), NumTables(N
) {}
70 size_t Total
= TableSize
* NumTables
;
71 return Total
< 100 || Total
> 1000000;
74 std::string
baseName() const {
75 return "_TableSize" + std::to_string(TableSize
) + "_NumTables" +
76 std::to_string(NumTables
);
80 template <class Access
>
81 struct Create
: Base
{
84 void run(benchmark::State
& State
) const {
85 std::vector
<uint64_t> Keys(TableSize
);
86 std::iota(Keys
.begin(), Keys
.end(), uint64_t{0});
87 sortKeysBy(Keys
, Access());
89 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
90 std::vector
<std::set
<uint64_t>> Sets(NumTables
);
92 for (auto& Set
: Sets
) {
93 benchmark::DoNotOptimize(Set
.insert(K
));
99 std::string
name() const {
100 return "BM_Create" + Access::name() + baseName();
104 template <class Hit
, class Access
>
108 void run(benchmark::State
& State
) const {
109 auto Data
= makeTestingSets(TableSize
, NumTables
, Hit(), Access());
111 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
112 for (auto K
: Data
.Keys
) {
113 for (auto& Set
: Data
.Sets
) {
114 benchmark::DoNotOptimize(Set
.find(K
));
120 std::string
name() const {
121 return "BM_Find" + Hit::name() + Access::name() + baseName();
125 template <class Hit
, class Access
>
126 struct FindNeEnd
: Base
{
129 void run(benchmark::State
& State
) const {
130 auto Data
= makeTestingSets(TableSize
, NumTables
, Hit(), Access());
132 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
133 for (auto K
: Data
.Keys
) {
134 for (auto& Set
: Data
.Sets
) {
135 benchmark::DoNotOptimize(Set
.find(K
) != Set
.end());
141 std::string
name() const {
142 return "BM_FindNeEnd" + Hit::name() + Access::name() + baseName();
146 template <class Access
>
147 struct InsertHit
: Base
{
150 void run(benchmark::State
& State
) const {
151 auto Data
= makeTestingSets(TableSize
, NumTables
, HitType::Hit
, Access());
153 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
154 for (auto K
: Data
.Keys
) {
155 for (auto& Set
: Data
.Sets
) {
156 benchmark::DoNotOptimize(Set
.insert(K
));
162 std::string
name() const {
163 return "BM_InsertHit" + Access::name() + baseName();
167 template <class Access
>
168 struct InsertMissAndErase
: Base
{
171 void run(benchmark::State
& State
) const {
172 auto Data
= makeTestingSets(TableSize
, NumTables
, HitType::Miss
, Access());
174 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
175 for (auto K
: Data
.Keys
) {
176 for (auto& Set
: Data
.Sets
) {
177 benchmark::DoNotOptimize(Set
.erase(Set
.insert(K
).first
));
183 std::string
name() const {
184 return "BM_InsertMissAndErase" + Access::name() + baseName();
188 struct IterateRangeFor
: Base
{
191 void run(benchmark::State
& State
) const {
192 auto Data
= makeTestingSets(TableSize
, NumTables
, HitType::Miss
,
193 AccessPattern::Ordered
);
195 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
196 for (auto& Set
: Data
.Sets
) {
197 for (auto& V
: Set
) {
198 benchmark::DoNotOptimize(V
);
204 std::string
name() const { return "BM_IterateRangeFor" + baseName(); }
207 struct IterateBeginEnd
: Base
{
210 void run(benchmark::State
& State
) const {
211 auto Data
= makeTestingSets(TableSize
, NumTables
, HitType::Miss
,
212 AccessPattern::Ordered
);
214 while (State
.KeepRunningBatch(TableSize
* NumTables
)) {
215 for (auto& Set
: Data
.Sets
) {
216 for (auto it
= Set
.begin(); it
!= Set
.end(); ++it
) {
217 benchmark::DoNotOptimize(*it
);
223 std::string
name() const { return "BM_IterateBeginEnd" + baseName(); }
228 int main(int argc
, char** argv
) {
229 benchmark::Initialize(&argc
, argv
);
230 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
233 const std::vector
<size_t> TableSize
{1, 10, 100, 1000, 10000, 100000, 1000000};
234 const std::vector
<size_t> NumTables
{1, 10, 100, 1000, 10000, 100000, 1000000};
236 makeCartesianProductBenchmark
<Create
, AllAccessPattern
>(TableSize
, NumTables
);
237 makeCartesianProductBenchmark
<Find
, AllHitTypes
, AllAccessPattern
>(
238 TableSize
, NumTables
);
239 makeCartesianProductBenchmark
<FindNeEnd
, AllHitTypes
, AllAccessPattern
>(
240 TableSize
, NumTables
);
241 makeCartesianProductBenchmark
<InsertHit
, AllAccessPattern
>(
242 TableSize
, NumTables
);
243 makeCartesianProductBenchmark
<InsertMissAndErase
, AllAccessPattern
>(
244 TableSize
, NumTables
);
245 makeCartesianProductBenchmark
<IterateRangeFor
>(TableSize
, NumTables
);
246 makeCartesianProductBenchmark
<IterateBeginEnd
>(TableSize
, NumTables
);
247 benchmark::RunSpecifiedBenchmarks();