blob: 104948739b9726dd4eb03c7237b4ca88c43749d9 [file] [log] [blame]
Samuel Benzaquend8754ba2018-10-23 14:49:27 +00001//===----------------------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <algorithm>
11#include <cstdint>
12#include <memory>
13#include <random>
14#include <set>
15#include <string>
16#include <vector>
17
18#include "CartesianBenchmarks.hpp"
19#include "benchmark/benchmark.h"
20#include "test_macros.h"
21
22namespace {
23
24enum class HitType { Hit, Miss };
25
26struct AllHitTypes : EnumValuesAsTuple<AllHitTypes, HitType, 2> {
27 static constexpr const char* Names[] = {"Hit", "Miss"};
28};
29
30enum class AccessPattern { Ordered, Random };
31
32struct AllAccessPattern
33 : EnumValuesAsTuple<AllAccessPattern, AccessPattern, 2> {
34 static constexpr const char* Names[] = {"Ordered", "Random"};
35};
36
37void sortKeysBy(std::vector<uint64_t>& Keys, AccessPattern AP) {
38 if (AP == AccessPattern::Random) {
39 std::random_device R;
40 std::mt19937 M(R());
41 std::shuffle(std::begin(Keys), std::end(Keys), M);
42 }
43}
44
45struct TestSets {
46 std::vector<std::set<uint64_t> > Sets;
47 std::vector<uint64_t> Keys;
48};
49
50TestSets makeTestingSets(size_t TableSize, size_t NumTables, HitType Hit,
51 AccessPattern Access) {
52 TestSets R;
53 R.Sets.resize(1);
54
55 for (uint64_t I = 0; I < TableSize; ++I) {
56 R.Sets[0].insert(2 * I);
57 R.Keys.push_back(Hit == HitType::Hit ? 2 * I : 2 * I + 1);
58 }
59 R.Sets.resize(NumTables, R.Sets[0]);
60 sortKeysBy(R.Keys, Access);
61
62 return R;
63}
64
65struct Base {
66 size_t TableSize;
67 size_t NumTables;
68 Base(size_t T, size_t N) : TableSize(T), NumTables(N) {}
69
70 bool skip() const {
71 size_t Total = TableSize * NumTables;
72 return Total < 100 || Total > 1000000;
73 }
74
75 std::string baseName() const {
76 return "_TableSize" + std::to_string(TableSize) + "_NumTables" +
77 std::to_string(NumTables);
78 }
79};
80
81template <class Access>
82struct Create : Base {
83 using Base::Base;
84
85 void run(benchmark::State& State) const {
86 std::vector<size_t> Keys(TableSize);
87 std::iota(Keys.begin(), Keys.end(), size_t{0});
88 sortKeysBy(Keys, Access());
89
90 while (State.KeepRunningBatch(TableSize * NumTables)) {
91 std::vector<std::set<size_t>> Sets(NumTables);
92 for (auto K : Keys) {
93 for (auto& Set : Sets) {
94 benchmark::DoNotOptimize(Set.insert(K));
95 }
96 }
97 }
98 }
99
100 std::string name() const {
101 return "BM_Create" + Access::name() + baseName();
102 }
103};
104
105template <class Hit, class Access>
106struct Find : Base {
107 using Base::Base;
108
109 void run(benchmark::State& State) const {
110 auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access());
111
112 while (State.KeepRunningBatch(TableSize * NumTables)) {
113 for (auto K : Data.Keys) {
114 for (auto& Set : Data.Sets) {
115 benchmark::DoNotOptimize(Set.find(K));
116 }
117 }
118 }
119 }
120
121 std::string name() const {
122 return "BM_Find" + Hit::name() + Access::name() + baseName();
123 }
124};
125
126template <class Hit, class Access>
127struct FindNeEnd : Base {
128 using Base::Base;
129
130 void run(benchmark::State& State) const {
131 auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access());
132
133 while (State.KeepRunningBatch(TableSize * NumTables)) {
134 for (auto K : Data.Keys) {
135 for (auto& Set : Data.Sets) {
136 benchmark::DoNotOptimize(Set.find(K) != Set.end());
137 }
138 }
139 }
140 }
141
142 std::string name() const {
143 return "BM_FindNeEnd" + Hit::name() + Access::name() + baseName();
144 }
145};
146
147template <class Access>
148struct InsertHit : Base {
149 using Base::Base;
150
151 void run(benchmark::State& State) const {
152 auto Data = makeTestingSets(TableSize, NumTables, HitType::Hit, Access());
153
154 while (State.KeepRunningBatch(TableSize * NumTables)) {
155 for (auto K : Data.Keys) {
156 for (auto& Set : Data.Sets) {
157 benchmark::DoNotOptimize(Set.insert(K));
158 }
159 }
160 }
161 }
162
163 std::string name() const {
164 return "BM_InsertHit" + Access::name() + baseName();
165 }
166};
167
168template <class Access>
169struct InsertMissAndErase : Base {
170 using Base::Base;
171
172 void run(benchmark::State& State) const {
173 auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss, Access());
174
175 while (State.KeepRunningBatch(TableSize * NumTables)) {
176 for (auto K : Data.Keys) {
177 for (auto& Set : Data.Sets) {
178 benchmark::DoNotOptimize(Set.erase(Set.insert(K).first));
179 }
180 }
181 }
182 }
183
184 std::string name() const {
185 return "BM_InsertMissAndErase" + Access::name() + baseName();
186 }
187};
188
189struct IterateRangeFor : Base {
190 using Base::Base;
191
192 void run(benchmark::State& State) const {
193 auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss,
194 AccessPattern::Ordered);
195
196 while (State.KeepRunningBatch(TableSize * NumTables)) {
197 for (auto& Set : Data.Sets) {
198 for (auto& V : Set) {
199 benchmark::DoNotOptimize(V);
200 }
201 }
202 }
203 }
204
205 std::string name() const { return "BM_IterateRangeFor" + baseName(); }
206};
207
208struct IterateBeginEnd : Base {
209 using Base::Base;
210
211 void run(benchmark::State& State) const {
212 auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss,
213 AccessPattern::Ordered);
214
215 while (State.KeepRunningBatch(TableSize * NumTables)) {
216 for (auto& Set : Data.Sets) {
217 for (auto it = Set.begin(); it != Set.end(); ++it) {
218 benchmark::DoNotOptimize(*it);
219 }
220 }
221 }
222 }
223
224 std::string name() const { return "BM_IterateBeginEnd" + baseName(); }
225};
226
227} // namespace
228
229int main(int argc, char** argv) {
230 benchmark::Initialize(&argc, argv);
231 if (benchmark::ReportUnrecognizedArguments(argc, argv))
232 return 1;
233
234 const std::vector<size_t> TableSize{1, 10, 100, 1000, 10000, 100000, 1000000};
235 const std::vector<size_t> NumTables{1, 10, 100, 1000, 10000, 100000, 1000000};
236
237 makeCartesianProductBenchmark<Create, AllAccessPattern>(TableSize, NumTables);
238 makeCartesianProductBenchmark<Find, AllHitTypes, AllAccessPattern>(
239 TableSize, NumTables);
240 makeCartesianProductBenchmark<FindNeEnd, AllHitTypes, AllAccessPattern>(
241 TableSize, NumTables);
242 makeCartesianProductBenchmark<InsertHit, AllAccessPattern>(
243 TableSize, NumTables);
244 makeCartesianProductBenchmark<InsertMissAndErase, AllAccessPattern>(
245 TableSize, NumTables);
246 makeCartesianProductBenchmark<IterateRangeFor>(TableSize, NumTables);
247 makeCartesianProductBenchmark<IterateBeginEnd>(TableSize, NumTables);
248 benchmark::RunSpecifiedBenchmarks();
249}