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