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 "absl/strings/string_view.h"
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #include <algorithm>
18*9356374aSAndroid Build Coastguard Worker #include <cstddef>
19*9356374aSAndroid Build Coastguard Worker #include <cstdint>
20*9356374aSAndroid Build Coastguard Worker #include <map>
21*9356374aSAndroid Build Coastguard Worker #include <random>
22*9356374aSAndroid Build Coastguard Worker #include <string>
23*9356374aSAndroid Build Coastguard Worker #include <unordered_set>
24*9356374aSAndroid Build Coastguard Worker #include <vector>
25*9356374aSAndroid Build Coastguard Worker
26*9356374aSAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
27*9356374aSAndroid Build Coastguard Worker #include "absl/base/attributes.h"
28*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/raw_logging.h"
29*9356374aSAndroid Build Coastguard Worker #include "absl/base/macros.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_cat.h"
31*9356374aSAndroid Build Coastguard Worker
32*9356374aSAndroid Build Coastguard Worker namespace {
33*9356374aSAndroid Build Coastguard Worker
BM_StringViewFromString(benchmark::State & state)34*9356374aSAndroid Build Coastguard Worker void BM_StringViewFromString(benchmark::State& state) {
35*9356374aSAndroid Build Coastguard Worker std::string s(state.range(0), 'x');
36*9356374aSAndroid Build Coastguard Worker std::string* ps = &s;
37*9356374aSAndroid Build Coastguard Worker struct SV {
38*9356374aSAndroid Build Coastguard Worker SV() = default;
39*9356374aSAndroid Build Coastguard Worker explicit SV(const std::string& s) : sv(s) {}
40*9356374aSAndroid Build Coastguard Worker absl::string_view sv;
41*9356374aSAndroid Build Coastguard Worker } sv;
42*9356374aSAndroid Build Coastguard Worker SV* psv = &sv;
43*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(ps);
44*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(psv);
45*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
46*9356374aSAndroid Build Coastguard Worker new (psv) SV(*ps);
47*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(sv);
48*9356374aSAndroid Build Coastguard Worker }
49*9356374aSAndroid Build Coastguard Worker }
50*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StringViewFromString)->Arg(12)->Arg(128);
51*9356374aSAndroid Build Coastguard Worker
52*9356374aSAndroid Build Coastguard Worker // Provide a forcibly out-of-line wrapper for operator== that can be used in
53*9356374aSAndroid Build Coastguard Worker // benchmarks to measure the impact of inlining.
54*9356374aSAndroid Build Coastguard Worker ABSL_ATTRIBUTE_NOINLINE
NonInlinedEq(absl::string_view a,absl::string_view b)55*9356374aSAndroid Build Coastguard Worker bool NonInlinedEq(absl::string_view a, absl::string_view b) { return a == b; }
56*9356374aSAndroid Build Coastguard Worker
57*9356374aSAndroid Build Coastguard Worker // We use functions that cannot be inlined to perform the comparison loops so
58*9356374aSAndroid Build Coastguard Worker // that inlining of the operator== can't optimize away *everything*.
59*9356374aSAndroid Build Coastguard Worker ABSL_ATTRIBUTE_NOINLINE
DoEqualityComparisons(benchmark::State & state,absl::string_view a,absl::string_view b)60*9356374aSAndroid Build Coastguard Worker void DoEqualityComparisons(benchmark::State& state, absl::string_view a,
61*9356374aSAndroid Build Coastguard Worker absl::string_view b) {
62*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
63*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == b);
64*9356374aSAndroid Build Coastguard Worker }
65*9356374aSAndroid Build Coastguard Worker }
66*9356374aSAndroid Build Coastguard Worker
BM_EqualIdentical(benchmark::State & state)67*9356374aSAndroid Build Coastguard Worker void BM_EqualIdentical(benchmark::State& state) {
68*9356374aSAndroid Build Coastguard Worker std::string x(state.range(0), 'a');
69*9356374aSAndroid Build Coastguard Worker DoEqualityComparisons(state, x, x);
70*9356374aSAndroid Build Coastguard Worker }
71*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_EqualIdentical)->DenseRange(0, 3)->Range(4, 1 << 10);
72*9356374aSAndroid Build Coastguard Worker
BM_EqualSame(benchmark::State & state)73*9356374aSAndroid Build Coastguard Worker void BM_EqualSame(benchmark::State& state) {
74*9356374aSAndroid Build Coastguard Worker std::string x(state.range(0), 'a');
75*9356374aSAndroid Build Coastguard Worker std::string y = x;
76*9356374aSAndroid Build Coastguard Worker DoEqualityComparisons(state, x, y);
77*9356374aSAndroid Build Coastguard Worker }
78*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_EqualSame)
79*9356374aSAndroid Build Coastguard Worker ->DenseRange(0, 10)
80*9356374aSAndroid Build Coastguard Worker ->Arg(20)
81*9356374aSAndroid Build Coastguard Worker ->Arg(40)
82*9356374aSAndroid Build Coastguard Worker ->Arg(70)
83*9356374aSAndroid Build Coastguard Worker ->Arg(110)
84*9356374aSAndroid Build Coastguard Worker ->Range(160, 4096);
85*9356374aSAndroid Build Coastguard Worker
BM_EqualDifferent(benchmark::State & state)86*9356374aSAndroid Build Coastguard Worker void BM_EqualDifferent(benchmark::State& state) {
87*9356374aSAndroid Build Coastguard Worker const int len = state.range(0);
88*9356374aSAndroid Build Coastguard Worker std::string x(len, 'a');
89*9356374aSAndroid Build Coastguard Worker std::string y = x;
90*9356374aSAndroid Build Coastguard Worker if (len > 0) {
91*9356374aSAndroid Build Coastguard Worker y[len - 1] = 'b';
92*9356374aSAndroid Build Coastguard Worker }
93*9356374aSAndroid Build Coastguard Worker DoEqualityComparisons(state, x, y);
94*9356374aSAndroid Build Coastguard Worker }
95*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_EqualDifferent)->DenseRange(0, 3)->Range(4, 1 << 10);
96*9356374aSAndroid Build Coastguard Worker
97*9356374aSAndroid Build Coastguard Worker // This benchmark is intended to check that important simplifications can be
98*9356374aSAndroid Build Coastguard Worker // made with absl::string_view comparisons against constant strings. The idea is
99*9356374aSAndroid Build Coastguard Worker // that if constant strings cause redundant components of the comparison, the
100*9356374aSAndroid Build Coastguard Worker // compiler should detect and eliminate them. Here we use 8 different strings,
101*9356374aSAndroid Build Coastguard Worker // each with the same size. Provided our comparison makes the implementation
102*9356374aSAndroid Build Coastguard Worker // inline-able by the compiler, it should fold all of these away into a single
103*9356374aSAndroid Build Coastguard Worker // size check once per loop iteration.
104*9356374aSAndroid Build Coastguard Worker ABSL_ATTRIBUTE_NOINLINE
DoConstantSizeInlinedEqualityComparisons(benchmark::State & state,absl::string_view a)105*9356374aSAndroid Build Coastguard Worker void DoConstantSizeInlinedEqualityComparisons(benchmark::State& state,
106*9356374aSAndroid Build Coastguard Worker absl::string_view a) {
107*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
108*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "aaa");
109*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "bbb");
110*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "ccc");
111*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "ddd");
112*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "eee");
113*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "fff");
114*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "ggg");
115*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a == "hhh");
116*9356374aSAndroid Build Coastguard Worker }
117*9356374aSAndroid Build Coastguard Worker }
BM_EqualConstantSizeInlined(benchmark::State & state)118*9356374aSAndroid Build Coastguard Worker void BM_EqualConstantSizeInlined(benchmark::State& state) {
119*9356374aSAndroid Build Coastguard Worker std::string x(state.range(0), 'a');
120*9356374aSAndroid Build Coastguard Worker DoConstantSizeInlinedEqualityComparisons(state, x);
121*9356374aSAndroid Build Coastguard Worker }
122*9356374aSAndroid Build Coastguard Worker // We only need to check for size of 3, and <> 3 as this benchmark only has to
123*9356374aSAndroid Build Coastguard Worker // do with size differences.
124*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_EqualConstantSizeInlined)->DenseRange(2, 4);
125*9356374aSAndroid Build Coastguard Worker
126*9356374aSAndroid Build Coastguard Worker // This benchmark exists purely to give context to the above timings: this is
127*9356374aSAndroid Build Coastguard Worker // what they would look like if the compiler is completely unable to simplify
128*9356374aSAndroid Build Coastguard Worker // between two comparisons when they are comparing against constant strings.
129*9356374aSAndroid Build Coastguard Worker ABSL_ATTRIBUTE_NOINLINE
DoConstantSizeNonInlinedEqualityComparisons(benchmark::State & state,absl::string_view a)130*9356374aSAndroid Build Coastguard Worker void DoConstantSizeNonInlinedEqualityComparisons(benchmark::State& state,
131*9356374aSAndroid Build Coastguard Worker absl::string_view a) {
132*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
133*9356374aSAndroid Build Coastguard Worker // Force these out-of-line to compare with the above function.
134*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "aaa"));
135*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "bbb"));
136*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "ccc"));
137*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "ddd"));
138*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "eee"));
139*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "fff"));
140*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "ggg"));
141*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(NonInlinedEq(a, "hhh"));
142*9356374aSAndroid Build Coastguard Worker }
143*9356374aSAndroid Build Coastguard Worker }
144*9356374aSAndroid Build Coastguard Worker
BM_EqualConstantSizeNonInlined(benchmark::State & state)145*9356374aSAndroid Build Coastguard Worker void BM_EqualConstantSizeNonInlined(benchmark::State& state) {
146*9356374aSAndroid Build Coastguard Worker std::string x(state.range(0), 'a');
147*9356374aSAndroid Build Coastguard Worker DoConstantSizeNonInlinedEqualityComparisons(state, x);
148*9356374aSAndroid Build Coastguard Worker }
149*9356374aSAndroid Build Coastguard Worker // We only need to check for size of 3, and <> 3 as this benchmark only has to
150*9356374aSAndroid Build Coastguard Worker // do with size differences.
151*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_EqualConstantSizeNonInlined)->DenseRange(2, 4);
152*9356374aSAndroid Build Coastguard Worker
BM_CompareSame(benchmark::State & state)153*9356374aSAndroid Build Coastguard Worker void BM_CompareSame(benchmark::State& state) {
154*9356374aSAndroid Build Coastguard Worker const int len = state.range(0);
155*9356374aSAndroid Build Coastguard Worker std::string x;
156*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < len; i++) {
157*9356374aSAndroid Build Coastguard Worker x += 'a';
158*9356374aSAndroid Build Coastguard Worker }
159*9356374aSAndroid Build Coastguard Worker std::string y = x;
160*9356374aSAndroid Build Coastguard Worker absl::string_view a = x;
161*9356374aSAndroid Build Coastguard Worker absl::string_view b = y;
162*9356374aSAndroid Build Coastguard Worker
163*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
164*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a);
165*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(b);
166*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a.compare(b));
167*9356374aSAndroid Build Coastguard Worker }
168*9356374aSAndroid Build Coastguard Worker }
169*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_CompareSame)->DenseRange(0, 3)->Range(4, 1 << 10);
170*9356374aSAndroid Build Coastguard Worker
BM_CompareFirstOneLess(benchmark::State & state)171*9356374aSAndroid Build Coastguard Worker void BM_CompareFirstOneLess(benchmark::State& state) {
172*9356374aSAndroid Build Coastguard Worker const int len = state.range(0);
173*9356374aSAndroid Build Coastguard Worker std::string x(len, 'a');
174*9356374aSAndroid Build Coastguard Worker std::string y = x;
175*9356374aSAndroid Build Coastguard Worker y.back() = 'b';
176*9356374aSAndroid Build Coastguard Worker absl::string_view a = x;
177*9356374aSAndroid Build Coastguard Worker absl::string_view b = y;
178*9356374aSAndroid Build Coastguard Worker
179*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
180*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a);
181*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(b);
182*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a.compare(b));
183*9356374aSAndroid Build Coastguard Worker }
184*9356374aSAndroid Build Coastguard Worker }
185*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_CompareFirstOneLess)->DenseRange(1, 3)->Range(4, 1 << 10);
186*9356374aSAndroid Build Coastguard Worker
BM_CompareSecondOneLess(benchmark::State & state)187*9356374aSAndroid Build Coastguard Worker void BM_CompareSecondOneLess(benchmark::State& state) {
188*9356374aSAndroid Build Coastguard Worker const int len = state.range(0);
189*9356374aSAndroid Build Coastguard Worker std::string x(len, 'a');
190*9356374aSAndroid Build Coastguard Worker std::string y = x;
191*9356374aSAndroid Build Coastguard Worker x.back() = 'b';
192*9356374aSAndroid Build Coastguard Worker absl::string_view a = x;
193*9356374aSAndroid Build Coastguard Worker absl::string_view b = y;
194*9356374aSAndroid Build Coastguard Worker
195*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
196*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a);
197*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(b);
198*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(a.compare(b));
199*9356374aSAndroid Build Coastguard Worker }
200*9356374aSAndroid Build Coastguard Worker }
201*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_CompareSecondOneLess)->DenseRange(1, 3)->Range(4, 1 << 10);
202*9356374aSAndroid Build Coastguard Worker
BM_find_string_view_len_one(benchmark::State & state)203*9356374aSAndroid Build Coastguard Worker void BM_find_string_view_len_one(benchmark::State& state) {
204*9356374aSAndroid Build Coastguard Worker std::string haystack(state.range(0), '0');
205*9356374aSAndroid Build Coastguard Worker absl::string_view s(haystack);
206*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
207*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(s.find("x")); // not present; length 1
208*9356374aSAndroid Build Coastguard Worker }
209*9356374aSAndroid Build Coastguard Worker }
210*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20);
211*9356374aSAndroid Build Coastguard Worker
BM_find_string_view_len_two(benchmark::State & state)212*9356374aSAndroid Build Coastguard Worker void BM_find_string_view_len_two(benchmark::State& state) {
213*9356374aSAndroid Build Coastguard Worker std::string haystack(state.range(0), '0');
214*9356374aSAndroid Build Coastguard Worker absl::string_view s(haystack);
215*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
216*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(s.find("xx")); // not present; length 2
217*9356374aSAndroid Build Coastguard Worker }
218*9356374aSAndroid Build Coastguard Worker }
219*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20);
220*9356374aSAndroid Build Coastguard Worker
BM_find_one_char(benchmark::State & state)221*9356374aSAndroid Build Coastguard Worker void BM_find_one_char(benchmark::State& state) {
222*9356374aSAndroid Build Coastguard Worker std::string haystack(state.range(0), '0');
223*9356374aSAndroid Build Coastguard Worker absl::string_view s(haystack);
224*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
225*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(s.find('x')); // not present
226*9356374aSAndroid Build Coastguard Worker }
227*9356374aSAndroid Build Coastguard Worker }
228*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_find_one_char)->Range(1, 1 << 20);
229*9356374aSAndroid Build Coastguard Worker
BM_rfind_one_char(benchmark::State & state)230*9356374aSAndroid Build Coastguard Worker void BM_rfind_one_char(benchmark::State& state) {
231*9356374aSAndroid Build Coastguard Worker std::string haystack(state.range(0), '0');
232*9356374aSAndroid Build Coastguard Worker absl::string_view s(haystack);
233*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
234*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(s.rfind('x')); // not present
235*9356374aSAndroid Build Coastguard Worker }
236*9356374aSAndroid Build Coastguard Worker }
237*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20);
238*9356374aSAndroid Build Coastguard Worker
BM_worst_case_find_first_of(benchmark::State & state,int haystack_len)239*9356374aSAndroid Build Coastguard Worker void BM_worst_case_find_first_of(benchmark::State& state, int haystack_len) {
240*9356374aSAndroid Build Coastguard Worker const int needle_len = state.range(0);
241*9356374aSAndroid Build Coastguard Worker std::string needle;
242*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < needle_len; ++i) {
243*9356374aSAndroid Build Coastguard Worker needle += 'a' + i;
244*9356374aSAndroid Build Coastguard Worker }
245*9356374aSAndroid Build Coastguard Worker std::string haystack(haystack_len, '0'); // 1000 zeros.
246*9356374aSAndroid Build Coastguard Worker
247*9356374aSAndroid Build Coastguard Worker absl::string_view s(haystack);
248*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
249*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(s.find_first_of(needle));
250*9356374aSAndroid Build Coastguard Worker }
251*9356374aSAndroid Build Coastguard Worker }
252*9356374aSAndroid Build Coastguard Worker
BM_find_first_of_short(benchmark::State & state)253*9356374aSAndroid Build Coastguard Worker void BM_find_first_of_short(benchmark::State& state) {
254*9356374aSAndroid Build Coastguard Worker BM_worst_case_find_first_of(state, 10);
255*9356374aSAndroid Build Coastguard Worker }
256*9356374aSAndroid Build Coastguard Worker
BM_find_first_of_medium(benchmark::State & state)257*9356374aSAndroid Build Coastguard Worker void BM_find_first_of_medium(benchmark::State& state) {
258*9356374aSAndroid Build Coastguard Worker BM_worst_case_find_first_of(state, 100);
259*9356374aSAndroid Build Coastguard Worker }
260*9356374aSAndroid Build Coastguard Worker
BM_find_first_of_long(benchmark::State & state)261*9356374aSAndroid Build Coastguard Worker void BM_find_first_of_long(benchmark::State& state) {
262*9356374aSAndroid Build Coastguard Worker BM_worst_case_find_first_of(state, 1000);
263*9356374aSAndroid Build Coastguard Worker }
264*9356374aSAndroid Build Coastguard Worker
265*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_find_first_of_short)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
266*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_find_first_of_medium)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
267*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_find_first_of_long)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
268*9356374aSAndroid Build Coastguard Worker
269*9356374aSAndroid Build Coastguard Worker struct EasyMap : public std::map<absl::string_view, uint64_t> {
EasyMap__anon3b60c6cf0111::EasyMap270*9356374aSAndroid Build Coastguard Worker explicit EasyMap(size_t) {}
271*9356374aSAndroid Build Coastguard Worker };
272*9356374aSAndroid Build Coastguard Worker
273*9356374aSAndroid Build Coastguard Worker // This templated benchmark helper function is intended to stress operator== or
274*9356374aSAndroid Build Coastguard Worker // operator< in a realistic test. It surely isn't entirely realistic, but it's
275*9356374aSAndroid Build Coastguard Worker // a start. The test creates a map of type Map, a template arg, and populates
276*9356374aSAndroid Build Coastguard Worker // it with table_size key/value pairs. Each key has WordsPerKey words. After
277*9356374aSAndroid Build Coastguard Worker // creating the map, a number of lookups are done in random order. Some keys
278*9356374aSAndroid Build Coastguard Worker // are used much more frequently than others in this phase of the test.
279*9356374aSAndroid Build Coastguard Worker template <typename Map, int WordsPerKey>
StringViewMapBenchmark(benchmark::State & state)280*9356374aSAndroid Build Coastguard Worker void StringViewMapBenchmark(benchmark::State& state) {
281*9356374aSAndroid Build Coastguard Worker const int table_size = state.range(0);
282*9356374aSAndroid Build Coastguard Worker const double kFractionOfKeysThatAreHot = 0.2;
283*9356374aSAndroid Build Coastguard Worker const int kNumLookupsOfHotKeys = 20;
284*9356374aSAndroid Build Coastguard Worker const int kNumLookupsOfColdKeys = 1;
285*9356374aSAndroid Build Coastguard Worker const char* words[] = {"the", "quick", "brown", "fox", "jumped",
286*9356374aSAndroid Build Coastguard Worker "over", "the", "lazy", "dog", "and",
287*9356374aSAndroid Build Coastguard Worker "found", "a", "large", "mushroom", "and",
288*9356374aSAndroid Build Coastguard Worker "a", "couple", "crickets", "eating", "pie"};
289*9356374aSAndroid Build Coastguard Worker // Create some keys that consist of words in random order.
290*9356374aSAndroid Build Coastguard Worker std::random_device r;
291*9356374aSAndroid Build Coastguard Worker std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
292*9356374aSAndroid Build Coastguard Worker std::mt19937 rng(seed);
293*9356374aSAndroid Build Coastguard Worker std::vector<std::string> keys(table_size);
294*9356374aSAndroid Build Coastguard Worker std::vector<int> all_indices;
295*9356374aSAndroid Build Coastguard Worker const int kBlockSize = 1 << 12;
296*9356374aSAndroid Build Coastguard Worker std::unordered_set<std::string> t(kBlockSize);
297*9356374aSAndroid Build Coastguard Worker std::uniform_int_distribution<int> uniform(0, ABSL_ARRAYSIZE(words) - 1);
298*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < table_size; i++) {
299*9356374aSAndroid Build Coastguard Worker all_indices.push_back(i);
300*9356374aSAndroid Build Coastguard Worker do {
301*9356374aSAndroid Build Coastguard Worker keys[i].clear();
302*9356374aSAndroid Build Coastguard Worker for (int j = 0; j < WordsPerKey; j++) {
303*9356374aSAndroid Build Coastguard Worker absl::StrAppend(&keys[i], j > 0 ? " " : "", words[uniform(rng)]);
304*9356374aSAndroid Build Coastguard Worker }
305*9356374aSAndroid Build Coastguard Worker } while (!t.insert(keys[i]).second);
306*9356374aSAndroid Build Coastguard Worker }
307*9356374aSAndroid Build Coastguard Worker
308*9356374aSAndroid Build Coastguard Worker // Create a list of strings to lookup: a permutation of the array of
309*9356374aSAndroid Build Coastguard Worker // keys we just created, with repeats. "Hot" keys get repeated more.
310*9356374aSAndroid Build Coastguard Worker std::shuffle(all_indices.begin(), all_indices.end(), rng);
311*9356374aSAndroid Build Coastguard Worker const int num_hot = table_size * kFractionOfKeysThatAreHot;
312*9356374aSAndroid Build Coastguard Worker const int num_cold = table_size - num_hot;
313*9356374aSAndroid Build Coastguard Worker std::vector<int> hot_indices(all_indices.begin(),
314*9356374aSAndroid Build Coastguard Worker all_indices.begin() + num_hot);
315*9356374aSAndroid Build Coastguard Worker std::vector<int> indices;
316*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < kNumLookupsOfColdKeys; i++) {
317*9356374aSAndroid Build Coastguard Worker indices.insert(indices.end(), all_indices.begin(), all_indices.end());
318*9356374aSAndroid Build Coastguard Worker }
319*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < kNumLookupsOfHotKeys - kNumLookupsOfColdKeys; i++) {
320*9356374aSAndroid Build Coastguard Worker indices.insert(indices.end(), hot_indices.begin(), hot_indices.end());
321*9356374aSAndroid Build Coastguard Worker }
322*9356374aSAndroid Build Coastguard Worker std::shuffle(indices.begin(), indices.end(), rng);
323*9356374aSAndroid Build Coastguard Worker ABSL_RAW_CHECK(
324*9356374aSAndroid Build Coastguard Worker num_cold * kNumLookupsOfColdKeys + num_hot * kNumLookupsOfHotKeys ==
325*9356374aSAndroid Build Coastguard Worker indices.size(),
326*9356374aSAndroid Build Coastguard Worker "");
327*9356374aSAndroid Build Coastguard Worker // After constructing the array we probe it with absl::string_views built from
328*9356374aSAndroid Build Coastguard Worker // test_strings. This means operator== won't see equal pointers, so
329*9356374aSAndroid Build Coastguard Worker // it'll have to check for equal lengths and equal characters.
330*9356374aSAndroid Build Coastguard Worker std::vector<std::string> test_strings(indices.size());
331*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < indices.size(); i++) {
332*9356374aSAndroid Build Coastguard Worker test_strings[i] = keys[indices[i]];
333*9356374aSAndroid Build Coastguard Worker }
334*9356374aSAndroid Build Coastguard Worker
335*9356374aSAndroid Build Coastguard Worker // Run the benchmark. It includes map construction but is mostly
336*9356374aSAndroid Build Coastguard Worker // map lookups.
337*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
338*9356374aSAndroid Build Coastguard Worker Map h(table_size);
339*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < table_size; i++) {
340*9356374aSAndroid Build Coastguard Worker h[keys[i]] = i * 2;
341*9356374aSAndroid Build Coastguard Worker }
342*9356374aSAndroid Build Coastguard Worker ABSL_RAW_CHECK(h.size() == table_size, "");
343*9356374aSAndroid Build Coastguard Worker uint64_t sum = 0;
344*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < indices.size(); i++) {
345*9356374aSAndroid Build Coastguard Worker sum += h[test_strings[i]];
346*9356374aSAndroid Build Coastguard Worker }
347*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(sum);
348*9356374aSAndroid Build Coastguard Worker }
349*9356374aSAndroid Build Coastguard Worker }
350*9356374aSAndroid Build Coastguard Worker
BM_StdMap_4(benchmark::State & state)351*9356374aSAndroid Build Coastguard Worker void BM_StdMap_4(benchmark::State& state) {
352*9356374aSAndroid Build Coastguard Worker StringViewMapBenchmark<EasyMap, 4>(state);
353*9356374aSAndroid Build Coastguard Worker }
354*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StdMap_4)->Range(1 << 10, 1 << 16);
355*9356374aSAndroid Build Coastguard Worker
BM_StdMap_8(benchmark::State & state)356*9356374aSAndroid Build Coastguard Worker void BM_StdMap_8(benchmark::State& state) {
357*9356374aSAndroid Build Coastguard Worker StringViewMapBenchmark<EasyMap, 8>(state);
358*9356374aSAndroid Build Coastguard Worker }
359*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StdMap_8)->Range(1 << 10, 1 << 16);
360*9356374aSAndroid Build Coastguard Worker
BM_CopyToStringNative(benchmark::State & state)361*9356374aSAndroid Build Coastguard Worker void BM_CopyToStringNative(benchmark::State& state) {
362*9356374aSAndroid Build Coastguard Worker std::string src(state.range(0), 'x');
363*9356374aSAndroid Build Coastguard Worker absl::string_view sv(src);
364*9356374aSAndroid Build Coastguard Worker std::string dst;
365*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
366*9356374aSAndroid Build Coastguard Worker dst.assign(sv.begin(), sv.end());
367*9356374aSAndroid Build Coastguard Worker }
368*9356374aSAndroid Build Coastguard Worker }
369*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_CopyToStringNative)->Range(1 << 3, 1 << 12);
370*9356374aSAndroid Build Coastguard Worker
BM_AppendToStringNative(benchmark::State & state)371*9356374aSAndroid Build Coastguard Worker void BM_AppendToStringNative(benchmark::State& state) {
372*9356374aSAndroid Build Coastguard Worker std::string src(state.range(0), 'x');
373*9356374aSAndroid Build Coastguard Worker absl::string_view sv(src);
374*9356374aSAndroid Build Coastguard Worker std::string dst;
375*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
376*9356374aSAndroid Build Coastguard Worker dst.clear();
377*9356374aSAndroid Build Coastguard Worker dst.insert(dst.end(), sv.begin(), sv.end());
378*9356374aSAndroid Build Coastguard Worker }
379*9356374aSAndroid Build Coastguard Worker }
380*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_AppendToStringNative)->Range(1 << 3, 1 << 12);
381*9356374aSAndroid Build Coastguard Worker
382*9356374aSAndroid Build Coastguard Worker } // namespace
383