1*9356374aSAndroid Build Coastguard Worker // Copyright 2018 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #include <stdint.h>
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #include <algorithm>
18*9356374aSAndroid Build Coastguard Worker #include <functional>
19*9356374aSAndroid Build Coastguard Worker #include <map>
20*9356374aSAndroid Build Coastguard Worker #include <numeric>
21*9356374aSAndroid Build Coastguard Worker #include <random>
22*9356374aSAndroid Build Coastguard Worker #include <set>
23*9356374aSAndroid Build Coastguard Worker #include <string>
24*9356374aSAndroid Build Coastguard Worker #include <type_traits>
25*9356374aSAndroid Build Coastguard Worker #include <unordered_map>
26*9356374aSAndroid Build Coastguard Worker #include <unordered_set>
27*9356374aSAndroid Build Coastguard Worker #include <vector>
28*9356374aSAndroid Build Coastguard Worker
29*9356374aSAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
31*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/raw_logging.h"
32*9356374aSAndroid Build Coastguard Worker #include "absl/container/btree_map.h"
33*9356374aSAndroid Build Coastguard Worker #include "absl/container/btree_set.h"
34*9356374aSAndroid Build Coastguard Worker #include "absl/container/btree_test.h"
35*9356374aSAndroid Build Coastguard Worker #include "absl/container/flat_hash_map.h"
36*9356374aSAndroid Build Coastguard Worker #include "absl/container/flat_hash_set.h"
37*9356374aSAndroid Build Coastguard Worker #include "absl/container/internal/hashtable_debug.h"
38*9356374aSAndroid Build Coastguard Worker #include "absl/hash/hash.h"
39*9356374aSAndroid Build Coastguard Worker #include "absl/log/log.h"
40*9356374aSAndroid Build Coastguard Worker #include "absl/memory/memory.h"
41*9356374aSAndroid Build Coastguard Worker #include "absl/random/random.h"
42*9356374aSAndroid Build Coastguard Worker #include "absl/strings/cord.h"
43*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_format.h"
44*9356374aSAndroid Build Coastguard Worker #include "absl/time/time.h"
45*9356374aSAndroid Build Coastguard Worker
46*9356374aSAndroid Build Coastguard Worker namespace absl {
47*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
48*9356374aSAndroid Build Coastguard Worker namespace container_internal {
49*9356374aSAndroid Build Coastguard Worker namespace {
50*9356374aSAndroid Build Coastguard Worker
51*9356374aSAndroid Build Coastguard Worker constexpr size_t kBenchmarkValues = 1 << 20;
52*9356374aSAndroid Build Coastguard Worker
53*9356374aSAndroid Build Coastguard Worker // How many times we add and remove sub-batches in one batch of *AddRem
54*9356374aSAndroid Build Coastguard Worker // benchmarks.
55*9356374aSAndroid Build Coastguard Worker constexpr size_t kAddRemBatchSize = 1 << 2;
56*9356374aSAndroid Build Coastguard Worker
57*9356374aSAndroid Build Coastguard Worker // Generates n values in the range [0, 4 * n].
58*9356374aSAndroid Build Coastguard Worker template <typename V>
GenerateValues(int n)59*9356374aSAndroid Build Coastguard Worker std::vector<V> GenerateValues(int n) {
60*9356374aSAndroid Build Coastguard Worker constexpr int kSeed = 23;
61*9356374aSAndroid Build Coastguard Worker return GenerateValuesWithSeed<V>(n, 4 * n, kSeed);
62*9356374aSAndroid Build Coastguard Worker }
63*9356374aSAndroid Build Coastguard Worker
64*9356374aSAndroid Build Coastguard Worker // Benchmark insertion of values into a container.
65*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_InsertImpl(benchmark::State & state,bool sorted)66*9356374aSAndroid Build Coastguard Worker void BM_InsertImpl(benchmark::State& state, bool sorted) {
67*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
68*9356374aSAndroid Build Coastguard Worker typename KeyOfValue<typename T::key_type, V>::type key_of_value;
69*9356374aSAndroid Build Coastguard Worker
70*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
71*9356374aSAndroid Build Coastguard Worker if (sorted) {
72*9356374aSAndroid Build Coastguard Worker std::sort(values.begin(), values.end());
73*9356374aSAndroid Build Coastguard Worker }
74*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
75*9356374aSAndroid Build Coastguard Worker
76*9356374aSAndroid Build Coastguard Worker // Remove and re-insert 10% of the keys per batch.
77*9356374aSAndroid Build Coastguard Worker const int batch_size = (kBenchmarkValues + 9) / 10;
78*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(batch_size)) {
79*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
80*9356374aSAndroid Build Coastguard Worker const auto i = static_cast<int>(state.iterations());
81*9356374aSAndroid Build Coastguard Worker
82*9356374aSAndroid Build Coastguard Worker for (int j = i; j < i + batch_size; j++) {
83*9356374aSAndroid Build Coastguard Worker int x = j % kBenchmarkValues;
84*9356374aSAndroid Build Coastguard Worker container.erase(key_of_value(values[x]));
85*9356374aSAndroid Build Coastguard Worker }
86*9356374aSAndroid Build Coastguard Worker
87*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
88*9356374aSAndroid Build Coastguard Worker
89*9356374aSAndroid Build Coastguard Worker for (int j = i; j < i + batch_size; j++) {
90*9356374aSAndroid Build Coastguard Worker int x = j % kBenchmarkValues;
91*9356374aSAndroid Build Coastguard Worker container.insert(values[x]);
92*9356374aSAndroid Build Coastguard Worker }
93*9356374aSAndroid Build Coastguard Worker }
94*9356374aSAndroid Build Coastguard Worker }
95*9356374aSAndroid Build Coastguard Worker
96*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_Insert(benchmark::State & state)97*9356374aSAndroid Build Coastguard Worker void BM_Insert(benchmark::State& state) {
98*9356374aSAndroid Build Coastguard Worker BM_InsertImpl<T>(state, false);
99*9356374aSAndroid Build Coastguard Worker }
100*9356374aSAndroid Build Coastguard Worker
101*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_InsertSorted(benchmark::State & state)102*9356374aSAndroid Build Coastguard Worker void BM_InsertSorted(benchmark::State& state) {
103*9356374aSAndroid Build Coastguard Worker BM_InsertImpl<T>(state, true);
104*9356374aSAndroid Build Coastguard Worker }
105*9356374aSAndroid Build Coastguard Worker
106*9356374aSAndroid Build Coastguard Worker // Benchmark inserting the first few elements in a container. In b-tree, this is
107*9356374aSAndroid Build Coastguard Worker // when the root node grows.
108*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_InsertSmall(benchmark::State & state)109*9356374aSAndroid Build Coastguard Worker void BM_InsertSmall(benchmark::State& state) {
110*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
111*9356374aSAndroid Build Coastguard Worker
112*9356374aSAndroid Build Coastguard Worker const int kSize = 8;
113*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kSize);
114*9356374aSAndroid Build Coastguard Worker T container;
115*9356374aSAndroid Build Coastguard Worker
116*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(kSize)) {
117*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < kSize; ++i) {
118*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(container.insert(values[i]));
119*9356374aSAndroid Build Coastguard Worker }
120*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
121*9356374aSAndroid Build Coastguard Worker // Do not measure the time it takes to clear the container.
122*9356374aSAndroid Build Coastguard Worker container.clear();
123*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
124*9356374aSAndroid Build Coastguard Worker }
125*9356374aSAndroid Build Coastguard Worker }
126*9356374aSAndroid Build Coastguard Worker
127*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_LookupImpl(benchmark::State & state,bool sorted)128*9356374aSAndroid Build Coastguard Worker void BM_LookupImpl(benchmark::State& state, bool sorted) {
129*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
130*9356374aSAndroid Build Coastguard Worker typename KeyOfValue<typename T::key_type, V>::type key_of_value;
131*9356374aSAndroid Build Coastguard Worker
132*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
133*9356374aSAndroid Build Coastguard Worker if (sorted) {
134*9356374aSAndroid Build Coastguard Worker std::sort(values.begin(), values.end());
135*9356374aSAndroid Build Coastguard Worker }
136*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
137*9356374aSAndroid Build Coastguard Worker
138*9356374aSAndroid Build Coastguard Worker while (state.KeepRunning()) {
139*9356374aSAndroid Build Coastguard Worker int idx = state.iterations() % kBenchmarkValues;
140*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(container.find(key_of_value(values[idx])));
141*9356374aSAndroid Build Coastguard Worker }
142*9356374aSAndroid Build Coastguard Worker }
143*9356374aSAndroid Build Coastguard Worker
144*9356374aSAndroid Build Coastguard Worker // Benchmark lookup of values in a container.
145*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_Lookup(benchmark::State & state)146*9356374aSAndroid Build Coastguard Worker void BM_Lookup(benchmark::State& state) {
147*9356374aSAndroid Build Coastguard Worker BM_LookupImpl<T>(state, false);
148*9356374aSAndroid Build Coastguard Worker }
149*9356374aSAndroid Build Coastguard Worker
150*9356374aSAndroid Build Coastguard Worker // Benchmark lookup of values in a full container, meaning that values
151*9356374aSAndroid Build Coastguard Worker // are inserted in-order to take advantage of biased insertion, which
152*9356374aSAndroid Build Coastguard Worker // yields a full tree.
153*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_FullLookup(benchmark::State & state)154*9356374aSAndroid Build Coastguard Worker void BM_FullLookup(benchmark::State& state) {
155*9356374aSAndroid Build Coastguard Worker BM_LookupImpl<T>(state, true);
156*9356374aSAndroid Build Coastguard Worker }
157*9356374aSAndroid Build Coastguard Worker
158*9356374aSAndroid Build Coastguard Worker // Benchmark erasing values from a container.
159*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_Erase(benchmark::State & state)160*9356374aSAndroid Build Coastguard Worker void BM_Erase(benchmark::State& state) {
161*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
162*9356374aSAndroid Build Coastguard Worker typename KeyOfValue<typename T::key_type, V>::type key_of_value;
163*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
164*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
165*9356374aSAndroid Build Coastguard Worker
166*9356374aSAndroid Build Coastguard Worker // Remove and re-insert 10% of the keys per batch.
167*9356374aSAndroid Build Coastguard Worker const int batch_size = (kBenchmarkValues + 9) / 10;
168*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(batch_size)) {
169*9356374aSAndroid Build Coastguard Worker const int i = state.iterations();
170*9356374aSAndroid Build Coastguard Worker
171*9356374aSAndroid Build Coastguard Worker for (int j = i; j < i + batch_size; j++) {
172*9356374aSAndroid Build Coastguard Worker int x = j % kBenchmarkValues;
173*9356374aSAndroid Build Coastguard Worker container.erase(key_of_value(values[x]));
174*9356374aSAndroid Build Coastguard Worker }
175*9356374aSAndroid Build Coastguard Worker
176*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
177*9356374aSAndroid Build Coastguard Worker for (int j = i; j < i + batch_size; j++) {
178*9356374aSAndroid Build Coastguard Worker int x = j % kBenchmarkValues;
179*9356374aSAndroid Build Coastguard Worker container.insert(values[x]);
180*9356374aSAndroid Build Coastguard Worker }
181*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
182*9356374aSAndroid Build Coastguard Worker }
183*9356374aSAndroid Build Coastguard Worker }
184*9356374aSAndroid Build Coastguard Worker
185*9356374aSAndroid Build Coastguard Worker // Benchmark erasing multiple values from a container.
186*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_EraseRange(benchmark::State & state)187*9356374aSAndroid Build Coastguard Worker void BM_EraseRange(benchmark::State& state) {
188*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
189*9356374aSAndroid Build Coastguard Worker typename KeyOfValue<typename T::key_type, V>::type key_of_value;
190*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
191*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
192*9356374aSAndroid Build Coastguard Worker
193*9356374aSAndroid Build Coastguard Worker // Remove and re-insert 10% of the keys per batch.
194*9356374aSAndroid Build Coastguard Worker const int batch_size = (kBenchmarkValues + 9) / 10;
195*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(batch_size)) {
196*9356374aSAndroid Build Coastguard Worker const int i = state.iterations();
197*9356374aSAndroid Build Coastguard Worker
198*9356374aSAndroid Build Coastguard Worker const int start_index = i % kBenchmarkValues;
199*9356374aSAndroid Build Coastguard Worker
200*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
201*9356374aSAndroid Build Coastguard Worker {
202*9356374aSAndroid Build Coastguard Worker std::vector<V> removed;
203*9356374aSAndroid Build Coastguard Worker removed.reserve(batch_size);
204*9356374aSAndroid Build Coastguard Worker auto itr = container.find(key_of_value(values[start_index]));
205*9356374aSAndroid Build Coastguard Worker auto start = itr;
206*9356374aSAndroid Build Coastguard Worker for (int j = 0; j < batch_size; j++) {
207*9356374aSAndroid Build Coastguard Worker if (itr == container.end()) {
208*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
209*9356374aSAndroid Build Coastguard Worker container.erase(start, itr);
210*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
211*9356374aSAndroid Build Coastguard Worker itr = container.begin();
212*9356374aSAndroid Build Coastguard Worker start = itr;
213*9356374aSAndroid Build Coastguard Worker }
214*9356374aSAndroid Build Coastguard Worker removed.push_back(*itr++);
215*9356374aSAndroid Build Coastguard Worker }
216*9356374aSAndroid Build Coastguard Worker
217*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
218*9356374aSAndroid Build Coastguard Worker container.erase(start, itr);
219*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
220*9356374aSAndroid Build Coastguard Worker
221*9356374aSAndroid Build Coastguard Worker container.insert(removed.begin(), removed.end());
222*9356374aSAndroid Build Coastguard Worker }
223*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
224*9356374aSAndroid Build Coastguard Worker }
225*9356374aSAndroid Build Coastguard Worker }
226*9356374aSAndroid Build Coastguard Worker
227*9356374aSAndroid Build Coastguard Worker // Predicate that erases every other element. We can't use a lambda because
228*9356374aSAndroid Build Coastguard Worker // C++11 doesn't support generic lambdas.
229*9356374aSAndroid Build Coastguard Worker // TODO(b/207389011): consider adding benchmarks that remove different fractions
230*9356374aSAndroid Build Coastguard Worker // of keys (e.g. 10%, 90%).
231*9356374aSAndroid Build Coastguard Worker struct EraseIfPred {
232*9356374aSAndroid Build Coastguard Worker uint64_t i = 0;
233*9356374aSAndroid Build Coastguard Worker template <typename T>
operator ()absl::container_internal::__anon98250b490111::EraseIfPred234*9356374aSAndroid Build Coastguard Worker bool operator()(const T&) {
235*9356374aSAndroid Build Coastguard Worker return ++i % 2;
236*9356374aSAndroid Build Coastguard Worker }
237*9356374aSAndroid Build Coastguard Worker };
238*9356374aSAndroid Build Coastguard Worker
239*9356374aSAndroid Build Coastguard Worker // Benchmark erasing multiple values from a container with a predicate.
240*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_EraseIf(benchmark::State & state)241*9356374aSAndroid Build Coastguard Worker void BM_EraseIf(benchmark::State& state) {
242*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
243*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
244*9356374aSAndroid Build Coastguard Worker
245*9356374aSAndroid Build Coastguard Worker // Removes half of the keys per batch.
246*9356374aSAndroid Build Coastguard Worker const int batch_size = (kBenchmarkValues + 1) / 2;
247*9356374aSAndroid Build Coastguard Worker EraseIfPred pred;
248*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(batch_size)) {
249*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
250*9356374aSAndroid Build Coastguard Worker {
251*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
252*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
253*9356374aSAndroid Build Coastguard Worker erase_if(container, pred);
254*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(container);
255*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
256*9356374aSAndroid Build Coastguard Worker }
257*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
258*9356374aSAndroid Build Coastguard Worker }
259*9356374aSAndroid Build Coastguard Worker }
260*9356374aSAndroid Build Coastguard Worker
261*9356374aSAndroid Build Coastguard Worker // Benchmark steady-state insert (into first half of range) and remove (from
262*9356374aSAndroid Build Coastguard Worker // second half of range), treating the container approximately like a queue with
263*9356374aSAndroid Build Coastguard Worker // log-time access for all elements. This benchmark does not test the case where
264*9356374aSAndroid Build Coastguard Worker // insertion and removal happen in the same region of the tree. This benchmark
265*9356374aSAndroid Build Coastguard Worker // counts two value constructors.
266*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_QueueAddRem(benchmark::State & state)267*9356374aSAndroid Build Coastguard Worker void BM_QueueAddRem(benchmark::State& state) {
268*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
269*9356374aSAndroid Build Coastguard Worker typename KeyOfValue<typename T::key_type, V>::type key_of_value;
270*9356374aSAndroid Build Coastguard Worker
271*9356374aSAndroid Build Coastguard Worker ABSL_RAW_CHECK(kBenchmarkValues % 2 == 0, "for performance");
272*9356374aSAndroid Build Coastguard Worker
273*9356374aSAndroid Build Coastguard Worker T container;
274*9356374aSAndroid Build Coastguard Worker
275*9356374aSAndroid Build Coastguard Worker const size_t half = kBenchmarkValues / 2;
276*9356374aSAndroid Build Coastguard Worker std::vector<int> remove_keys(half);
277*9356374aSAndroid Build Coastguard Worker std::vector<int> add_keys(half);
278*9356374aSAndroid Build Coastguard Worker
279*9356374aSAndroid Build Coastguard Worker // We want to do the exact same work repeatedly, and the benchmark can end
280*9356374aSAndroid Build Coastguard Worker // after a different number of iterations depending on the speed of the
281*9356374aSAndroid Build Coastguard Worker // individual run so we use a large batch size here and ensure that we do
282*9356374aSAndroid Build Coastguard Worker // deterministic work every batch.
283*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(half * kAddRemBatchSize)) {
284*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
285*9356374aSAndroid Build Coastguard Worker
286*9356374aSAndroid Build Coastguard Worker container.clear();
287*9356374aSAndroid Build Coastguard Worker
288*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < half; ++i) {
289*9356374aSAndroid Build Coastguard Worker remove_keys[i] = i;
290*9356374aSAndroid Build Coastguard Worker add_keys[i] = i;
291*9356374aSAndroid Build Coastguard Worker }
292*9356374aSAndroid Build Coastguard Worker constexpr int kSeed = 5;
293*9356374aSAndroid Build Coastguard Worker std::mt19937_64 rand(kSeed);
294*9356374aSAndroid Build Coastguard Worker std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
295*9356374aSAndroid Build Coastguard Worker std::shuffle(add_keys.begin(), add_keys.end(), rand);
296*9356374aSAndroid Build Coastguard Worker
297*9356374aSAndroid Build Coastguard Worker // Note needs lazy generation of values.
298*9356374aSAndroid Build Coastguard Worker Generator<V> g(kBenchmarkValues * kAddRemBatchSize);
299*9356374aSAndroid Build Coastguard Worker
300*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < half; ++i) {
301*9356374aSAndroid Build Coastguard Worker container.insert(g(add_keys[i]));
302*9356374aSAndroid Build Coastguard Worker container.insert(g(half + remove_keys[i]));
303*9356374aSAndroid Build Coastguard Worker }
304*9356374aSAndroid Build Coastguard Worker
305*9356374aSAndroid Build Coastguard Worker // There are three parts each of size "half":
306*9356374aSAndroid Build Coastguard Worker // 1 is being deleted from [offset - half, offset)
307*9356374aSAndroid Build Coastguard Worker // 2 is standing [offset, offset + half)
308*9356374aSAndroid Build Coastguard Worker // 3 is being inserted into [offset + half, offset + 2 * half)
309*9356374aSAndroid Build Coastguard Worker size_t offset = 0;
310*9356374aSAndroid Build Coastguard Worker
311*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < kAddRemBatchSize; ++i) {
312*9356374aSAndroid Build Coastguard Worker std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
313*9356374aSAndroid Build Coastguard Worker std::shuffle(add_keys.begin(), add_keys.end(), rand);
314*9356374aSAndroid Build Coastguard Worker offset += half;
315*9356374aSAndroid Build Coastguard Worker
316*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
317*9356374aSAndroid Build Coastguard Worker for (size_t idx = 0; idx < half; ++idx) {
318*9356374aSAndroid Build Coastguard Worker container.erase(key_of_value(g(offset - half + remove_keys[idx])));
319*9356374aSAndroid Build Coastguard Worker container.insert(g(offset + half + add_keys[idx]));
320*9356374aSAndroid Build Coastguard Worker }
321*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
322*9356374aSAndroid Build Coastguard Worker }
323*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
324*9356374aSAndroid Build Coastguard Worker }
325*9356374aSAndroid Build Coastguard Worker }
326*9356374aSAndroid Build Coastguard Worker
327*9356374aSAndroid Build Coastguard Worker // Mixed insertion and deletion in the same range using pre-constructed values.
328*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_MixedAddRem(benchmark::State & state)329*9356374aSAndroid Build Coastguard Worker void BM_MixedAddRem(benchmark::State& state) {
330*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
331*9356374aSAndroid Build Coastguard Worker typename KeyOfValue<typename T::key_type, V>::type key_of_value;
332*9356374aSAndroid Build Coastguard Worker
333*9356374aSAndroid Build Coastguard Worker ABSL_RAW_CHECK(kBenchmarkValues % 2 == 0, "for performance");
334*9356374aSAndroid Build Coastguard Worker
335*9356374aSAndroid Build Coastguard Worker T container;
336*9356374aSAndroid Build Coastguard Worker
337*9356374aSAndroid Build Coastguard Worker // Create two random shuffles
338*9356374aSAndroid Build Coastguard Worker std::vector<int> remove_keys(kBenchmarkValues);
339*9356374aSAndroid Build Coastguard Worker std::vector<int> add_keys(kBenchmarkValues);
340*9356374aSAndroid Build Coastguard Worker
341*9356374aSAndroid Build Coastguard Worker // We want to do the exact same work repeatedly, and the benchmark can end
342*9356374aSAndroid Build Coastguard Worker // after a different number of iterations depending on the speed of the
343*9356374aSAndroid Build Coastguard Worker // individual run so we use a large batch size here and ensure that we do
344*9356374aSAndroid Build Coastguard Worker // deterministic work every batch.
345*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(kBenchmarkValues * kAddRemBatchSize)) {
346*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
347*9356374aSAndroid Build Coastguard Worker
348*9356374aSAndroid Build Coastguard Worker container.clear();
349*9356374aSAndroid Build Coastguard Worker
350*9356374aSAndroid Build Coastguard Worker constexpr int kSeed = 7;
351*9356374aSAndroid Build Coastguard Worker std::mt19937_64 rand(kSeed);
352*9356374aSAndroid Build Coastguard Worker
353*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues * 2);
354*9356374aSAndroid Build Coastguard Worker
355*9356374aSAndroid Build Coastguard Worker // Insert the first half of the values (already in random order)
356*9356374aSAndroid Build Coastguard Worker container.insert(values.begin(), values.begin() + kBenchmarkValues);
357*9356374aSAndroid Build Coastguard Worker
358*9356374aSAndroid Build Coastguard Worker // Insert the first half of the values (already in random order)
359*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < kBenchmarkValues; ++i) {
360*9356374aSAndroid Build Coastguard Worker // remove_keys and add_keys will be swapped before each round,
361*9356374aSAndroid Build Coastguard Worker // therefore fill add_keys here w/ the keys being inserted, so
362*9356374aSAndroid Build Coastguard Worker // they'll be the first to be removed.
363*9356374aSAndroid Build Coastguard Worker remove_keys[i] = i + kBenchmarkValues;
364*9356374aSAndroid Build Coastguard Worker add_keys[i] = i;
365*9356374aSAndroid Build Coastguard Worker }
366*9356374aSAndroid Build Coastguard Worker
367*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < kAddRemBatchSize; ++i) {
368*9356374aSAndroid Build Coastguard Worker remove_keys.swap(add_keys);
369*9356374aSAndroid Build Coastguard Worker std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
370*9356374aSAndroid Build Coastguard Worker std::shuffle(add_keys.begin(), add_keys.end(), rand);
371*9356374aSAndroid Build Coastguard Worker
372*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
373*9356374aSAndroid Build Coastguard Worker for (size_t idx = 0; idx < kBenchmarkValues; ++idx) {
374*9356374aSAndroid Build Coastguard Worker container.erase(key_of_value(values[remove_keys[idx]]));
375*9356374aSAndroid Build Coastguard Worker container.insert(values[add_keys[idx]]);
376*9356374aSAndroid Build Coastguard Worker }
377*9356374aSAndroid Build Coastguard Worker state.PauseTiming();
378*9356374aSAndroid Build Coastguard Worker }
379*9356374aSAndroid Build Coastguard Worker state.ResumeTiming();
380*9356374aSAndroid Build Coastguard Worker }
381*9356374aSAndroid Build Coastguard Worker }
382*9356374aSAndroid Build Coastguard Worker
383*9356374aSAndroid Build Coastguard Worker // Insertion at end, removal from the beginning. This benchmark
384*9356374aSAndroid Build Coastguard Worker // counts two value constructors.
385*9356374aSAndroid Build Coastguard Worker // TODO(ezb): we could add a GenerateNext version of generator that could reduce
386*9356374aSAndroid Build Coastguard Worker // noise for string-like types.
387*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_Fifo(benchmark::State & state)388*9356374aSAndroid Build Coastguard Worker void BM_Fifo(benchmark::State& state) {
389*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
390*9356374aSAndroid Build Coastguard Worker
391*9356374aSAndroid Build Coastguard Worker T container;
392*9356374aSAndroid Build Coastguard Worker // Need lazy generation of values as state.max_iterations is large.
393*9356374aSAndroid Build Coastguard Worker Generator<V> g(kBenchmarkValues + state.max_iterations);
394*9356374aSAndroid Build Coastguard Worker
395*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < kBenchmarkValues; i++) {
396*9356374aSAndroid Build Coastguard Worker container.insert(g(i));
397*9356374aSAndroid Build Coastguard Worker }
398*9356374aSAndroid Build Coastguard Worker
399*9356374aSAndroid Build Coastguard Worker while (state.KeepRunning()) {
400*9356374aSAndroid Build Coastguard Worker container.erase(container.begin());
401*9356374aSAndroid Build Coastguard Worker container.insert(container.end(), g(state.iterations() + kBenchmarkValues));
402*9356374aSAndroid Build Coastguard Worker }
403*9356374aSAndroid Build Coastguard Worker }
404*9356374aSAndroid Build Coastguard Worker
405*9356374aSAndroid Build Coastguard Worker // Iteration (forward) through the tree
406*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_FwdIter(benchmark::State & state)407*9356374aSAndroid Build Coastguard Worker void BM_FwdIter(benchmark::State& state) {
408*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
409*9356374aSAndroid Build Coastguard Worker using R = typename T::value_type const*;
410*9356374aSAndroid Build Coastguard Worker
411*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
412*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
413*9356374aSAndroid Build Coastguard Worker
414*9356374aSAndroid Build Coastguard Worker auto iter = container.end();
415*9356374aSAndroid Build Coastguard Worker
416*9356374aSAndroid Build Coastguard Worker R r = nullptr;
417*9356374aSAndroid Build Coastguard Worker
418*9356374aSAndroid Build Coastguard Worker while (state.KeepRunning()) {
419*9356374aSAndroid Build Coastguard Worker if (iter == container.end()) iter = container.begin();
420*9356374aSAndroid Build Coastguard Worker r = &(*iter);
421*9356374aSAndroid Build Coastguard Worker ++iter;
422*9356374aSAndroid Build Coastguard Worker }
423*9356374aSAndroid Build Coastguard Worker
424*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(r);
425*9356374aSAndroid Build Coastguard Worker }
426*9356374aSAndroid Build Coastguard Worker
427*9356374aSAndroid Build Coastguard Worker // Benchmark random range-construction of a container.
428*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_RangeConstructionImpl(benchmark::State & state,bool sorted)429*9356374aSAndroid Build Coastguard Worker void BM_RangeConstructionImpl(benchmark::State& state, bool sorted) {
430*9356374aSAndroid Build Coastguard Worker using V = typename remove_pair_const<typename T::value_type>::type;
431*9356374aSAndroid Build Coastguard Worker
432*9356374aSAndroid Build Coastguard Worker std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
433*9356374aSAndroid Build Coastguard Worker if (sorted) {
434*9356374aSAndroid Build Coastguard Worker std::sort(values.begin(), values.end());
435*9356374aSAndroid Build Coastguard Worker }
436*9356374aSAndroid Build Coastguard Worker {
437*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
438*9356374aSAndroid Build Coastguard Worker }
439*9356374aSAndroid Build Coastguard Worker
440*9356374aSAndroid Build Coastguard Worker while (state.KeepRunning()) {
441*9356374aSAndroid Build Coastguard Worker T container(values.begin(), values.end());
442*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(container);
443*9356374aSAndroid Build Coastguard Worker }
444*9356374aSAndroid Build Coastguard Worker }
445*9356374aSAndroid Build Coastguard Worker
446*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_InsertRangeRandom(benchmark::State & state)447*9356374aSAndroid Build Coastguard Worker void BM_InsertRangeRandom(benchmark::State& state) {
448*9356374aSAndroid Build Coastguard Worker BM_RangeConstructionImpl<T>(state, false);
449*9356374aSAndroid Build Coastguard Worker }
450*9356374aSAndroid Build Coastguard Worker
451*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_InsertRangeSorted(benchmark::State & state)452*9356374aSAndroid Build Coastguard Worker void BM_InsertRangeSorted(benchmark::State& state) {
453*9356374aSAndroid Build Coastguard Worker BM_RangeConstructionImpl<T>(state, true);
454*9356374aSAndroid Build Coastguard Worker }
455*9356374aSAndroid Build Coastguard Worker
456*9356374aSAndroid Build Coastguard Worker #define STL_ORDERED_TYPES(value) \
457*9356374aSAndroid Build Coastguard Worker using stl_set_##value = std::set<value>; \
458*9356374aSAndroid Build Coastguard Worker using stl_map_##value = std::map<value, intptr_t>; \
459*9356374aSAndroid Build Coastguard Worker using stl_multiset_##value = std::multiset<value>; \
460*9356374aSAndroid Build Coastguard Worker using stl_multimap_##value = std::multimap<value, intptr_t>
461*9356374aSAndroid Build Coastguard Worker
462*9356374aSAndroid Build Coastguard Worker using StdString = std::string;
463*9356374aSAndroid Build Coastguard Worker STL_ORDERED_TYPES(int32_t);
464*9356374aSAndroid Build Coastguard Worker STL_ORDERED_TYPES(int64_t);
465*9356374aSAndroid Build Coastguard Worker STL_ORDERED_TYPES(StdString);
466*9356374aSAndroid Build Coastguard Worker STL_ORDERED_TYPES(Cord);
467*9356374aSAndroid Build Coastguard Worker STL_ORDERED_TYPES(Time);
468*9356374aSAndroid Build Coastguard Worker
469*9356374aSAndroid Build Coastguard Worker #define STL_UNORDERED_TYPES(value) \
470*9356374aSAndroid Build Coastguard Worker using stl_unordered_set_##value = std::unordered_set<value>; \
471*9356374aSAndroid Build Coastguard Worker using stl_unordered_map_##value = std::unordered_map<value, intptr_t>; \
472*9356374aSAndroid Build Coastguard Worker using flat_hash_set_##value = flat_hash_set<value>; \
473*9356374aSAndroid Build Coastguard Worker using flat_hash_map_##value = flat_hash_map<value, intptr_t>; \
474*9356374aSAndroid Build Coastguard Worker using stl_unordered_multiset_##value = std::unordered_multiset<value>; \
475*9356374aSAndroid Build Coastguard Worker using stl_unordered_multimap_##value = \
476*9356374aSAndroid Build Coastguard Worker std::unordered_multimap<value, intptr_t>
477*9356374aSAndroid Build Coastguard Worker
478*9356374aSAndroid Build Coastguard Worker #define STL_UNORDERED_TYPES_CUSTOM_HASH(value, hash) \
479*9356374aSAndroid Build Coastguard Worker using stl_unordered_set_##value = std::unordered_set<value, hash>; \
480*9356374aSAndroid Build Coastguard Worker using stl_unordered_map_##value = std::unordered_map<value, intptr_t, hash>; \
481*9356374aSAndroid Build Coastguard Worker using flat_hash_set_##value = flat_hash_set<value, hash>; \
482*9356374aSAndroid Build Coastguard Worker using flat_hash_map_##value = flat_hash_map<value, intptr_t, hash>; \
483*9356374aSAndroid Build Coastguard Worker using stl_unordered_multiset_##value = std::unordered_multiset<value, hash>; \
484*9356374aSAndroid Build Coastguard Worker using stl_unordered_multimap_##value = \
485*9356374aSAndroid Build Coastguard Worker std::unordered_multimap<value, intptr_t, hash>
486*9356374aSAndroid Build Coastguard Worker
487*9356374aSAndroid Build Coastguard Worker STL_UNORDERED_TYPES_CUSTOM_HASH(Cord, absl::Hash<absl::Cord>);
488*9356374aSAndroid Build Coastguard Worker
489*9356374aSAndroid Build Coastguard Worker STL_UNORDERED_TYPES(int32_t);
490*9356374aSAndroid Build Coastguard Worker STL_UNORDERED_TYPES(int64_t);
491*9356374aSAndroid Build Coastguard Worker STL_UNORDERED_TYPES(StdString);
492*9356374aSAndroid Build Coastguard Worker STL_UNORDERED_TYPES_CUSTOM_HASH(Time, absl::Hash<absl::Time>);
493*9356374aSAndroid Build Coastguard Worker
494*9356374aSAndroid Build Coastguard Worker #define BTREE_TYPES(value) \
495*9356374aSAndroid Build Coastguard Worker using btree_256_set_##value = \
496*9356374aSAndroid Build Coastguard Worker btree_set<value, std::less<value>, std::allocator<value>>; \
497*9356374aSAndroid Build Coastguard Worker using btree_256_map_##value = \
498*9356374aSAndroid Build Coastguard Worker btree_map<value, intptr_t, std::less<value>, \
499*9356374aSAndroid Build Coastguard Worker std::allocator<std::pair<const value, intptr_t>>>; \
500*9356374aSAndroid Build Coastguard Worker using btree_256_multiset_##value = \
501*9356374aSAndroid Build Coastguard Worker btree_multiset<value, std::less<value>, std::allocator<value>>; \
502*9356374aSAndroid Build Coastguard Worker using btree_256_multimap_##value = \
503*9356374aSAndroid Build Coastguard Worker btree_multimap<value, intptr_t, std::less<value>, \
504*9356374aSAndroid Build Coastguard Worker std::allocator<std::pair<const value, intptr_t>>>
505*9356374aSAndroid Build Coastguard Worker
506*9356374aSAndroid Build Coastguard Worker BTREE_TYPES(int32_t);
507*9356374aSAndroid Build Coastguard Worker BTREE_TYPES(int64_t);
508*9356374aSAndroid Build Coastguard Worker BTREE_TYPES(StdString);
509*9356374aSAndroid Build Coastguard Worker BTREE_TYPES(Cord);
510*9356374aSAndroid Build Coastguard Worker BTREE_TYPES(Time);
511*9356374aSAndroid Build Coastguard Worker
512*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK4(type, func) \
513*9356374aSAndroid Build Coastguard Worker void BM_##type##_##func(benchmark::State& state) { BM_##func<type>(state); } \
514*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_##type##_##func)
515*9356374aSAndroid Build Coastguard Worker
516*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK3_STL(type) \
517*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, Insert); \
518*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, InsertSorted); \
519*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, InsertSmall); \
520*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, Lookup); \
521*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, FullLookup); \
522*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, Erase); \
523*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, EraseRange); \
524*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, QueueAddRem); \
525*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, MixedAddRem); \
526*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, Fifo); \
527*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, FwdIter); \
528*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, InsertRangeRandom); \
529*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, InsertRangeSorted)
530*9356374aSAndroid Build Coastguard Worker
531*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK3(type) \
532*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK4(type, EraseIf); \
533*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(type)
534*9356374aSAndroid Build Coastguard Worker
535*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type) \
536*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(stl_##type); \
537*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(stl_unordered_##type); \
538*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3(btree_256_##type)
539*9356374aSAndroid Build Coastguard Worker
540*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK2(type) \
541*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type); \
542*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3(flat_hash_##type)
543*9356374aSAndroid Build Coastguard Worker
544*9356374aSAndroid Build Coastguard Worker // Define MULTI_TESTING to see benchmarks for multi-containers also.
545*9356374aSAndroid Build Coastguard Worker //
546*9356374aSAndroid Build Coastguard Worker // You can use --copt=-DMULTI_TESTING.
547*9356374aSAndroid Build Coastguard Worker #ifdef MULTI_TESTING
548*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK(type) \
549*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2(set_##type); \
550*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2(map_##type); \
551*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(multiset_##type); \
552*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(multimap_##type)
553*9356374aSAndroid Build Coastguard Worker #else
554*9356374aSAndroid Build Coastguard Worker #define MY_BENCHMARK(type) \
555*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2(set_##type); \
556*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK2(map_##type)
557*9356374aSAndroid Build Coastguard Worker #endif
558*9356374aSAndroid Build Coastguard Worker
559*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK(int32_t);
560*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK(int64_t);
561*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK(StdString);
562*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK(Cord);
563*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK(Time);
564*9356374aSAndroid Build Coastguard Worker
565*9356374aSAndroid Build Coastguard Worker // Define a type whose size and cost of moving are independently customizable.
566*9356374aSAndroid Build Coastguard Worker // When sizeof(value_type) increases, we expect btree to no longer have as much
567*9356374aSAndroid Build Coastguard Worker // cache-locality advantage over STL. When cost of moving increases, we expect
568*9356374aSAndroid Build Coastguard Worker // btree to actually do more work than STL because it has to move values around
569*9356374aSAndroid Build Coastguard Worker // and STL doesn't have to.
570*9356374aSAndroid Build Coastguard Worker template <int Size, int Copies>
571*9356374aSAndroid Build Coastguard Worker struct BigType {
BigTypeabsl::container_internal::__anon98250b490111::BigType572*9356374aSAndroid Build Coastguard Worker BigType() : BigType(0) {}
BigTypeabsl::container_internal::__anon98250b490111::BigType573*9356374aSAndroid Build Coastguard Worker explicit BigType(int x) { std::iota(values.begin(), values.end(), x); }
574*9356374aSAndroid Build Coastguard Worker
Copyabsl::container_internal::__anon98250b490111::BigType575*9356374aSAndroid Build Coastguard Worker void Copy(const BigType& other) {
576*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < Size && i < Copies; ++i) values[i] = other.values[i];
577*9356374aSAndroid Build Coastguard Worker // If Copies > Size, do extra copies.
578*9356374aSAndroid Build Coastguard Worker for (int i = Size, idx = 0; i < Copies; ++i) {
579*9356374aSAndroid Build Coastguard Worker int64_t tmp = other.values[idx];
580*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(tmp);
581*9356374aSAndroid Build Coastguard Worker idx = idx + 1 == Size ? 0 : idx + 1;
582*9356374aSAndroid Build Coastguard Worker }
583*9356374aSAndroid Build Coastguard Worker }
584*9356374aSAndroid Build Coastguard Worker
BigTypeabsl::container_internal::__anon98250b490111::BigType585*9356374aSAndroid Build Coastguard Worker BigType(const BigType& other) { Copy(other); }
operator =absl::container_internal::__anon98250b490111::BigType586*9356374aSAndroid Build Coastguard Worker BigType& operator=(const BigType& other) {
587*9356374aSAndroid Build Coastguard Worker Copy(other);
588*9356374aSAndroid Build Coastguard Worker return *this;
589*9356374aSAndroid Build Coastguard Worker }
590*9356374aSAndroid Build Coastguard Worker
591*9356374aSAndroid Build Coastguard Worker // Compare only the first Copies elements if Copies is less than Size.
operator <absl::container_internal::__anon98250b490111::BigType592*9356374aSAndroid Build Coastguard Worker bool operator<(const BigType& other) const {
593*9356374aSAndroid Build Coastguard Worker return std::lexicographical_compare(
594*9356374aSAndroid Build Coastguard Worker values.begin(), values.begin() + std::min(Size, Copies),
595*9356374aSAndroid Build Coastguard Worker other.values.begin(), other.values.begin() + std::min(Size, Copies));
596*9356374aSAndroid Build Coastguard Worker }
operator ==absl::container_internal::__anon98250b490111::BigType597*9356374aSAndroid Build Coastguard Worker bool operator==(const BigType& other) const {
598*9356374aSAndroid Build Coastguard Worker return std::equal(values.begin(), values.begin() + std::min(Size, Copies),
599*9356374aSAndroid Build Coastguard Worker other.values.begin());
600*9356374aSAndroid Build Coastguard Worker }
601*9356374aSAndroid Build Coastguard Worker
602*9356374aSAndroid Build Coastguard Worker // Support absl::Hash.
603*9356374aSAndroid Build Coastguard Worker template <typename State>
AbslHashValue(State h,const BigType & b)604*9356374aSAndroid Build Coastguard Worker friend State AbslHashValue(State h, const BigType& b) {
605*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < Size && i < Copies; ++i)
606*9356374aSAndroid Build Coastguard Worker h = State::combine(std::move(h), b.values[i]);
607*9356374aSAndroid Build Coastguard Worker return h;
608*9356374aSAndroid Build Coastguard Worker }
609*9356374aSAndroid Build Coastguard Worker
610*9356374aSAndroid Build Coastguard Worker std::array<int64_t, Size> values;
611*9356374aSAndroid Build Coastguard Worker };
612*9356374aSAndroid Build Coastguard Worker
613*9356374aSAndroid Build Coastguard Worker #define BIG_TYPE_BENCHMARKS(SIZE, COPIES) \
614*9356374aSAndroid Build Coastguard Worker using stl_set_size##SIZE##copies##COPIES = std::set<BigType<SIZE, COPIES>>; \
615*9356374aSAndroid Build Coastguard Worker using stl_map_size##SIZE##copies##COPIES = \
616*9356374aSAndroid Build Coastguard Worker std::map<BigType<SIZE, COPIES>, intptr_t>; \
617*9356374aSAndroid Build Coastguard Worker using stl_multiset_size##SIZE##copies##COPIES = \
618*9356374aSAndroid Build Coastguard Worker std::multiset<BigType<SIZE, COPIES>>; \
619*9356374aSAndroid Build Coastguard Worker using stl_multimap_size##SIZE##copies##COPIES = \
620*9356374aSAndroid Build Coastguard Worker std::multimap<BigType<SIZE, COPIES>, intptr_t>; \
621*9356374aSAndroid Build Coastguard Worker using stl_unordered_set_size##SIZE##copies##COPIES = \
622*9356374aSAndroid Build Coastguard Worker std::unordered_set<BigType<SIZE, COPIES>, \
623*9356374aSAndroid Build Coastguard Worker absl::Hash<BigType<SIZE, COPIES>>>; \
624*9356374aSAndroid Build Coastguard Worker using stl_unordered_map_size##SIZE##copies##COPIES = \
625*9356374aSAndroid Build Coastguard Worker std::unordered_map<BigType<SIZE, COPIES>, intptr_t, \
626*9356374aSAndroid Build Coastguard Worker absl::Hash<BigType<SIZE, COPIES>>>; \
627*9356374aSAndroid Build Coastguard Worker using flat_hash_set_size##SIZE##copies##COPIES = \
628*9356374aSAndroid Build Coastguard Worker flat_hash_set<BigType<SIZE, COPIES>>; \
629*9356374aSAndroid Build Coastguard Worker using flat_hash_map_size##SIZE##copies##COPIES = \
630*9356374aSAndroid Build Coastguard Worker flat_hash_map<BigType<SIZE, COPIES>, intptr_t>; \
631*9356374aSAndroid Build Coastguard Worker using stl_unordered_multiset_size##SIZE##copies##COPIES = \
632*9356374aSAndroid Build Coastguard Worker std::unordered_multiset<BigType<SIZE, COPIES>, \
633*9356374aSAndroid Build Coastguard Worker absl::Hash<BigType<SIZE, COPIES>>>; \
634*9356374aSAndroid Build Coastguard Worker using stl_unordered_multimap_size##SIZE##copies##COPIES = \
635*9356374aSAndroid Build Coastguard Worker std::unordered_multimap<BigType<SIZE, COPIES>, intptr_t, \
636*9356374aSAndroid Build Coastguard Worker absl::Hash<BigType<SIZE, COPIES>>>; \
637*9356374aSAndroid Build Coastguard Worker using btree_256_set_size##SIZE##copies##COPIES = \
638*9356374aSAndroid Build Coastguard Worker btree_set<BigType<SIZE, COPIES>>; \
639*9356374aSAndroid Build Coastguard Worker using btree_256_map_size##SIZE##copies##COPIES = \
640*9356374aSAndroid Build Coastguard Worker btree_map<BigType<SIZE, COPIES>, intptr_t>; \
641*9356374aSAndroid Build Coastguard Worker using btree_256_multiset_size##SIZE##copies##COPIES = \
642*9356374aSAndroid Build Coastguard Worker btree_multiset<BigType<SIZE, COPIES>>; \
643*9356374aSAndroid Build Coastguard Worker using btree_256_multimap_size##SIZE##copies##COPIES = \
644*9356374aSAndroid Build Coastguard Worker btree_multimap<BigType<SIZE, COPIES>, intptr_t>; \
645*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK(size##SIZE##copies##COPIES)
646*9356374aSAndroid Build Coastguard Worker
647*9356374aSAndroid Build Coastguard Worker // Define BIG_TYPE_TESTING to see benchmarks for more big types.
648*9356374aSAndroid Build Coastguard Worker //
649*9356374aSAndroid Build Coastguard Worker // You can use --copt=-DBIG_TYPE_TESTING.
650*9356374aSAndroid Build Coastguard Worker #ifndef NODESIZE_TESTING
651*9356374aSAndroid Build Coastguard Worker #ifdef BIG_TYPE_TESTING
652*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(1, 4);
653*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(4, 1);
654*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(4, 4);
655*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(1, 8);
656*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(8, 1);
657*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(8, 8);
658*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(1, 16);
659*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(16, 1);
660*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(16, 16);
661*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(1, 32);
662*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(32, 1);
663*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(32, 32);
664*9356374aSAndroid Build Coastguard Worker #else
665*9356374aSAndroid Build Coastguard Worker BIG_TYPE_BENCHMARKS(32, 32);
666*9356374aSAndroid Build Coastguard Worker #endif
667*9356374aSAndroid Build Coastguard Worker #endif
668*9356374aSAndroid Build Coastguard Worker
669*9356374aSAndroid Build Coastguard Worker // Benchmark using unique_ptrs to large value types. In order to be able to use
670*9356374aSAndroid Build Coastguard Worker // the same benchmark code as the other types, use a type that holds a
671*9356374aSAndroid Build Coastguard Worker // unique_ptr and has a copy constructor.
672*9356374aSAndroid Build Coastguard Worker template <int Size>
673*9356374aSAndroid Build Coastguard Worker struct BigTypePtr {
BigTypePtrabsl::container_internal::__anon98250b490111::BigTypePtr674*9356374aSAndroid Build Coastguard Worker BigTypePtr() : BigTypePtr(0) {}
BigTypePtrabsl::container_internal::__anon98250b490111::BigTypePtr675*9356374aSAndroid Build Coastguard Worker explicit BigTypePtr(int x) {
676*9356374aSAndroid Build Coastguard Worker ptr = absl::make_unique<BigType<Size, Size>>(x);
677*9356374aSAndroid Build Coastguard Worker }
BigTypePtrabsl::container_internal::__anon98250b490111::BigTypePtr678*9356374aSAndroid Build Coastguard Worker BigTypePtr(const BigTypePtr& other) {
679*9356374aSAndroid Build Coastguard Worker ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
680*9356374aSAndroid Build Coastguard Worker }
681*9356374aSAndroid Build Coastguard Worker BigTypePtr(BigTypePtr&& other) noexcept = default;
operator =absl::container_internal::__anon98250b490111::BigTypePtr682*9356374aSAndroid Build Coastguard Worker BigTypePtr& operator=(const BigTypePtr& other) {
683*9356374aSAndroid Build Coastguard Worker ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
684*9356374aSAndroid Build Coastguard Worker }
685*9356374aSAndroid Build Coastguard Worker BigTypePtr& operator=(BigTypePtr&& other) noexcept = default;
686*9356374aSAndroid Build Coastguard Worker
operator <absl::container_internal::__anon98250b490111::BigTypePtr687*9356374aSAndroid Build Coastguard Worker bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; }
operator ==absl::container_internal::__anon98250b490111::BigTypePtr688*9356374aSAndroid Build Coastguard Worker bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; }
689*9356374aSAndroid Build Coastguard Worker
690*9356374aSAndroid Build Coastguard Worker std::unique_ptr<BigType<Size, Size>> ptr;
691*9356374aSAndroid Build Coastguard Worker };
692*9356374aSAndroid Build Coastguard Worker
693*9356374aSAndroid Build Coastguard Worker template <int Size>
ContainerInfo(const btree_set<BigTypePtr<Size>> & b)694*9356374aSAndroid Build Coastguard Worker double ContainerInfo(const btree_set<BigTypePtr<Size>>& b) {
695*9356374aSAndroid Build Coastguard Worker const double bytes_used =
696*9356374aSAndroid Build Coastguard Worker b.bytes_used() + b.size() * sizeof(BigType<Size, Size>);
697*9356374aSAndroid Build Coastguard Worker const double bytes_per_value = bytes_used / b.size();
698*9356374aSAndroid Build Coastguard Worker BtreeContainerInfoLog(b, bytes_used, bytes_per_value);
699*9356374aSAndroid Build Coastguard Worker return bytes_per_value;
700*9356374aSAndroid Build Coastguard Worker }
701*9356374aSAndroid Build Coastguard Worker template <int Size>
ContainerInfo(const btree_map<int,BigTypePtr<Size>> & b)702*9356374aSAndroid Build Coastguard Worker double ContainerInfo(const btree_map<int, BigTypePtr<Size>>& b) {
703*9356374aSAndroid Build Coastguard Worker const double bytes_used =
704*9356374aSAndroid Build Coastguard Worker b.bytes_used() + b.size() * sizeof(BigType<Size, Size>);
705*9356374aSAndroid Build Coastguard Worker const double bytes_per_value = bytes_used / b.size();
706*9356374aSAndroid Build Coastguard Worker BtreeContainerInfoLog(b, bytes_used, bytes_per_value);
707*9356374aSAndroid Build Coastguard Worker return bytes_per_value;
708*9356374aSAndroid Build Coastguard Worker }
709*9356374aSAndroid Build Coastguard Worker
710*9356374aSAndroid Build Coastguard Worker #define BIG_TYPE_PTR_BENCHMARKS(SIZE) \
711*9356374aSAndroid Build Coastguard Worker using stl_set_size##SIZE##copies##SIZE##ptr = std::set<BigType<SIZE, SIZE>>; \
712*9356374aSAndroid Build Coastguard Worker using stl_map_size##SIZE##copies##SIZE##ptr = \
713*9356374aSAndroid Build Coastguard Worker std::map<int, BigType<SIZE, SIZE>>; \
714*9356374aSAndroid Build Coastguard Worker using stl_unordered_set_size##SIZE##copies##SIZE##ptr = \
715*9356374aSAndroid Build Coastguard Worker std::unordered_set<BigType<SIZE, SIZE>, \
716*9356374aSAndroid Build Coastguard Worker absl::Hash<BigType<SIZE, SIZE>>>; \
717*9356374aSAndroid Build Coastguard Worker using stl_unordered_map_size##SIZE##copies##SIZE##ptr = \
718*9356374aSAndroid Build Coastguard Worker std::unordered_map<int, BigType<SIZE, SIZE>>; \
719*9356374aSAndroid Build Coastguard Worker using flat_hash_set_size##SIZE##copies##SIZE##ptr = \
720*9356374aSAndroid Build Coastguard Worker flat_hash_set<BigType<SIZE, SIZE>>; \
721*9356374aSAndroid Build Coastguard Worker using flat_hash_map_size##SIZE##copies##SIZE##ptr = \
722*9356374aSAndroid Build Coastguard Worker flat_hash_map<int, BigTypePtr<SIZE>>; \
723*9356374aSAndroid Build Coastguard Worker using btree_256_set_size##SIZE##copies##SIZE##ptr = \
724*9356374aSAndroid Build Coastguard Worker btree_set<BigTypePtr<SIZE>>; \
725*9356374aSAndroid Build Coastguard Worker using btree_256_map_size##SIZE##copies##SIZE##ptr = \
726*9356374aSAndroid Build Coastguard Worker btree_map<int, BigTypePtr<SIZE>>; \
727*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(stl_set_size##SIZE##copies##SIZE##ptr); \
728*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(stl_unordered_set_size##SIZE##copies##SIZE##ptr); \
729*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3(flat_hash_set_size##SIZE##copies##SIZE##ptr); \
730*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3(btree_256_set_size##SIZE##copies##SIZE##ptr); \
731*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(stl_map_size##SIZE##copies##SIZE##ptr); \
732*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3_STL(stl_unordered_map_size##SIZE##copies##SIZE##ptr); \
733*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3(flat_hash_map_size##SIZE##copies##SIZE##ptr); \
734*9356374aSAndroid Build Coastguard Worker MY_BENCHMARK3(btree_256_map_size##SIZE##copies##SIZE##ptr)
735*9356374aSAndroid Build Coastguard Worker
736*9356374aSAndroid Build Coastguard Worker BIG_TYPE_PTR_BENCHMARKS(32);
737*9356374aSAndroid Build Coastguard Worker
BM_BtreeSet_IteratorSubtraction(benchmark::State & state)738*9356374aSAndroid Build Coastguard Worker void BM_BtreeSet_IteratorSubtraction(benchmark::State& state) {
739*9356374aSAndroid Build Coastguard Worker absl::InsecureBitGen bitgen;
740*9356374aSAndroid Build Coastguard Worker std::vector<int> vec;
741*9356374aSAndroid Build Coastguard Worker // Randomize the set's insertion order so the nodes aren't all full.
742*9356374aSAndroid Build Coastguard Worker vec.reserve(state.range(0));
743*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < state.range(0); ++i) vec.push_back(i);
744*9356374aSAndroid Build Coastguard Worker absl::c_shuffle(vec, bitgen);
745*9356374aSAndroid Build Coastguard Worker
746*9356374aSAndroid Build Coastguard Worker absl::btree_set<int> set;
747*9356374aSAndroid Build Coastguard Worker for (int i : vec) set.insert(i);
748*9356374aSAndroid Build Coastguard Worker
749*9356374aSAndroid Build Coastguard Worker size_t distance = absl::Uniform(bitgen, 0u, set.size());
750*9356374aSAndroid Build Coastguard Worker while (state.KeepRunningBatch(distance)) {
751*9356374aSAndroid Build Coastguard Worker size_t end = absl::Uniform(bitgen, distance, set.size());
752*9356374aSAndroid Build Coastguard Worker size_t begin = end - distance;
753*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(set.find(static_cast<int>(end)) -
754*9356374aSAndroid Build Coastguard Worker set.find(static_cast<int>(begin)));
755*9356374aSAndroid Build Coastguard Worker distance = absl::Uniform(bitgen, 0u, set.size());
756*9356374aSAndroid Build Coastguard Worker }
757*9356374aSAndroid Build Coastguard Worker }
758*9356374aSAndroid Build Coastguard Worker
759*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_BtreeSet_IteratorSubtraction)->Range(1 << 10, 1 << 20);
760*9356374aSAndroid Build Coastguard Worker
761*9356374aSAndroid Build Coastguard Worker } // namespace
762*9356374aSAndroid Build Coastguard Worker } // namespace container_internal
763*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
764*9356374aSAndroid Build Coastguard Worker } // namespace absl
765