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