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 <array>
16*9356374aSAndroid Build Coastguard Worker #include <cstdint>
17*9356374aSAndroid Build Coastguard Worker #include <cstdio>
18*9356374aSAndroid Build Coastguard Worker #include <cstdlib>
19*9356374aSAndroid Build Coastguard Worker #include <cstring>
20*9356374aSAndroid Build Coastguard Worker #include <string>
21*9356374aSAndroid Build Coastguard Worker #include <tuple>
22*9356374aSAndroid Build Coastguard Worker #include <utility>
23*9356374aSAndroid Build Coastguard Worker
24*9356374aSAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
25*9356374aSAndroid Build Coastguard Worker #include "absl/random/log_uniform_int_distribution.h"
26*9356374aSAndroid Build Coastguard Worker #include "absl/random/random.h"
27*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_cat.h"
28*9356374aSAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
29*9356374aSAndroid Build Coastguard Worker #include "absl/strings/substitute.h"
30*9356374aSAndroid Build Coastguard Worker
31*9356374aSAndroid Build Coastguard Worker namespace {
32*9356374aSAndroid Build Coastguard Worker
33*9356374aSAndroid Build Coastguard Worker const char kStringOne[] = "Once Upon A Time, ";
34*9356374aSAndroid Build Coastguard Worker const char kStringTwo[] = "There was a string benchmark";
35*9356374aSAndroid Build Coastguard Worker
36*9356374aSAndroid Build Coastguard Worker // We want to include negative numbers in the benchmark, so this function
37*9356374aSAndroid Build Coastguard Worker // is used to count 0, 1, -1, 2, -2, 3, -3, ...
IncrementAlternatingSign(int i)38*9356374aSAndroid Build Coastguard Worker inline int IncrementAlternatingSign(int i) {
39*9356374aSAndroid Build Coastguard Worker return i > 0 ? -i : 1 - i;
40*9356374aSAndroid Build Coastguard Worker }
41*9356374aSAndroid Build Coastguard Worker
BM_Sum_By_StrCat(benchmark::State & state)42*9356374aSAndroid Build Coastguard Worker void BM_Sum_By_StrCat(benchmark::State& state) {
43*9356374aSAndroid Build Coastguard Worker int i = 0;
44*9356374aSAndroid Build Coastguard Worker char foo[100];
45*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
46*9356374aSAndroid Build Coastguard Worker // NOLINTNEXTLINE(runtime/printf)
47*9356374aSAndroid Build Coastguard Worker strcpy(foo, absl::StrCat(kStringOne, i, kStringTwo, i * 65536ULL).c_str());
48*9356374aSAndroid Build Coastguard Worker int sum = 0;
49*9356374aSAndroid Build Coastguard Worker for (char* f = &foo[0]; *f != 0; ++f) {
50*9356374aSAndroid Build Coastguard Worker sum += *f;
51*9356374aSAndroid Build Coastguard Worker }
52*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(sum);
53*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
54*9356374aSAndroid Build Coastguard Worker }
55*9356374aSAndroid Build Coastguard Worker }
56*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_Sum_By_StrCat);
57*9356374aSAndroid Build Coastguard Worker
BM_StrCat_By_snprintf(benchmark::State & state)58*9356374aSAndroid Build Coastguard Worker void BM_StrCat_By_snprintf(benchmark::State& state) {
59*9356374aSAndroid Build Coastguard Worker int i = 0;
60*9356374aSAndroid Build Coastguard Worker char on_stack[1000];
61*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
62*9356374aSAndroid Build Coastguard Worker snprintf(on_stack, sizeof(on_stack), "%s %s:%d", kStringOne, kStringTwo, i);
63*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
64*9356374aSAndroid Build Coastguard Worker }
65*9356374aSAndroid Build Coastguard Worker }
66*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrCat_By_snprintf);
67*9356374aSAndroid Build Coastguard Worker
BM_StrCat_By_Strings(benchmark::State & state)68*9356374aSAndroid Build Coastguard Worker void BM_StrCat_By_Strings(benchmark::State& state) {
69*9356374aSAndroid Build Coastguard Worker int i = 0;
70*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
71*9356374aSAndroid Build Coastguard Worker std::string result =
72*9356374aSAndroid Build Coastguard Worker std::string(kStringOne) + " " + kStringTwo + ":" + absl::StrCat(i);
73*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
74*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
75*9356374aSAndroid Build Coastguard Worker }
76*9356374aSAndroid Build Coastguard Worker }
77*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrCat_By_Strings);
78*9356374aSAndroid Build Coastguard Worker
BM_StrCat_By_StringOpPlus(benchmark::State & state)79*9356374aSAndroid Build Coastguard Worker void BM_StrCat_By_StringOpPlus(benchmark::State& state) {
80*9356374aSAndroid Build Coastguard Worker int i = 0;
81*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
82*9356374aSAndroid Build Coastguard Worker std::string result = kStringOne;
83*9356374aSAndroid Build Coastguard Worker result += " ";
84*9356374aSAndroid Build Coastguard Worker result += kStringTwo;
85*9356374aSAndroid Build Coastguard Worker result += ":";
86*9356374aSAndroid Build Coastguard Worker result += absl::StrCat(i);
87*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
88*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
89*9356374aSAndroid Build Coastguard Worker }
90*9356374aSAndroid Build Coastguard Worker }
91*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrCat_By_StringOpPlus);
92*9356374aSAndroid Build Coastguard Worker
BM_StrCat_By_StrCat(benchmark::State & state)93*9356374aSAndroid Build Coastguard Worker void BM_StrCat_By_StrCat(benchmark::State& state) {
94*9356374aSAndroid Build Coastguard Worker int i = 0;
95*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
96*9356374aSAndroid Build Coastguard Worker std::string result = absl::StrCat(kStringOne, " ", kStringTwo, ":", i);
97*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
98*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
99*9356374aSAndroid Build Coastguard Worker }
100*9356374aSAndroid Build Coastguard Worker }
101*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrCat_By_StrCat);
102*9356374aSAndroid Build Coastguard Worker
BM_HexCat_By_StrCat(benchmark::State & state)103*9356374aSAndroid Build Coastguard Worker void BM_HexCat_By_StrCat(benchmark::State& state) {
104*9356374aSAndroid Build Coastguard Worker int i = 0;
105*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
106*9356374aSAndroid Build Coastguard Worker std::string result =
107*9356374aSAndroid Build Coastguard Worker absl::StrCat(kStringOne, " ", absl::Hex(int64_t{i} + 0x10000000));
108*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
109*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
110*9356374aSAndroid Build Coastguard Worker }
111*9356374aSAndroid Build Coastguard Worker }
112*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_HexCat_By_StrCat);
113*9356374aSAndroid Build Coastguard Worker
BM_HexCat_By_Substitute(benchmark::State & state)114*9356374aSAndroid Build Coastguard Worker void BM_HexCat_By_Substitute(benchmark::State& state) {
115*9356374aSAndroid Build Coastguard Worker int i = 0;
116*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
117*9356374aSAndroid Build Coastguard Worker std::string result = absl::Substitute(
118*9356374aSAndroid Build Coastguard Worker "$0 $1", kStringOne, reinterpret_cast<void*>(int64_t{i} + 0x10000000));
119*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
120*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
121*9356374aSAndroid Build Coastguard Worker }
122*9356374aSAndroid Build Coastguard Worker }
123*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_HexCat_By_Substitute);
124*9356374aSAndroid Build Coastguard Worker
BM_FloatToString_By_StrCat(benchmark::State & state)125*9356374aSAndroid Build Coastguard Worker void BM_FloatToString_By_StrCat(benchmark::State& state) {
126*9356374aSAndroid Build Coastguard Worker int i = 0;
127*9356374aSAndroid Build Coastguard Worker float foo = 0.0f;
128*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
129*9356374aSAndroid Build Coastguard Worker std::string result = absl::StrCat(foo += 1.001f, " != ", int64_t{i});
130*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
131*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
132*9356374aSAndroid Build Coastguard Worker }
133*9356374aSAndroid Build Coastguard Worker }
134*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_FloatToString_By_StrCat);
135*9356374aSAndroid Build Coastguard Worker
BM_DoubleToString_By_SixDigits(benchmark::State & state)136*9356374aSAndroid Build Coastguard Worker void BM_DoubleToString_By_SixDigits(benchmark::State& state) {
137*9356374aSAndroid Build Coastguard Worker int i = 0;
138*9356374aSAndroid Build Coastguard Worker double foo = 0.0;
139*9356374aSAndroid Build Coastguard Worker for (auto _ : state) {
140*9356374aSAndroid Build Coastguard Worker std::string result =
141*9356374aSAndroid Build Coastguard Worker absl::StrCat(absl::SixDigits(foo += 1.001), " != ", int64_t{i});
142*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
143*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
144*9356374aSAndroid Build Coastguard Worker }
145*9356374aSAndroid Build Coastguard Worker }
146*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_DoubleToString_By_SixDigits);
147*9356374aSAndroid Build Coastguard Worker
148*9356374aSAndroid Build Coastguard Worker template <typename Table, size_t... Index>
BM_StrAppendImpl(benchmark::State & state,Table table,size_t total_bytes,std::index_sequence<Index...>)149*9356374aSAndroid Build Coastguard Worker void BM_StrAppendImpl(benchmark::State& state, Table table, size_t total_bytes,
150*9356374aSAndroid Build Coastguard Worker std::index_sequence<Index...>) {
151*9356374aSAndroid Build Coastguard Worker for (auto s : state) {
152*9356374aSAndroid Build Coastguard Worker const size_t table_size = table.size();
153*9356374aSAndroid Build Coastguard Worker size_t i = 0;
154*9356374aSAndroid Build Coastguard Worker std::string result;
155*9356374aSAndroid Build Coastguard Worker while (result.size() < total_bytes) {
156*9356374aSAndroid Build Coastguard Worker absl::StrAppend(&result, std::get<Index>(table[i])...);
157*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
158*9356374aSAndroid Build Coastguard Worker ++i;
159*9356374aSAndroid Build Coastguard Worker i -= i >= table_size ? table_size : 0;
160*9356374aSAndroid Build Coastguard Worker }
161*9356374aSAndroid Build Coastguard Worker }
162*9356374aSAndroid Build Coastguard Worker }
163*9356374aSAndroid Build Coastguard Worker
164*9356374aSAndroid Build Coastguard Worker template <typename Array>
BM_StrAppend(benchmark::State & state,Array && table)165*9356374aSAndroid Build Coastguard Worker void BM_StrAppend(benchmark::State& state, Array&& table) {
166*9356374aSAndroid Build Coastguard Worker const size_t total_bytes = state.range(0);
167*9356374aSAndroid Build Coastguard Worker const int chunks_at_a_time = state.range(1);
168*9356374aSAndroid Build Coastguard Worker
169*9356374aSAndroid Build Coastguard Worker switch (chunks_at_a_time) {
170*9356374aSAndroid Build Coastguard Worker case 1:
171*9356374aSAndroid Build Coastguard Worker return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
172*9356374aSAndroid Build Coastguard Worker std::make_index_sequence<1>());
173*9356374aSAndroid Build Coastguard Worker case 2:
174*9356374aSAndroid Build Coastguard Worker return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
175*9356374aSAndroid Build Coastguard Worker std::make_index_sequence<2>());
176*9356374aSAndroid Build Coastguard Worker case 4:
177*9356374aSAndroid Build Coastguard Worker return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
178*9356374aSAndroid Build Coastguard Worker std::make_index_sequence<4>());
179*9356374aSAndroid Build Coastguard Worker case 8:
180*9356374aSAndroid Build Coastguard Worker return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
181*9356374aSAndroid Build Coastguard Worker std::make_index_sequence<8>());
182*9356374aSAndroid Build Coastguard Worker default:
183*9356374aSAndroid Build Coastguard Worker std::abort();
184*9356374aSAndroid Build Coastguard Worker }
185*9356374aSAndroid Build Coastguard Worker }
186*9356374aSAndroid Build Coastguard Worker
BM_StrAppendStr(benchmark::State & state)187*9356374aSAndroid Build Coastguard Worker void BM_StrAppendStr(benchmark::State& state) {
188*9356374aSAndroid Build Coastguard Worker using T = absl::string_view;
189*9356374aSAndroid Build Coastguard Worker using Row = std::tuple<T, T, T, T, T, T, T, T>;
190*9356374aSAndroid Build Coastguard Worker constexpr absl::string_view kChunk = "0123456789";
191*9356374aSAndroid Build Coastguard Worker Row row = {kChunk, kChunk, kChunk, kChunk, kChunk, kChunk, kChunk, kChunk};
192*9356374aSAndroid Build Coastguard Worker return BM_StrAppend(state, std::array<Row, 1>({row}));
193*9356374aSAndroid Build Coastguard Worker }
194*9356374aSAndroid Build Coastguard Worker
195*9356374aSAndroid Build Coastguard Worker template <typename T>
BM_StrAppendInt(benchmark::State & state)196*9356374aSAndroid Build Coastguard Worker void BM_StrAppendInt(benchmark::State& state) {
197*9356374aSAndroid Build Coastguard Worker absl::BitGen rng;
198*9356374aSAndroid Build Coastguard Worker absl::log_uniform_int_distribution<T> dist;
199*9356374aSAndroid Build Coastguard Worker std::array<std::tuple<T, T, T, T, T, T, T, T>, (1 << 7)> table;
200*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < table.size(); ++i) {
201*9356374aSAndroid Build Coastguard Worker table[i] = {dist(rng), dist(rng), dist(rng), dist(rng),
202*9356374aSAndroid Build Coastguard Worker dist(rng), dist(rng), dist(rng), dist(rng)};
203*9356374aSAndroid Build Coastguard Worker }
204*9356374aSAndroid Build Coastguard Worker return BM_StrAppend(state, table);
205*9356374aSAndroid Build Coastguard Worker }
206*9356374aSAndroid Build Coastguard Worker
207*9356374aSAndroid Build Coastguard Worker template <typename B>
StrAppendConfig(B * benchmark)208*9356374aSAndroid Build Coastguard Worker void StrAppendConfig(B* benchmark) {
209*9356374aSAndroid Build Coastguard Worker for (int bytes : {10, 100, 1000, 10000}) {
210*9356374aSAndroid Build Coastguard Worker for (int chunks : {1, 2, 4, 8}) {
211*9356374aSAndroid Build Coastguard Worker // Only add the ones that divide properly. Otherwise we are over counting.
212*9356374aSAndroid Build Coastguard Worker if (bytes % (10 * chunks) == 0) {
213*9356374aSAndroid Build Coastguard Worker benchmark->Args({bytes, chunks});
214*9356374aSAndroid Build Coastguard Worker }
215*9356374aSAndroid Build Coastguard Worker }
216*9356374aSAndroid Build Coastguard Worker }
217*9356374aSAndroid Build Coastguard Worker }
218*9356374aSAndroid Build Coastguard Worker
219*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrAppendStr)->Apply(StrAppendConfig);
220*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrAppendInt<int64_t>)->Apply(StrAppendConfig);
221*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrAppendInt<uint64_t>)->Apply(StrAppendConfig);
222*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrAppendInt<int32_t>)->Apply(StrAppendConfig);
223*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrAppendInt<uint32_t>)->Apply(StrAppendConfig);
224*9356374aSAndroid Build Coastguard Worker
225*9356374aSAndroid Build Coastguard Worker template <typename... Chunks>
BM_StrCatImpl(benchmark::State & state,Chunks...chunks)226*9356374aSAndroid Build Coastguard Worker void BM_StrCatImpl(benchmark::State& state,
227*9356374aSAndroid Build Coastguard Worker Chunks... chunks) {
228*9356374aSAndroid Build Coastguard Worker for (auto s : state) {
229*9356374aSAndroid Build Coastguard Worker std::string result = absl::StrCat(chunks...);
230*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
231*9356374aSAndroid Build Coastguard Worker }
232*9356374aSAndroid Build Coastguard Worker }
233*9356374aSAndroid Build Coastguard Worker
BM_StrCat(benchmark::State & state)234*9356374aSAndroid Build Coastguard Worker void BM_StrCat(benchmark::State& state) {
235*9356374aSAndroid Build Coastguard Worker const int chunks_at_a_time = state.range(0);
236*9356374aSAndroid Build Coastguard Worker const absl::string_view kChunk = "0123456789";
237*9356374aSAndroid Build Coastguard Worker
238*9356374aSAndroid Build Coastguard Worker switch (chunks_at_a_time) {
239*9356374aSAndroid Build Coastguard Worker case 1:
240*9356374aSAndroid Build Coastguard Worker return BM_StrCatImpl(state, kChunk);
241*9356374aSAndroid Build Coastguard Worker case 2:
242*9356374aSAndroid Build Coastguard Worker return BM_StrCatImpl(state, kChunk, kChunk);
243*9356374aSAndroid Build Coastguard Worker case 3:
244*9356374aSAndroid Build Coastguard Worker return BM_StrCatImpl(state, kChunk, kChunk, kChunk);
245*9356374aSAndroid Build Coastguard Worker case 4:
246*9356374aSAndroid Build Coastguard Worker return BM_StrCatImpl(state, kChunk, kChunk, kChunk, kChunk);
247*9356374aSAndroid Build Coastguard Worker default:
248*9356374aSAndroid Build Coastguard Worker std::abort();
249*9356374aSAndroid Build Coastguard Worker }
250*9356374aSAndroid Build Coastguard Worker }
251*9356374aSAndroid Build Coastguard Worker
252*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrCat)->Arg(1)->Arg(2)->Arg(3)->Arg(4);
253*9356374aSAndroid Build Coastguard Worker
BM_StrCat_int(benchmark::State & state)254*9356374aSAndroid Build Coastguard Worker void BM_StrCat_int(benchmark::State& state) {
255*9356374aSAndroid Build Coastguard Worker int i = 0;
256*9356374aSAndroid Build Coastguard Worker for (auto s : state) {
257*9356374aSAndroid Build Coastguard Worker std::string result = absl::StrCat(i);
258*9356374aSAndroid Build Coastguard Worker benchmark::DoNotOptimize(result);
259*9356374aSAndroid Build Coastguard Worker i = IncrementAlternatingSign(i);
260*9356374aSAndroid Build Coastguard Worker }
261*9356374aSAndroid Build Coastguard Worker }
262*9356374aSAndroid Build Coastguard Worker
263*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrCat_int);
264*9356374aSAndroid Build Coastguard Worker
265*9356374aSAndroid Build Coastguard Worker } // namespace
266