• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/strings/str_cat.h"
16 
17 #include <cstdint>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 #include <string>
22 
23 #include "benchmark/benchmark.h"
24 #include "absl/strings/string_view.h"
25 #include "absl/strings/substitute.h"
26 
27 namespace {
28 
29 const char kStringOne[] = "Once Upon A Time, ";
30 const char kStringTwo[] = "There was a string benchmark";
31 
32 // We want to include negative numbers in the benchmark, so this function
33 // is used to count 0, 1, -1, 2, -2, 3, -3, ...
IncrementAlternatingSign(int i)34 inline int IncrementAlternatingSign(int i) {
35   return i > 0 ? -i : 1 - i;
36 }
37 
BM_Sum_By_StrCat(benchmark::State & state)38 void BM_Sum_By_StrCat(benchmark::State& state) {
39   int i = 0;
40   char foo[100];
41   for (auto _ : state) {
42     // NOLINTNEXTLINE(runtime/printf)
43     strcpy(foo, absl::StrCat(kStringOne, i, kStringTwo, i * 65536ULL).c_str());
44     int sum = 0;
45     for (char* f = &foo[0]; *f != 0; ++f) {
46       sum += *f;
47     }
48     benchmark::DoNotOptimize(sum);
49     i = IncrementAlternatingSign(i);
50   }
51 }
52 BENCHMARK(BM_Sum_By_StrCat);
53 
BM_StrCat_By_snprintf(benchmark::State & state)54 void BM_StrCat_By_snprintf(benchmark::State& state) {
55   int i = 0;
56   char on_stack[1000];
57   for (auto _ : state) {
58     snprintf(on_stack, sizeof(on_stack), "%s %s:%d", kStringOne, kStringTwo, i);
59     i = IncrementAlternatingSign(i);
60   }
61 }
62 BENCHMARK(BM_StrCat_By_snprintf);
63 
BM_StrCat_By_Strings(benchmark::State & state)64 void BM_StrCat_By_Strings(benchmark::State& state) {
65   int i = 0;
66   for (auto _ : state) {
67     std::string result =
68         std::string(kStringOne) + " " + kStringTwo + ":" + absl::StrCat(i);
69     benchmark::DoNotOptimize(result);
70     i = IncrementAlternatingSign(i);
71   }
72 }
73 BENCHMARK(BM_StrCat_By_Strings);
74 
BM_StrCat_By_StringOpPlus(benchmark::State & state)75 void BM_StrCat_By_StringOpPlus(benchmark::State& state) {
76   int i = 0;
77   for (auto _ : state) {
78     std::string result = kStringOne;
79     result += " ";
80     result += kStringTwo;
81     result += ":";
82     result += absl::StrCat(i);
83     benchmark::DoNotOptimize(result);
84     i = IncrementAlternatingSign(i);
85   }
86 }
87 BENCHMARK(BM_StrCat_By_StringOpPlus);
88 
BM_StrCat_By_StrCat(benchmark::State & state)89 void BM_StrCat_By_StrCat(benchmark::State& state) {
90   int i = 0;
91   for (auto _ : state) {
92     std::string result = absl::StrCat(kStringOne, " ", kStringTwo, ":", i);
93     benchmark::DoNotOptimize(result);
94     i = IncrementAlternatingSign(i);
95   }
96 }
97 BENCHMARK(BM_StrCat_By_StrCat);
98 
BM_HexCat_By_StrCat(benchmark::State & state)99 void BM_HexCat_By_StrCat(benchmark::State& state) {
100   int i = 0;
101   for (auto _ : state) {
102     std::string result =
103         absl::StrCat(kStringOne, " ", absl::Hex(int64_t{i} + 0x10000000));
104     benchmark::DoNotOptimize(result);
105     i = IncrementAlternatingSign(i);
106   }
107 }
108 BENCHMARK(BM_HexCat_By_StrCat);
109 
BM_HexCat_By_Substitute(benchmark::State & state)110 void BM_HexCat_By_Substitute(benchmark::State& state) {
111   int i = 0;
112   for (auto _ : state) {
113     std::string result = absl::Substitute(
114         "$0 $1", kStringOne, reinterpret_cast<void*>(int64_t{i} + 0x10000000));
115     benchmark::DoNotOptimize(result);
116     i = IncrementAlternatingSign(i);
117   }
118 }
119 BENCHMARK(BM_HexCat_By_Substitute);
120 
BM_FloatToString_By_StrCat(benchmark::State & state)121 void BM_FloatToString_By_StrCat(benchmark::State& state) {
122   int i = 0;
123   float foo = 0.0f;
124   for (auto _ : state) {
125     std::string result = absl::StrCat(foo += 1.001f, " != ", int64_t{i});
126     benchmark::DoNotOptimize(result);
127     i = IncrementAlternatingSign(i);
128   }
129 }
130 BENCHMARK(BM_FloatToString_By_StrCat);
131 
BM_DoubleToString_By_SixDigits(benchmark::State & state)132 void BM_DoubleToString_By_SixDigits(benchmark::State& state) {
133   int i = 0;
134   double foo = 0.0;
135   for (auto _ : state) {
136     std::string result =
137         absl::StrCat(absl::SixDigits(foo += 1.001), " != ", int64_t{i});
138     benchmark::DoNotOptimize(result);
139     i = IncrementAlternatingSign(i);
140   }
141 }
142 BENCHMARK(BM_DoubleToString_By_SixDigits);
143 
144 template <typename... Chunks>
BM_StrAppendImpl(benchmark::State & state,size_t total_bytes,Chunks...chunks)145 void BM_StrAppendImpl(benchmark::State& state, size_t total_bytes,
146                       Chunks... chunks) {
147   for (auto s : state) {
148     std::string result;
149     while (result.size() < total_bytes) {
150       absl::StrAppend(&result, chunks...);
151       benchmark::DoNotOptimize(result);
152     }
153   }
154 }
155 
BM_StrAppend(benchmark::State & state)156 void BM_StrAppend(benchmark::State& state) {
157   const size_t total_bytes = state.range(0);
158   const int chunks_at_a_time = state.range(1);
159   const absl::string_view kChunk = "0123456789";
160 
161   switch (chunks_at_a_time) {
162     case 1:
163       return BM_StrAppendImpl(state, total_bytes, kChunk);
164     case 2:
165       return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk);
166     case 4:
167       return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
168                               kChunk);
169     case 8:
170       return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
171                               kChunk, kChunk, kChunk, kChunk, kChunk);
172     default:
173       std::abort();
174   }
175 }
176 
BM_StrAppendInt(benchmark::State & state)177 void BM_StrAppendInt(benchmark::State& state) {
178   const size_t total_bytes = state.range(0);
179   const int chunks_at_a_time = state.range(1);
180   const size_t kChunk = 1234;
181 
182   switch (chunks_at_a_time) {
183     case 1:
184       return BM_StrAppendImpl(state, total_bytes, kChunk);
185     case 2:
186       return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk);
187     case 4:
188       return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
189                               kChunk);
190     case 8:
191       return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
192                               kChunk, kChunk, kChunk, kChunk, kChunk);
193     default:
194       std::abort();
195   }
196 }
197 
198 template <typename B>
StrAppendConfig(B * benchmark)199 void StrAppendConfig(B* benchmark) {
200   for (int bytes : {10, 100, 1000, 10000}) {
201     for (int chunks : {1, 2, 4, 8}) {
202       // Only add the ones that divide properly. Otherwise we are over counting.
203       if (bytes % (10 * chunks) == 0) {
204         benchmark->Args({bytes, chunks});
205       }
206     }
207   }
208 }
209 
210 BENCHMARK(BM_StrAppend)->Apply(StrAppendConfig);
211 BENCHMARK(BM_StrAppendInt)->Apply(StrAppendConfig);
212 
213 template <typename... Chunks>
BM_StrCatImpl(benchmark::State & state,Chunks...chunks)214 void BM_StrCatImpl(benchmark::State& state,
215                       Chunks... chunks) {
216   for (auto s : state) {
217     std::string result = absl::StrCat(chunks...);
218     benchmark::DoNotOptimize(result);
219   }
220 }
221 
BM_StrCat(benchmark::State & state)222 void BM_StrCat(benchmark::State& state) {
223   const int chunks_at_a_time = state.range(0);
224   const absl::string_view kChunk = "0123456789";
225 
226   switch (chunks_at_a_time) {
227     case 1:
228       return BM_StrCatImpl(state, kChunk);
229     case 2:
230       return BM_StrCatImpl(state, kChunk, kChunk);
231     case 3:
232       return BM_StrCatImpl(state, kChunk, kChunk, kChunk);
233     case 4:
234       return BM_StrCatImpl(state, kChunk, kChunk, kChunk, kChunk);
235     default:
236       std::abort();
237   }
238 }
239 
240 BENCHMARK(BM_StrCat)->Arg(1)->Arg(2)->Arg(3)->Arg(4);
241 
BM_StrCat_int(benchmark::State & state)242 void BM_StrCat_int(benchmark::State& state) {
243   int i = 0;
244   for (auto s : state) {
245     std::string result = absl::StrCat(i);
246     benchmark::DoNotOptimize(result);
247     i = IncrementAlternatingSign(i);
248   }
249 }
250 
251 BENCHMARK(BM_StrCat_int);
252 
253 }  // namespace
254