• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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