• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef BENCHMARK_CONTAINER_BENCHMARKS_H
11 #define BENCHMARK_CONTAINER_BENCHMARKS_H
12 
13 #include <cassert>
14 #include <iterator>
15 #include <utility>
16 
17 #include "benchmark/benchmark.h"
18 #include "Utilities.h"
19 #include "test_iterators.h"
20 
21 namespace ContainerBenchmarks {
22 
23 template <class Container>
BM_ConstructSize(benchmark::State & st,Container)24 void BM_ConstructSize(benchmark::State& st, Container) {
25   auto size = st.range(0);
26   for (auto _ : st) {
27     Container c(size);
28     DoNotOptimizeData(c);
29   }
30 }
31 
32 template <class Container>
BM_CopyConstruct(benchmark::State & st,Container)33 void BM_CopyConstruct(benchmark::State& st, Container) {
34   auto size = st.range(0);
35   Container c(size);
36   for (auto _ : st) {
37     auto v = c;
38     DoNotOptimizeData(v);
39   }
40 }
41 
42 template <class Container>
BM_Assignment(benchmark::State & st,Container)43 void BM_Assignment(benchmark::State& st, Container) {
44   auto size = st.range(0);
45   Container c1;
46   Container c2(size);
47   for (auto _ : st) {
48     c1 = c2;
49     DoNotOptimizeData(c1);
50     DoNotOptimizeData(c2);
51   }
52 }
53 
54 template <std::size_t... sz, typename Container, typename GenInputs>
BM_AssignInputIterIter(benchmark::State & st,Container c,GenInputs gen)55 void BM_AssignInputIterIter(benchmark::State& st, Container c, GenInputs gen) {
56   auto v = gen(1, sz...);
57   c.resize(st.range(0), v[0]);
58   auto in = gen(st.range(1), sz...);
59   benchmark::DoNotOptimize(&in);
60   benchmark::DoNotOptimize(&c);
61   for (auto _ : st) {
62     c.assign(cpp17_input_iterator(in.begin()), cpp17_input_iterator(in.end()));
63     benchmark::ClobberMemory();
64   }
65 }
66 
67 template <class Container>
BM_ConstructSizeValue(benchmark::State & st,Container,typename Container::value_type const & val)68 void BM_ConstructSizeValue(benchmark::State& st, Container, typename Container::value_type const& val) {
69   const auto size = st.range(0);
70   for (auto _ : st) {
71     Container c(size, val);
72     DoNotOptimizeData(c);
73   }
74 }
75 
76 template <class Container, class GenInputs>
BM_ConstructIterIter(benchmark::State & st,Container,GenInputs gen)77 void BM_ConstructIterIter(benchmark::State& st, Container, GenInputs gen) {
78   auto in          = gen(st.range(0));
79   const auto begin = in.begin();
80   const auto end   = in.end();
81   benchmark::DoNotOptimize(&in);
82   while (st.KeepRunning()) {
83     Container c(begin, end);
84     DoNotOptimizeData(c);
85   }
86 }
87 
88 template <class Container, class GenInputs>
BM_ConstructFromRange(benchmark::State & st,Container,GenInputs gen)89 void BM_ConstructFromRange(benchmark::State& st, Container, GenInputs gen) {
90   auto in = gen(st.range(0));
91   benchmark::DoNotOptimize(&in);
92   while (st.KeepRunning()) {
93     Container c(std::from_range, in);
94     DoNotOptimizeData(c);
95   }
96 }
97 
98 template <class Container>
BM_Pushback_no_grow(benchmark::State & state,Container c)99 void BM_Pushback_no_grow(benchmark::State& state, Container c) {
100   int count = state.range(0);
101   c.reserve(count);
102   while (state.KeepRunningBatch(count)) {
103     c.clear();
104     for (int i = 0; i != count; ++i) {
105       c.push_back(i);
106     }
107     benchmark::DoNotOptimize(c.data());
108   }
109 }
110 
111 template <class Container, class GenInputs>
BM_InsertValue(benchmark::State & st,Container c,GenInputs gen)112 void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) {
113   auto in        = gen(st.range(0));
114   const auto end = in.end();
115   while (st.KeepRunning()) {
116     c.clear();
117     for (auto it = in.begin(); it != end; ++it) {
118       benchmark::DoNotOptimize(&(*c.insert(*it).first));
119     }
120     benchmark::ClobberMemory();
121   }
122 }
123 
124 template <class Container, class GenInputs>
BM_InsertValueRehash(benchmark::State & st,Container c,GenInputs gen)125 void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) {
126   auto in        = gen(st.range(0));
127   const auto end = in.end();
128   while (st.KeepRunning()) {
129     c.clear();
130     c.rehash(16);
131     for (auto it = in.begin(); it != end; ++it) {
132       benchmark::DoNotOptimize(&(*c.insert(*it).first));
133     }
134     benchmark::ClobberMemory();
135   }
136 }
137 
138 template <class Container, class GenInputs>
BM_InsertDuplicate(benchmark::State & st,Container c,GenInputs gen)139 void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) {
140   auto in        = gen(st.range(0));
141   const auto end = in.end();
142   c.insert(in.begin(), in.end());
143   benchmark::DoNotOptimize(&c);
144   benchmark::DoNotOptimize(&in);
145   while (st.KeepRunning()) {
146     for (auto it = in.begin(); it != end; ++it) {
147       benchmark::DoNotOptimize(&(*c.insert(*it).first));
148     }
149     benchmark::ClobberMemory();
150   }
151 }
152 
153 template <class Container, class GenInputs>
BM_EmplaceDuplicate(benchmark::State & st,Container c,GenInputs gen)154 void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) {
155   auto in        = gen(st.range(0));
156   const auto end = in.end();
157   c.insert(in.begin(), in.end());
158   benchmark::DoNotOptimize(&c);
159   benchmark::DoNotOptimize(&in);
160   while (st.KeepRunning()) {
161     for (auto it = in.begin(); it != end; ++it) {
162       benchmark::DoNotOptimize(&(*c.emplace(*it).first));
163     }
164     benchmark::ClobberMemory();
165   }
166 }
167 
168 template <class Container, class GenInputs>
BM_erase_iter_in_middle(benchmark::State & st,Container,GenInputs gen)169 void BM_erase_iter_in_middle(benchmark::State& st, Container, GenInputs gen) {
170   auto in = gen(st.range(0));
171   Container c(in.begin(), in.end());
172   assert(c.size() > 2);
173   for (auto _ : st) {
174     auto mid    = std::next(c.begin(), c.size() / 2);
175     auto tmp    = *mid;
176     auto result = c.erase(mid); // erase an element in the middle
177     benchmark::DoNotOptimize(result);
178     c.push_back(std::move(tmp)); // and then push it back at the end to avoid needing a new container
179   }
180 }
181 
182 template <class Container, class GenInputs>
BM_erase_iter_at_start(benchmark::State & st,Container,GenInputs gen)183 void BM_erase_iter_at_start(benchmark::State& st, Container, GenInputs gen) {
184   auto in = gen(st.range(0));
185   Container c(in.begin(), in.end());
186   assert(c.size() > 2);
187   for (auto _ : st) {
188     auto it     = c.begin();
189     auto tmp    = *it;
190     auto result = c.erase(it); // erase the first element
191     benchmark::DoNotOptimize(result);
192     c.push_back(std::move(tmp)); // and then push it back at the end to avoid needing a new container
193   }
194 }
195 
196 template <class Container, class GenInputs>
BM_Find(benchmark::State & st,Container c,GenInputs gen)197 void BM_Find(benchmark::State& st, Container c, GenInputs gen) {
198   auto in = gen(st.range(0));
199   c.insert(in.begin(), in.end());
200   benchmark::DoNotOptimize(&(*c.begin()));
201   const auto end = in.data() + in.size();
202   while (st.KeepRunning()) {
203     for (auto it = in.data(); it != end; ++it) {
204       benchmark::DoNotOptimize(&(*c.find(*it)));
205     }
206     benchmark::ClobberMemory();
207   }
208 }
209 
210 template <class Container, class GenInputs>
BM_FindRehash(benchmark::State & st,Container c,GenInputs gen)211 void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) {
212   c.rehash(8);
213   auto in = gen(st.range(0));
214   c.insert(in.begin(), in.end());
215   benchmark::DoNotOptimize(&(*c.begin()));
216   const auto end = in.data() + in.size();
217   while (st.KeepRunning()) {
218     for (auto it = in.data(); it != end; ++it) {
219       benchmark::DoNotOptimize(&(*c.find(*it)));
220     }
221     benchmark::ClobberMemory();
222   }
223 }
224 
225 template <class Container, class GenInputs>
BM_Rehash(benchmark::State & st,Container c,GenInputs gen)226 void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) {
227   auto in = gen(st.range(0));
228   c.max_load_factor(3.0);
229   c.insert(in.begin(), in.end());
230   benchmark::DoNotOptimize(c);
231   const auto bucket_count = c.bucket_count();
232   while (st.KeepRunning()) {
233     c.rehash(bucket_count + 1);
234     c.rehash(bucket_count);
235     benchmark::ClobberMemory();
236   }
237 }
238 
239 template <class Container, class GenInputs>
BM_Compare_same_container(benchmark::State & st,Container,GenInputs gen)240 void BM_Compare_same_container(benchmark::State& st, Container, GenInputs gen) {
241   auto in = gen(st.range(0));
242   Container c1(in.begin(), in.end());
243   Container c2 = c1;
244 
245   benchmark::DoNotOptimize(&(*c1.begin()));
246   benchmark::DoNotOptimize(&(*c2.begin()));
247   while (st.KeepRunning()) {
248     bool res = c1 == c2;
249     benchmark::DoNotOptimize(&res);
250     benchmark::ClobberMemory();
251   }
252 }
253 
254 template <class Container, class GenInputs>
BM_Compare_different_containers(benchmark::State & st,Container,GenInputs gen)255 void BM_Compare_different_containers(benchmark::State& st, Container, GenInputs gen) {
256   auto in1 = gen(st.range(0));
257   auto in2 = gen(st.range(0));
258   Container c1(in1.begin(), in1.end());
259   Container c2(in2.begin(), in2.end());
260 
261   benchmark::DoNotOptimize(&(*c1.begin()));
262   benchmark::DoNotOptimize(&(*c2.begin()));
263   while (st.KeepRunning()) {
264     bool res = c1 == c2;
265     benchmark::DoNotOptimize(&res);
266     benchmark::ClobberMemory();
267   }
268 }
269 
270 } // namespace ContainerBenchmarks
271 
272 #endif // BENCHMARK_CONTAINER_BENCHMARKS_H
273