1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03, c++11, c++14
10
11 #include <cstdint>
12 #include <cstdlib>
13 #include <new>
14 #include <vector>
15
16 #include "CartesianBenchmarks.h"
17 #include "GenerateInput.h"
18 #include "benchmark/benchmark.h"
19 #include "test_macros.h"
20
21 constexpr std::size_t MAX_STRING_LEN = 8 << 14;
22
23 // Benchmark when there is no match.
BM_StringFindNoMatch(benchmark::State & state)24 static void BM_StringFindNoMatch(benchmark::State& state) {
25 std::string s1(state.range(0), '-');
26 std::string s2(8, '*');
27 for (auto _ : state)
28 benchmark::DoNotOptimize(s1.find(s2));
29 }
30 BENCHMARK(BM_StringFindNoMatch)->Range(10, MAX_STRING_LEN);
31
32 // Benchmark when the string matches first time.
BM_StringFindAllMatch(benchmark::State & state)33 static void BM_StringFindAllMatch(benchmark::State& state) {
34 std::string s1(MAX_STRING_LEN, '-');
35 std::string s2(state.range(0), '-');
36 for (auto _ : state)
37 benchmark::DoNotOptimize(s1.find(s2));
38 }
39 BENCHMARK(BM_StringFindAllMatch)->Range(1, MAX_STRING_LEN);
40
41 // Benchmark when the string matches somewhere in the end.
BM_StringFindMatch1(benchmark::State & state)42 static void BM_StringFindMatch1(benchmark::State& state) {
43 std::string s1(MAX_STRING_LEN / 2, '*');
44 s1 += std::string(state.range(0), '-');
45 std::string s2(state.range(0), '-');
46 for (auto _ : state)
47 benchmark::DoNotOptimize(s1.find(s2));
48 }
49 BENCHMARK(BM_StringFindMatch1)->Range(1, MAX_STRING_LEN / 4);
50
51 // Benchmark when the string matches somewhere from middle to the end.
BM_StringFindMatch2(benchmark::State & state)52 static void BM_StringFindMatch2(benchmark::State& state) {
53 std::string s1(MAX_STRING_LEN / 2, '*');
54 s1 += std::string(state.range(0), '-');
55 s1 += std::string(state.range(0), '*');
56 std::string s2(state.range(0), '-');
57 for (auto _ : state)
58 benchmark::DoNotOptimize(s1.find(s2));
59 }
60 BENCHMARK(BM_StringFindMatch2)->Range(1, MAX_STRING_LEN / 4);
61
BM_StringCtorDefault(benchmark::State & state)62 static void BM_StringCtorDefault(benchmark::State& state) {
63 for (auto _ : state) {
64 std::string Default;
65 benchmark::DoNotOptimize(Default);
66 }
67 }
68 BENCHMARK(BM_StringCtorDefault);
69
70 enum class Length { Empty, Small, Large, Huge };
71 struct AllLengths : EnumValuesAsTuple<AllLengths, Length, 4> {
72 static constexpr const char* Names[] = {"Empty", "Small", "Large", "Huge"};
73 };
74
75 enum class Opacity { Opaque, Transparent };
76 struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
77 static constexpr const char* Names[] = {"Opaque", "Transparent"};
78 };
79
80 enum class DiffType { Control, ChangeFirst, ChangeMiddle, ChangeLast };
81 struct AllDiffTypes : EnumValuesAsTuple<AllDiffTypes, DiffType, 4> {
82 static constexpr const char* Names[] = {"Control", "ChangeFirst", "ChangeMiddle", "ChangeLast"};
83 };
84
85 static constexpr char SmallStringLiteral[] = "012345678";
86
getSmallString(DiffType D)87 TEST_ALWAYS_INLINE const char* getSmallString(DiffType D) {
88 switch (D) {
89 case DiffType::Control:
90 return SmallStringLiteral;
91 case DiffType::ChangeFirst:
92 return "-12345678";
93 case DiffType::ChangeMiddle:
94 return "0123-5678";
95 case DiffType::ChangeLast:
96 return "01234567-";
97 }
98 __builtin_unreachable();
99 }
100
101 static constexpr char LargeStringLiteral[] = "012345678901234567890123456789012345678901234567890123456789012";
102
getLargeString(DiffType D)103 TEST_ALWAYS_INLINE const char* getLargeString(DiffType D) {
104 #define LARGE_STRING_FIRST "123456789012345678901234567890"
105 #define LARGE_STRING_SECOND "234567890123456789012345678901"
106 switch (D) {
107 case DiffType::Control:
108 return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
109 case DiffType::ChangeFirst:
110 return "-" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
111 case DiffType::ChangeMiddle:
112 return "0" LARGE_STRING_FIRST "-" LARGE_STRING_SECOND "2";
113 case DiffType::ChangeLast:
114 return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "-";
115 }
116 __builtin_unreachable();
117 }
118
getHugeString(DiffType D)119 TEST_ALWAYS_INLINE const char* getHugeString(DiffType D) {
120 #define HUGE_STRING0 "0123456789"
121 #define HUGE_STRING1 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0
122 #define HUGE_STRING2 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1
123 #define HUGE_STRING3 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2
124 #define HUGE_STRING4 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3
125 switch (D) {
126 case DiffType::Control:
127 return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
128 case DiffType::ChangeFirst:
129 return "-123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
130 case DiffType::ChangeMiddle:
131 return "0123456789" HUGE_STRING4 "01234-6789" HUGE_STRING4 "0123456789";
132 case DiffType::ChangeLast:
133 return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "012345678-";
134 }
135 __builtin_unreachable();
136 }
137
getString(Length L,DiffType D=DiffType::Control)138 TEST_ALWAYS_INLINE const char* getString(Length L, DiffType D = DiffType::Control) {
139 switch (L) {
140 case Length::Empty:
141 return "";
142 case Length::Small:
143 return getSmallString(D);
144 case Length::Large:
145 return getLargeString(D);
146 case Length::Huge:
147 return getHugeString(D);
148 }
149 __builtin_unreachable();
150 }
151
makeString(Length L,DiffType D=DiffType::Control,Opacity O=Opacity::Transparent)152 TEST_ALWAYS_INLINE std::string makeString(Length L, DiffType D = DiffType::Control, Opacity O = Opacity::Transparent) {
153 switch (L) {
154 case Length::Empty:
155 return maybeOpaque("", O == Opacity::Opaque);
156 case Length::Small:
157 return maybeOpaque(getSmallString(D), O == Opacity::Opaque);
158 case Length::Large:
159 return maybeOpaque(getLargeString(D), O == Opacity::Opaque);
160 case Length::Huge:
161 return maybeOpaque(getHugeString(D), O == Opacity::Opaque);
162 }
163 __builtin_unreachable();
164 }
165
166 template <class Length, class Opaque>
167 struct StringConstructDestroyCStr {
runStringConstructDestroyCStr168 static void run(benchmark::State& state) {
169 for (auto _ : state) {
170 benchmark::DoNotOptimize(makeString(Length(), DiffType::Control, Opaque()));
171 }
172 }
173
nameStringConstructDestroyCStr174 static std::string name() { return "BM_StringConstructDestroyCStr" + Length::name() + Opaque::name(); }
175 };
176
177 template <class Length, bool MeasureCopy, bool MeasureDestroy>
StringCopyAndDestroy(benchmark::State & state)178 static void StringCopyAndDestroy(benchmark::State& state) {
179 static constexpr size_t NumStrings = 1024;
180 auto Orig = makeString(Length());
181 alignas(std::string) char Storage[NumStrings * sizeof(std::string)];
182
183 while (state.KeepRunningBatch(NumStrings)) {
184 if (!MeasureCopy)
185 state.PauseTiming();
186 for (size_t I = 0; I < NumStrings; ++I) {
187 ::new (reinterpret_cast<std::string*>(Storage) + I) std::string(Orig);
188 }
189 if (!MeasureCopy)
190 state.ResumeTiming();
191 if (!MeasureDestroy)
192 state.PauseTiming();
193 for (size_t I = 0; I < NumStrings; ++I) {
194 using S = std::string;
195 (reinterpret_cast<S*>(Storage) + I)->~S();
196 }
197 if (!MeasureDestroy)
198 state.ResumeTiming();
199 }
200 }
201
202 template <class Length>
203 struct StringCopy {
runStringCopy204 static void run(benchmark::State& state) { StringCopyAndDestroy<Length, true, false>(state); }
205
nameStringCopy206 static std::string name() { return "BM_StringCopy" + Length::name(); }
207 };
208
209 template <class Length>
210 struct StringDestroy {
runStringDestroy211 static void run(benchmark::State& state) { StringCopyAndDestroy<Length, false, true>(state); }
212
nameStringDestroy213 static std::string name() { return "BM_StringDestroy" + Length::name(); }
214 };
215
216 template <class Length>
217 struct StringMove {
runStringMove218 static void run(benchmark::State& state) {
219 // Keep two object locations and move construct back and forth.
220 alignas(std::string) char Storage[2 * sizeof(std::string)];
221 using S = std::string;
222 size_t I = 0;
223 S* newS = new (reinterpret_cast<std::string*>(Storage)) std::string(makeString(Length()));
224 for (auto _ : state) {
225 // Switch locations.
226 I ^= 1;
227 benchmark::DoNotOptimize(Storage);
228 // Move construct into the new location,
229 S* tmpS = new (reinterpret_cast<std::string*>(Storage) + I) S(std::move(*newS));
230 // then destroy the old one.
231 newS->~S();
232 newS = tmpS;
233 }
234 newS->~S();
235 }
236
nameStringMove237 static std::string name() { return "BM_StringMove" + Length::name(); }
238 };
239
240 template <class Length, class Opaque>
241 struct StringResizeDefaultInit {
runStringResizeDefaultInit242 static void run(benchmark::State& state) {
243 constexpr bool opaque = Opaque{} == Opacity::Opaque;
244 constexpr int kNumStrings = 4 << 10;
245 size_t length = makeString(Length()).size();
246 std::string strings[kNumStrings];
247 while (state.KeepRunningBatch(kNumStrings)) {
248 state.PauseTiming();
249 for (int i = 0; i < kNumStrings; ++i) {
250 std::string().swap(strings[i]);
251 }
252 benchmark::DoNotOptimize(strings);
253 state.ResumeTiming();
254 for (int i = 0; i < kNumStrings; ++i) {
255 strings[i].__resize_default_init(maybeOpaque(length, opaque));
256 }
257 }
258 }
259
nameStringResizeDefaultInit260 static std::string name() { return "BM_StringResizeDefaultInit" + Length::name() + Opaque::name(); }
261 };
262
263 template <class Length, class Opaque>
264 struct StringAssignStr {
runStringAssignStr265 static void run(benchmark::State& state) {
266 constexpr bool opaque = Opaque{} == Opacity::Opaque;
267 constexpr int kNumStrings = 4 << 10;
268 std::string src = makeString(Length());
269 std::string strings[kNumStrings];
270 while (state.KeepRunningBatch(kNumStrings)) {
271 state.PauseTiming();
272 for (int i = 0; i < kNumStrings; ++i) {
273 std::string().swap(strings[i]);
274 }
275 benchmark::DoNotOptimize(strings);
276 state.ResumeTiming();
277 for (int i = 0; i < kNumStrings; ++i) {
278 strings[i] = *maybeOpaque(&src, opaque);
279 }
280 }
281 }
282
nameStringAssignStr283 static std::string name() { return "BM_StringAssignStr" + Length::name() + Opaque::name(); }
284 };
285
286 template <class Length, class Opaque>
287 struct StringAssignAsciiz {
runStringAssignAsciiz288 static void run(benchmark::State& state) {
289 constexpr bool opaque = Opaque{} == Opacity::Opaque;
290 constexpr int kNumStrings = 4 << 10;
291 std::string strings[kNumStrings];
292 while (state.KeepRunningBatch(kNumStrings)) {
293 state.PauseTiming();
294 for (int i = 0; i < kNumStrings; ++i) {
295 std::string().swap(strings[i]);
296 }
297 benchmark::DoNotOptimize(strings);
298 state.ResumeTiming();
299 for (int i = 0; i < kNumStrings; ++i) {
300 strings[i] = maybeOpaque(getString(Length()), opaque);
301 }
302 }
303 }
304
nameStringAssignAsciiz305 static std::string name() { return "BM_StringAssignAsciiz" + Length::name() + Opaque::name(); }
306 };
307
308 template <class Length, class Opaque>
309 struct StringEraseToEnd {
runStringEraseToEnd310 static void run(benchmark::State& state) {
311 constexpr bool opaque = Opaque{} == Opacity::Opaque;
312 constexpr int kNumStrings = 4 << 10;
313 std::string strings[kNumStrings];
314 const int mid = makeString(Length()).size() / 2;
315 while (state.KeepRunningBatch(kNumStrings)) {
316 state.PauseTiming();
317 for (int i = 0; i < kNumStrings; ++i) {
318 strings[i] = makeString(Length());
319 }
320 benchmark::DoNotOptimize(strings);
321 state.ResumeTiming();
322 for (int i = 0; i < kNumStrings; ++i) {
323 strings[i].erase(maybeOpaque(mid, opaque), maybeOpaque(std::string::npos, opaque));
324 }
325 }
326 }
327
nameStringEraseToEnd328 static std::string name() { return "BM_StringEraseToEnd" + Length::name() + Opaque::name(); }
329 };
330
331 template <class Length, class Opaque>
332 struct StringEraseWithMove {
runStringEraseWithMove333 static void run(benchmark::State& state) {
334 constexpr bool opaque = Opaque{} == Opacity::Opaque;
335 constexpr int kNumStrings = 4 << 10;
336 std::string strings[kNumStrings];
337 const int n = makeString(Length()).size() / 2;
338 const int pos = n / 2;
339 while (state.KeepRunningBatch(kNumStrings)) {
340 state.PauseTiming();
341 for (int i = 0; i < kNumStrings; ++i) {
342 strings[i] = makeString(Length());
343 }
344 benchmark::DoNotOptimize(strings);
345 state.ResumeTiming();
346 for (int i = 0; i < kNumStrings; ++i) {
347 strings[i].erase(maybeOpaque(pos, opaque), maybeOpaque(n, opaque));
348 }
349 }
350 }
351
nameStringEraseWithMove352 static std::string name() { return "BM_StringEraseWithMove" + Length::name() + Opaque::name(); }
353 };
354
355 template <class Opaque>
356 struct StringAssignAsciizMix {
runStringAssignAsciizMix357 static void run(benchmark::State& state) {
358 constexpr auto O = Opaque{};
359 constexpr auto D = DiffType::Control;
360 constexpr int kNumStrings = 4 << 10;
361 std::string strings[kNumStrings];
362 while (state.KeepRunningBatch(kNumStrings)) {
363 state.PauseTiming();
364 for (int i = 0; i < kNumStrings; ++i) {
365 std::string().swap(strings[i]);
366 }
367 benchmark::DoNotOptimize(strings);
368 state.ResumeTiming();
369 for (int i = 0; i < kNumStrings - 7; i += 8) {
370 strings[i + 0] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
371 strings[i + 1] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
372 strings[i + 2] = maybeOpaque(getLargeString(D), O == Opacity::Opaque);
373 strings[i + 3] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
374 strings[i + 4] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
375 strings[i + 5] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
376 strings[i + 6] = maybeOpaque(getLargeString(D), O == Opacity::Opaque);
377 strings[i + 7] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
378 }
379 }
380 }
381
nameStringAssignAsciizMix382 static std::string name() { return "BM_StringAssignAsciizMix" + Opaque::name(); }
383 };
384
385 enum class Relation { Eq, Less, Compare };
386 struct AllRelations : EnumValuesAsTuple<AllRelations, Relation, 3> {
387 static constexpr const char* Names[] = {"Eq", "Less", "Compare"};
388 };
389
390 template <class Rel, class LHLength, class RHLength, class DiffType>
391 struct StringRelational {
runStringRelational392 static void run(benchmark::State& state) {
393 auto Lhs = makeString(RHLength());
394 auto Rhs = makeString(LHLength(), DiffType());
395 for (auto _ : state) {
396 benchmark::DoNotOptimize(Lhs);
397 benchmark::DoNotOptimize(Rhs);
398 switch (Rel()) {
399 case Relation::Eq:
400 benchmark::DoNotOptimize(Lhs == Rhs);
401 break;
402 case Relation::Less:
403 benchmark::DoNotOptimize(Lhs < Rhs);
404 break;
405 case Relation::Compare:
406 benchmark::DoNotOptimize(Lhs.compare(Rhs));
407 break;
408 }
409 }
410 }
411
skipStringRelational412 static bool skip() {
413 // Eq is commutative, so skip half the matrix.
414 if (Rel() == Relation::Eq && LHLength() > RHLength())
415 return true;
416 // We only care about control when the lengths differ.
417 if (LHLength() != RHLength() && DiffType() != ::DiffType::Control)
418 return true;
419 // For empty, only control matters.
420 if (LHLength() == Length::Empty && DiffType() != ::DiffType::Control)
421 return true;
422 return false;
423 }
424
nameStringRelational425 static std::string name() {
426 return "BM_StringRelational" + Rel::name() + LHLength::name() + RHLength::name() + DiffType::name();
427 }
428 };
429
430 template <class Rel, class LHLength, class RHLength, class DiffType>
431 struct StringRelationalLiteral {
runStringRelationalLiteral432 static void run(benchmark::State& state) {
433 auto Lhs = makeString(LHLength(), DiffType());
434 for (auto _ : state) {
435 benchmark::DoNotOptimize(Lhs);
436 constexpr const char* Literal =
437 RHLength::value == Length::Empty ? ""
438 : RHLength::value == Length::Small
439 ? SmallStringLiteral
440 : LargeStringLiteral;
441 switch (Rel()) {
442 case Relation::Eq:
443 benchmark::DoNotOptimize(Lhs == Literal);
444 break;
445 case Relation::Less:
446 benchmark::DoNotOptimize(Lhs < Literal);
447 break;
448 case Relation::Compare:
449 benchmark::DoNotOptimize(Lhs.compare(Literal));
450 break;
451 }
452 }
453 }
454
skipStringRelationalLiteral455 static bool skip() {
456 // Doesn't matter how they differ if they have different size.
457 if (LHLength() != RHLength() && DiffType() != ::DiffType::Control)
458 return true;
459 // We don't need huge. Doensn't give anything different than Large.
460 if (LHLength() == Length::Huge || RHLength() == Length::Huge)
461 return true;
462 return false;
463 }
464
nameStringRelationalLiteral465 static std::string name() {
466 return "BM_StringRelationalLiteral" + Rel::name() + LHLength::name() + RHLength::name() + DiffType::name();
467 }
468 };
469
470 enum class Depth { Shallow, Deep };
471 struct AllDepths : EnumValuesAsTuple<AllDepths, Depth, 2> {
472 static constexpr const char* Names[] = {"Shallow", "Deep"};
473 };
474
475 enum class Temperature { Hot, Cold };
476 struct AllTemperatures : EnumValuesAsTuple<AllTemperatures, Temperature, 2> {
477 static constexpr const char* Names[] = {"Hot", "Cold"};
478 };
479
480 template <class Temperature, class Depth, class Length>
481 struct StringRead {
runStringRead482 void run(benchmark::State& state) const {
483 static constexpr size_t NumStrings =
484 Temperature() == ::Temperature::Hot ? 1 << 10 : /* Enough strings to overflow the cache */ 1 << 20;
485 static_assert((NumStrings & (NumStrings - 1)) == 0, "NumStrings should be a power of two to reduce overhead.");
486
487 std::vector<std::string> Values(NumStrings, makeString(Length()));
488 size_t I = 0;
489 for (auto _ : state) {
490 // Jump long enough to defeat cache locality, and use a value that is
491 // coprime with NumStrings to ensure we visit every element.
492 I = (I + 17) % NumStrings;
493 auto& V = Values[I];
494
495 // Read everything first. Escaping data() through DoNotOptimize might
496 // cause the compiler to have to recalculate information about `V` due to
497 // aliasing.
498 char* Data = V.data();
499 size_t Size = V.size();
500 benchmark::DoNotOptimize(Data);
501 benchmark::DoNotOptimize(Size);
502 if (Depth() == ::Depth::Deep) {
503 // Read into the payload. This mainly shows the benefit of SSO when the
504 // data is cold.
505 benchmark::DoNotOptimize(*Data);
506 }
507 }
508 }
509
skipStringRead510 static bool skip() {
511 // Huge does not give us anything that Large doesn't have. Skip it.
512 if (Length() == ::Length::Huge) {
513 return true;
514 }
515 return false;
516 }
517
nameStringRead518 std::string name() const { return "BM_StringRead" + Temperature::name() + Depth::name() + Length::name(); }
519 };
520
sanityCheckGeneratedStrings()521 void sanityCheckGeneratedStrings() {
522 for (auto Lhs : {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
523 const auto LhsString = makeString(Lhs);
524 for (auto Rhs : {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
525 if (Lhs > Rhs)
526 continue;
527 const auto RhsString = makeString(Rhs);
528
529 // The smaller one must be a prefix of the larger one.
530 if (RhsString.find(LhsString) != 0) {
531 fprintf(
532 stderr, "Invalid autogenerated strings for sizes (%d,%d).\n", static_cast<int>(Lhs), static_cast<int>(Rhs));
533 std::abort();
534 }
535 }
536 }
537 // Verify the autogenerated diffs
538 for (auto L : {Length::Small, Length::Large, Length::Huge}) {
539 const auto Control = makeString(L);
540 const auto Verify = [&](std::string Exp, size_t Pos) {
541 // Only change on the Pos char.
542 if (Control[Pos] != Exp[Pos]) {
543 Exp[Pos] = Control[Pos];
544 if (Control == Exp)
545 return;
546 }
547 fprintf(stderr, "Invalid autogenerated diff with size %d\n", static_cast<int>(L));
548 std::abort();
549 };
550 Verify(makeString(L, DiffType::ChangeFirst), 0);
551 Verify(makeString(L, DiffType::ChangeMiddle), Control.size() / 2);
552 Verify(makeString(L, DiffType::ChangeLast), Control.size() - 1);
553 }
554 }
555
556 // Some small codegen thunks to easily see generated code.
StringEqString(const std::string & a,const std::string & b)557 bool StringEqString(const std::string& a, const std::string& b) { return a == b; }
StringEqCStr(const std::string & a,const char * b)558 bool StringEqCStr(const std::string& a, const char* b) { return a == b; }
CStrEqString(const char * a,const std::string & b)559 bool CStrEqString(const char* a, const std::string& b) { return a == b; }
StringEqCStrLiteralEmpty(const std::string & a)560 bool StringEqCStrLiteralEmpty(const std::string& a) { return a == ""; }
StringEqCStrLiteralSmall(const std::string & a)561 bool StringEqCStrLiteralSmall(const std::string& a) { return a == SmallStringLiteral; }
StringEqCStrLiteralLarge(const std::string & a)562 bool StringEqCStrLiteralLarge(const std::string& a) { return a == LargeStringLiteral; }
563
main(int argc,char ** argv)564 int main(int argc, char** argv) {
565 benchmark::Initialize(&argc, argv);
566 if (benchmark::ReportUnrecognizedArguments(argc, argv))
567 return 1;
568
569 sanityCheckGeneratedStrings();
570
571 makeCartesianProductBenchmark<StringConstructDestroyCStr, AllLengths, AllOpacity>();
572
573 makeCartesianProductBenchmark<StringAssignStr, AllLengths, AllOpacity>();
574 makeCartesianProductBenchmark<StringAssignAsciiz, AllLengths, AllOpacity>();
575 makeCartesianProductBenchmark<StringAssignAsciizMix, AllOpacity>();
576
577 makeCartesianProductBenchmark<StringCopy, AllLengths>();
578 makeCartesianProductBenchmark<StringMove, AllLengths>();
579 makeCartesianProductBenchmark<StringDestroy, AllLengths>();
580 makeCartesianProductBenchmark<StringResizeDefaultInit, AllLengths, AllOpacity>();
581 makeCartesianProductBenchmark<StringEraseToEnd, AllLengths, AllOpacity>();
582 makeCartesianProductBenchmark<StringEraseWithMove, AllLengths, AllOpacity>();
583 makeCartesianProductBenchmark<StringRelational, AllRelations, AllLengths, AllLengths, AllDiffTypes>();
584 makeCartesianProductBenchmark<StringRelationalLiteral, AllRelations, AllLengths, AllLengths, AllDiffTypes>();
585 makeCartesianProductBenchmark<StringRead, AllTemperatures, AllDepths, AllLengths>();
586 benchmark::RunSpecifiedBenchmarks();
587
588 if (argc < 0) {
589 // ODR-use the functions to force them being generated in the binary.
590 auto functions = std::make_tuple(
591 StringEqString,
592 StringEqCStr,
593 CStrEqString,
594 StringEqCStrLiteralEmpty,
595 StringEqCStrLiteralSmall,
596 StringEqCStrLiteralLarge);
597 printf("%p", &functions);
598 }
599 }
600