xref: /aosp_15_r20/external/libcxx/benchmarks/string.bench.cpp (revision 58b9f456b02922dfdb1fad8a988d5fd8765ecb80)
1*58b9f456SAndroid Build Coastguard Worker 
2*58b9f456SAndroid Build Coastguard Worker #include <cstdint>
3*58b9f456SAndroid Build Coastguard Worker #include <new>
4*58b9f456SAndroid Build Coastguard Worker #include <vector>
5*58b9f456SAndroid Build Coastguard Worker 
6*58b9f456SAndroid Build Coastguard Worker #include "CartesianBenchmarks.hpp"
7*58b9f456SAndroid Build Coastguard Worker #include "GenerateInput.hpp"
8*58b9f456SAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
9*58b9f456SAndroid Build Coastguard Worker #include "test_macros.h"
10*58b9f456SAndroid Build Coastguard Worker 
11*58b9f456SAndroid Build Coastguard Worker constexpr std::size_t MAX_STRING_LEN = 8 << 14;
12*58b9f456SAndroid Build Coastguard Worker 
13*58b9f456SAndroid Build Coastguard Worker // Benchmark when there is no match.
BM_StringFindNoMatch(benchmark::State & state)14*58b9f456SAndroid Build Coastguard Worker static void BM_StringFindNoMatch(benchmark::State &state) {
15*58b9f456SAndroid Build Coastguard Worker   std::string s1(state.range(0), '-');
16*58b9f456SAndroid Build Coastguard Worker   std::string s2(8, '*');
17*58b9f456SAndroid Build Coastguard Worker   for (auto _ : state)
18*58b9f456SAndroid Build Coastguard Worker     benchmark::DoNotOptimize(s1.find(s2));
19*58b9f456SAndroid Build Coastguard Worker }
20*58b9f456SAndroid Build Coastguard Worker BENCHMARK(BM_StringFindNoMatch)->Range(10, MAX_STRING_LEN);
21*58b9f456SAndroid Build Coastguard Worker 
22*58b9f456SAndroid Build Coastguard Worker // Benchmark when the string matches first time.
BM_StringFindAllMatch(benchmark::State & state)23*58b9f456SAndroid Build Coastguard Worker static void BM_StringFindAllMatch(benchmark::State &state) {
24*58b9f456SAndroid Build Coastguard Worker   std::string s1(MAX_STRING_LEN, '-');
25*58b9f456SAndroid Build Coastguard Worker   std::string s2(state.range(0), '-');
26*58b9f456SAndroid Build Coastguard Worker   for (auto _ : state)
27*58b9f456SAndroid Build Coastguard Worker     benchmark::DoNotOptimize(s1.find(s2));
28*58b9f456SAndroid Build Coastguard Worker }
29*58b9f456SAndroid Build Coastguard Worker BENCHMARK(BM_StringFindAllMatch)->Range(1, MAX_STRING_LEN);
30*58b9f456SAndroid Build Coastguard Worker 
31*58b9f456SAndroid Build Coastguard Worker // Benchmark when the string matches somewhere in the end.
BM_StringFindMatch1(benchmark::State & state)32*58b9f456SAndroid Build Coastguard Worker static void BM_StringFindMatch1(benchmark::State &state) {
33*58b9f456SAndroid Build Coastguard Worker   std::string s1(MAX_STRING_LEN / 2, '*');
34*58b9f456SAndroid Build Coastguard Worker   s1 += std::string(state.range(0), '-');
35*58b9f456SAndroid Build Coastguard Worker   std::string s2(state.range(0), '-');
36*58b9f456SAndroid Build Coastguard Worker   for (auto _ : state)
37*58b9f456SAndroid Build Coastguard Worker     benchmark::DoNotOptimize(s1.find(s2));
38*58b9f456SAndroid Build Coastguard Worker }
39*58b9f456SAndroid Build Coastguard Worker BENCHMARK(BM_StringFindMatch1)->Range(1, MAX_STRING_LEN / 4);
40*58b9f456SAndroid Build Coastguard Worker 
41*58b9f456SAndroid Build Coastguard Worker // Benchmark when the string matches somewhere from middle to the end.
BM_StringFindMatch2(benchmark::State & state)42*58b9f456SAndroid Build Coastguard Worker static void BM_StringFindMatch2(benchmark::State &state) {
43*58b9f456SAndroid Build Coastguard Worker   std::string s1(MAX_STRING_LEN / 2, '*');
44*58b9f456SAndroid Build Coastguard Worker   s1 += std::string(state.range(0), '-');
45*58b9f456SAndroid Build Coastguard Worker   s1 += std::string(state.range(0), '*');
46*58b9f456SAndroid Build Coastguard Worker   std::string s2(state.range(0), '-');
47*58b9f456SAndroid Build Coastguard Worker   for (auto _ : state)
48*58b9f456SAndroid Build Coastguard Worker     benchmark::DoNotOptimize(s1.find(s2));
49*58b9f456SAndroid Build Coastguard Worker }
50*58b9f456SAndroid Build Coastguard Worker BENCHMARK(BM_StringFindMatch2)->Range(1, MAX_STRING_LEN / 4);
51*58b9f456SAndroid Build Coastguard Worker 
BM_StringCtorDefault(benchmark::State & state)52*58b9f456SAndroid Build Coastguard Worker static void BM_StringCtorDefault(benchmark::State &state) {
53*58b9f456SAndroid Build Coastguard Worker   for (auto _ : state) {
54*58b9f456SAndroid Build Coastguard Worker     std::string Default;
55*58b9f456SAndroid Build Coastguard Worker     benchmark::DoNotOptimize(Default);
56*58b9f456SAndroid Build Coastguard Worker   }
57*58b9f456SAndroid Build Coastguard Worker }
58*58b9f456SAndroid Build Coastguard Worker BENCHMARK(BM_StringCtorDefault);
59*58b9f456SAndroid Build Coastguard Worker 
60*58b9f456SAndroid Build Coastguard Worker enum class Length { Empty, Small, Large, Huge };
61*58b9f456SAndroid Build Coastguard Worker struct AllLengths : EnumValuesAsTuple<AllLengths, Length, 4> {
62*58b9f456SAndroid Build Coastguard Worker   static constexpr const char* Names[] = {"Empty", "Small", "Large", "Huge"};
63*58b9f456SAndroid Build Coastguard Worker };
64*58b9f456SAndroid Build Coastguard Worker 
65*58b9f456SAndroid Build Coastguard Worker enum class Opacity { Opaque, Transparent };
66*58b9f456SAndroid Build Coastguard Worker struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
67*58b9f456SAndroid Build Coastguard Worker   static constexpr const char* Names[] = {"Opaque", "Transparent"};
68*58b9f456SAndroid Build Coastguard Worker };
69*58b9f456SAndroid Build Coastguard Worker 
70*58b9f456SAndroid Build Coastguard Worker enum class DiffType { Control, ChangeFirst, ChangeMiddle, ChangeLast };
71*58b9f456SAndroid Build Coastguard Worker struct AllDiffTypes : EnumValuesAsTuple<AllDiffTypes, DiffType, 4> {
72*58b9f456SAndroid Build Coastguard Worker   static constexpr const char* Names[] = {"Control", "ChangeFirst",
73*58b9f456SAndroid Build Coastguard Worker                                           "ChangeMiddle", "ChangeLast"};
74*58b9f456SAndroid Build Coastguard Worker };
75*58b9f456SAndroid Build Coastguard Worker 
getSmallString(DiffType D)76*58b9f456SAndroid Build Coastguard Worker TEST_ALWAYS_INLINE const char* getSmallString(DiffType D) {
77*58b9f456SAndroid Build Coastguard Worker   switch (D) {
78*58b9f456SAndroid Build Coastguard Worker     case DiffType::Control:
79*58b9f456SAndroid Build Coastguard Worker       return "0123456";
80*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeFirst:
81*58b9f456SAndroid Build Coastguard Worker       return "-123456";
82*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeMiddle:
83*58b9f456SAndroid Build Coastguard Worker       return "012-456";
84*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeLast:
85*58b9f456SAndroid Build Coastguard Worker       return "012345-";
86*58b9f456SAndroid Build Coastguard Worker   }
87*58b9f456SAndroid Build Coastguard Worker }
88*58b9f456SAndroid Build Coastguard Worker 
getLargeString(DiffType D)89*58b9f456SAndroid Build Coastguard Worker TEST_ALWAYS_INLINE const char* getLargeString(DiffType D) {
90*58b9f456SAndroid Build Coastguard Worker #define LARGE_STRING_FIRST "123456789012345678901234567890"
91*58b9f456SAndroid Build Coastguard Worker #define LARGE_STRING_SECOND "234567890123456789012345678901"
92*58b9f456SAndroid Build Coastguard Worker   switch (D) {
93*58b9f456SAndroid Build Coastguard Worker     case DiffType::Control:
94*58b9f456SAndroid Build Coastguard Worker       return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
95*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeFirst:
96*58b9f456SAndroid Build Coastguard Worker       return "-" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
97*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeMiddle:
98*58b9f456SAndroid Build Coastguard Worker       return "0" LARGE_STRING_FIRST "-" LARGE_STRING_SECOND "2";
99*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeLast:
100*58b9f456SAndroid Build Coastguard Worker       return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "-";
101*58b9f456SAndroid Build Coastguard Worker   }
102*58b9f456SAndroid Build Coastguard Worker }
103*58b9f456SAndroid Build Coastguard Worker 
getHugeString(DiffType D)104*58b9f456SAndroid Build Coastguard Worker TEST_ALWAYS_INLINE const char* getHugeString(DiffType D) {
105*58b9f456SAndroid Build Coastguard Worker #define HUGE_STRING0 "0123456789"
106*58b9f456SAndroid Build Coastguard Worker #define HUGE_STRING1 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0
107*58b9f456SAndroid Build Coastguard Worker #define HUGE_STRING2 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1
108*58b9f456SAndroid Build Coastguard Worker #define HUGE_STRING3 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2
109*58b9f456SAndroid Build Coastguard Worker #define HUGE_STRING4 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3
110*58b9f456SAndroid Build Coastguard Worker   switch (D) {
111*58b9f456SAndroid Build Coastguard Worker     case DiffType::Control:
112*58b9f456SAndroid Build Coastguard Worker       return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
113*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeFirst:
114*58b9f456SAndroid Build Coastguard Worker       return "-123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
115*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeMiddle:
116*58b9f456SAndroid Build Coastguard Worker       return "0123456789" HUGE_STRING4 "01234-6789" HUGE_STRING4 "0123456789";
117*58b9f456SAndroid Build Coastguard Worker     case DiffType::ChangeLast:
118*58b9f456SAndroid Build Coastguard Worker       return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "012345678-";
119*58b9f456SAndroid Build Coastguard Worker   }
120*58b9f456SAndroid Build Coastguard Worker }
121*58b9f456SAndroid Build Coastguard Worker 
makeString(Length L,DiffType D=DiffType::Control,Opacity O=Opacity::Transparent)122*58b9f456SAndroid Build Coastguard Worker TEST_ALWAYS_INLINE std::string makeString(Length L,
123*58b9f456SAndroid Build Coastguard Worker                                           DiffType D = DiffType::Control,
124*58b9f456SAndroid Build Coastguard Worker                                           Opacity O = Opacity::Transparent) {
125*58b9f456SAndroid Build Coastguard Worker   switch (L) {
126*58b9f456SAndroid Build Coastguard Worker   case Length::Empty:
127*58b9f456SAndroid Build Coastguard Worker     return maybeOpaque("", O == Opacity::Opaque);
128*58b9f456SAndroid Build Coastguard Worker   case Length::Small:
129*58b9f456SAndroid Build Coastguard Worker     return maybeOpaque(getSmallString(D), O == Opacity::Opaque);
130*58b9f456SAndroid Build Coastguard Worker   case Length::Large:
131*58b9f456SAndroid Build Coastguard Worker     return maybeOpaque(getLargeString(D), O == Opacity::Opaque);
132*58b9f456SAndroid Build Coastguard Worker   case Length::Huge:
133*58b9f456SAndroid Build Coastguard Worker     return maybeOpaque(getHugeString(D), O == Opacity::Opaque);
134*58b9f456SAndroid Build Coastguard Worker   }
135*58b9f456SAndroid Build Coastguard Worker }
136*58b9f456SAndroid Build Coastguard Worker 
137*58b9f456SAndroid Build Coastguard Worker template <class Length, class Opaque>
138*58b9f456SAndroid Build Coastguard Worker struct StringConstructDestroyCStr {
runStringConstructDestroyCStr139*58b9f456SAndroid Build Coastguard Worker   static void run(benchmark::State& state) {
140*58b9f456SAndroid Build Coastguard Worker     for (auto _ : state) {
141*58b9f456SAndroid Build Coastguard Worker       benchmark::DoNotOptimize(
142*58b9f456SAndroid Build Coastguard Worker           makeString(Length(), DiffType::Control, Opaque()));
143*58b9f456SAndroid Build Coastguard Worker     }
144*58b9f456SAndroid Build Coastguard Worker   }
145*58b9f456SAndroid Build Coastguard Worker 
nameStringConstructDestroyCStr146*58b9f456SAndroid Build Coastguard Worker   static std::string name() {
147*58b9f456SAndroid Build Coastguard Worker     return "BM_StringConstructDestroyCStr" + Length::name() + Opaque::name();
148*58b9f456SAndroid Build Coastguard Worker   }
149*58b9f456SAndroid Build Coastguard Worker };
150*58b9f456SAndroid Build Coastguard Worker 
151*58b9f456SAndroid Build Coastguard Worker template <class Length, bool MeasureCopy, bool MeasureDestroy>
StringCopyAndDestroy(benchmark::State & state)152*58b9f456SAndroid Build Coastguard Worker static void StringCopyAndDestroy(benchmark::State& state) {
153*58b9f456SAndroid Build Coastguard Worker   static constexpr size_t NumStrings = 1024;
154*58b9f456SAndroid Build Coastguard Worker   auto Orig = makeString(Length());
155*58b9f456SAndroid Build Coastguard Worker   std::aligned_storage<sizeof(std::string)>::type Storage[NumStrings];
156*58b9f456SAndroid Build Coastguard Worker 
157*58b9f456SAndroid Build Coastguard Worker   while (state.KeepRunningBatch(NumStrings)) {
158*58b9f456SAndroid Build Coastguard Worker     if (!MeasureCopy)
159*58b9f456SAndroid Build Coastguard Worker       state.PauseTiming();
160*58b9f456SAndroid Build Coastguard Worker     for (size_t I = 0; I < NumStrings; ++I) {
161*58b9f456SAndroid Build Coastguard Worker       ::new (static_cast<void*>(Storage + I)) std::string(Orig);
162*58b9f456SAndroid Build Coastguard Worker     }
163*58b9f456SAndroid Build Coastguard Worker     if (!MeasureCopy)
164*58b9f456SAndroid Build Coastguard Worker       state.ResumeTiming();
165*58b9f456SAndroid Build Coastguard Worker     if (!MeasureDestroy)
166*58b9f456SAndroid Build Coastguard Worker       state.PauseTiming();
167*58b9f456SAndroid Build Coastguard Worker     for (size_t I = 0; I < NumStrings; ++I) {
168*58b9f456SAndroid Build Coastguard Worker       using S = std::string;
169*58b9f456SAndroid Build Coastguard Worker       reinterpret_cast<S*>(Storage + I)->~S();
170*58b9f456SAndroid Build Coastguard Worker     }
171*58b9f456SAndroid Build Coastguard Worker     if (!MeasureDestroy)
172*58b9f456SAndroid Build Coastguard Worker       state.ResumeTiming();
173*58b9f456SAndroid Build Coastguard Worker   }
174*58b9f456SAndroid Build Coastguard Worker }
175*58b9f456SAndroid Build Coastguard Worker 
176*58b9f456SAndroid Build Coastguard Worker template <class Length>
177*58b9f456SAndroid Build Coastguard Worker struct StringCopy {
runStringCopy178*58b9f456SAndroid Build Coastguard Worker   static void run(benchmark::State& state) {
179*58b9f456SAndroid Build Coastguard Worker     StringCopyAndDestroy<Length, true, false>(state);
180*58b9f456SAndroid Build Coastguard Worker   }
181*58b9f456SAndroid Build Coastguard Worker 
nameStringCopy182*58b9f456SAndroid Build Coastguard Worker   static std::string name() { return "BM_StringCopy" + Length::name(); }
183*58b9f456SAndroid Build Coastguard Worker };
184*58b9f456SAndroid Build Coastguard Worker 
185*58b9f456SAndroid Build Coastguard Worker template <class Length>
186*58b9f456SAndroid Build Coastguard Worker struct StringDestroy {
runStringDestroy187*58b9f456SAndroid Build Coastguard Worker   static void run(benchmark::State& state) {
188*58b9f456SAndroid Build Coastguard Worker     StringCopyAndDestroy<Length, false, true>(state);
189*58b9f456SAndroid Build Coastguard Worker   }
190*58b9f456SAndroid Build Coastguard Worker 
nameStringDestroy191*58b9f456SAndroid Build Coastguard Worker   static std::string name() { return "BM_StringDestroy" + Length::name(); }
192*58b9f456SAndroid Build Coastguard Worker };
193*58b9f456SAndroid Build Coastguard Worker 
194*58b9f456SAndroid Build Coastguard Worker template <class Length>
195*58b9f456SAndroid Build Coastguard Worker struct StringMove {
runStringMove196*58b9f456SAndroid Build Coastguard Worker   static void run(benchmark::State& state) {
197*58b9f456SAndroid Build Coastguard Worker     // Keep two object locations and move construct back and forth.
198*58b9f456SAndroid Build Coastguard Worker     std::aligned_storage<sizeof(std::string), alignof(std::string)>::type Storage[2];
199*58b9f456SAndroid Build Coastguard Worker     using S = std::string;
200*58b9f456SAndroid Build Coastguard Worker     size_t I = 0;
201*58b9f456SAndroid Build Coastguard Worker     S *newS = new (static_cast<void*>(Storage)) std::string(makeString(Length()));
202*58b9f456SAndroid Build Coastguard Worker     for (auto _ : state) {
203*58b9f456SAndroid Build Coastguard Worker       // Switch locations.
204*58b9f456SAndroid Build Coastguard Worker       I ^= 1;
205*58b9f456SAndroid Build Coastguard Worker       benchmark::DoNotOptimize(Storage);
206*58b9f456SAndroid Build Coastguard Worker       // Move construct into the new location,
207*58b9f456SAndroid Build Coastguard Worker       S *tmpS = new (static_cast<void*>(Storage + I)) S(std::move(*newS));
208*58b9f456SAndroid Build Coastguard Worker       // then destroy the old one.
209*58b9f456SAndroid Build Coastguard Worker       newS->~S();
210*58b9f456SAndroid Build Coastguard Worker       newS = tmpS;
211*58b9f456SAndroid Build Coastguard Worker     }
212*58b9f456SAndroid Build Coastguard Worker     newS->~S();
213*58b9f456SAndroid Build Coastguard Worker   }
214*58b9f456SAndroid Build Coastguard Worker 
nameStringMove215*58b9f456SAndroid Build Coastguard Worker   static std::string name() { return "BM_StringMove" + Length::name(); }
216*58b9f456SAndroid Build Coastguard Worker };
217*58b9f456SAndroid Build Coastguard Worker 
218*58b9f456SAndroid Build Coastguard Worker enum class Relation { Eq, Less, Compare };
219*58b9f456SAndroid Build Coastguard Worker struct AllRelations : EnumValuesAsTuple<AllRelations, Relation, 3> {
220*58b9f456SAndroid Build Coastguard Worker   static constexpr const char* Names[] = {"Eq", "Less", "Compare"};
221*58b9f456SAndroid Build Coastguard Worker };
222*58b9f456SAndroid Build Coastguard Worker 
223*58b9f456SAndroid Build Coastguard Worker template <class Rel, class LHLength, class RHLength, class DiffType>
224*58b9f456SAndroid Build Coastguard Worker struct StringRelational {
runStringRelational225*58b9f456SAndroid Build Coastguard Worker   static void run(benchmark::State& state) {
226*58b9f456SAndroid Build Coastguard Worker     auto Lhs = makeString(RHLength());
227*58b9f456SAndroid Build Coastguard Worker     auto Rhs = makeString(LHLength(), DiffType());
228*58b9f456SAndroid Build Coastguard Worker     for (auto _ : state) {
229*58b9f456SAndroid Build Coastguard Worker       benchmark::DoNotOptimize(Lhs);
230*58b9f456SAndroid Build Coastguard Worker       benchmark::DoNotOptimize(Rhs);
231*58b9f456SAndroid Build Coastguard Worker       switch (Rel()) {
232*58b9f456SAndroid Build Coastguard Worker       case Relation::Eq:
233*58b9f456SAndroid Build Coastguard Worker         benchmark::DoNotOptimize(Lhs == Rhs);
234*58b9f456SAndroid Build Coastguard Worker         break;
235*58b9f456SAndroid Build Coastguard Worker       case Relation::Less:
236*58b9f456SAndroid Build Coastguard Worker         benchmark::DoNotOptimize(Lhs < Rhs);
237*58b9f456SAndroid Build Coastguard Worker         break;
238*58b9f456SAndroid Build Coastguard Worker       case Relation::Compare:
239*58b9f456SAndroid Build Coastguard Worker         benchmark::DoNotOptimize(Lhs.compare(Rhs));
240*58b9f456SAndroid Build Coastguard Worker         break;
241*58b9f456SAndroid Build Coastguard Worker       }
242*58b9f456SAndroid Build Coastguard Worker     }
243*58b9f456SAndroid Build Coastguard Worker   }
244*58b9f456SAndroid Build Coastguard Worker 
skipStringRelational245*58b9f456SAndroid Build Coastguard Worker   static bool skip() {
246*58b9f456SAndroid Build Coastguard Worker     // Eq is commutative, so skip half the matrix.
247*58b9f456SAndroid Build Coastguard Worker     if (Rel() == Relation::Eq && LHLength() > RHLength())
248*58b9f456SAndroid Build Coastguard Worker       return true;
249*58b9f456SAndroid Build Coastguard Worker     // We only care about control when the lengths differ.
250*58b9f456SAndroid Build Coastguard Worker     if (LHLength() != RHLength() && DiffType() != ::DiffType::Control)
251*58b9f456SAndroid Build Coastguard Worker       return true;
252*58b9f456SAndroid Build Coastguard Worker     // For empty, only control matters.
253*58b9f456SAndroid Build Coastguard Worker     if (LHLength() == Length::Empty && DiffType() != ::DiffType::Control)
254*58b9f456SAndroid Build Coastguard Worker       return true;
255*58b9f456SAndroid Build Coastguard Worker     return false;
256*58b9f456SAndroid Build Coastguard Worker   }
257*58b9f456SAndroid Build Coastguard Worker 
nameStringRelational258*58b9f456SAndroid Build Coastguard Worker   static std::string name() {
259*58b9f456SAndroid Build Coastguard Worker     return "BM_StringRelational" + Rel::name() + LHLength::name() +
260*58b9f456SAndroid Build Coastguard Worker            RHLength::name() + DiffType::name();
261*58b9f456SAndroid Build Coastguard Worker   }
262*58b9f456SAndroid Build Coastguard Worker };
263*58b9f456SAndroid Build Coastguard Worker 
264*58b9f456SAndroid Build Coastguard Worker enum class Depth { Shallow, Deep };
265*58b9f456SAndroid Build Coastguard Worker struct AllDepths : EnumValuesAsTuple<AllDepths, Depth, 2> {
266*58b9f456SAndroid Build Coastguard Worker   static constexpr const char* Names[] = {"Shallow", "Deep"};
267*58b9f456SAndroid Build Coastguard Worker };
268*58b9f456SAndroid Build Coastguard Worker 
269*58b9f456SAndroid Build Coastguard Worker enum class Temperature { Hot, Cold };
270*58b9f456SAndroid Build Coastguard Worker struct AllTemperatures : EnumValuesAsTuple<AllTemperatures, Temperature, 2> {
271*58b9f456SAndroid Build Coastguard Worker   static constexpr const char* Names[] = {"Hot", "Cold"};
272*58b9f456SAndroid Build Coastguard Worker };
273*58b9f456SAndroid Build Coastguard Worker 
274*58b9f456SAndroid Build Coastguard Worker template <class Temperature, class Depth, class Length>
275*58b9f456SAndroid Build Coastguard Worker struct StringRead {
runStringRead276*58b9f456SAndroid Build Coastguard Worker   void run(benchmark::State& state) const {
277*58b9f456SAndroid Build Coastguard Worker     static constexpr size_t NumStrings =
278*58b9f456SAndroid Build Coastguard Worker         Temperature() == ::Temperature::Hot
279*58b9f456SAndroid Build Coastguard Worker             ? 1 << 10
280*58b9f456SAndroid Build Coastguard Worker             : /* Enough strings to overflow the cache */ 1 << 20;
281*58b9f456SAndroid Build Coastguard Worker     static_assert((NumStrings & (NumStrings - 1)) == 0,
282*58b9f456SAndroid Build Coastguard Worker                   "NumStrings should be a power of two to reduce overhead.");
283*58b9f456SAndroid Build Coastguard Worker 
284*58b9f456SAndroid Build Coastguard Worker     std::vector<std::string> Values(NumStrings, makeString(Length()));
285*58b9f456SAndroid Build Coastguard Worker     size_t I = 0;
286*58b9f456SAndroid Build Coastguard Worker     for (auto _ : state) {
287*58b9f456SAndroid Build Coastguard Worker       // Jump long enough to defeat cache locality, and use a value that is
288*58b9f456SAndroid Build Coastguard Worker       // coprime with NumStrings to ensure we visit every element.
289*58b9f456SAndroid Build Coastguard Worker       I = (I + 17) % NumStrings;
290*58b9f456SAndroid Build Coastguard Worker       const auto& V = Values[I];
291*58b9f456SAndroid Build Coastguard Worker 
292*58b9f456SAndroid Build Coastguard Worker       // Read everything first. Escaping data() through DoNotOptimize might
293*58b9f456SAndroid Build Coastguard Worker       // cause the compiler to have to recalculate information about `V` due to
294*58b9f456SAndroid Build Coastguard Worker       // aliasing.
295*58b9f456SAndroid Build Coastguard Worker       const char* const Data = V.data();
296*58b9f456SAndroid Build Coastguard Worker       const size_t Size = V.size();
297*58b9f456SAndroid Build Coastguard Worker       benchmark::DoNotOptimize(Data);
298*58b9f456SAndroid Build Coastguard Worker       benchmark::DoNotOptimize(Size);
299*58b9f456SAndroid Build Coastguard Worker       if (Depth() == ::Depth::Deep) {
300*58b9f456SAndroid Build Coastguard Worker         // Read into the payload. This mainly shows the benefit of SSO when the
301*58b9f456SAndroid Build Coastguard Worker         // data is cold.
302*58b9f456SAndroid Build Coastguard Worker         benchmark::DoNotOptimize(*Data);
303*58b9f456SAndroid Build Coastguard Worker       }
304*58b9f456SAndroid Build Coastguard Worker     }
305*58b9f456SAndroid Build Coastguard Worker   }
306*58b9f456SAndroid Build Coastguard Worker 
skipStringRead307*58b9f456SAndroid Build Coastguard Worker   static bool skip() {
308*58b9f456SAndroid Build Coastguard Worker     // Huge does not give us anything that Large doesn't have. Skip it.
309*58b9f456SAndroid Build Coastguard Worker     if (Length() == ::Length::Huge) {
310*58b9f456SAndroid Build Coastguard Worker       return true;
311*58b9f456SAndroid Build Coastguard Worker     }
312*58b9f456SAndroid Build Coastguard Worker     return false;
313*58b9f456SAndroid Build Coastguard Worker   }
314*58b9f456SAndroid Build Coastguard Worker 
nameStringRead315*58b9f456SAndroid Build Coastguard Worker   std::string name() const {
316*58b9f456SAndroid Build Coastguard Worker     return "BM_StringRead" + Temperature::name() + Depth::name() +
317*58b9f456SAndroid Build Coastguard Worker            Length::name();
318*58b9f456SAndroid Build Coastguard Worker   }
319*58b9f456SAndroid Build Coastguard Worker };
320*58b9f456SAndroid Build Coastguard Worker 
sanityCheckGeneratedStrings()321*58b9f456SAndroid Build Coastguard Worker void sanityCheckGeneratedStrings() {
322*58b9f456SAndroid Build Coastguard Worker   for (auto Lhs : {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
323*58b9f456SAndroid Build Coastguard Worker     const auto LhsString = makeString(Lhs);
324*58b9f456SAndroid Build Coastguard Worker     for (auto Rhs :
325*58b9f456SAndroid Build Coastguard Worker          {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
326*58b9f456SAndroid Build Coastguard Worker       if (Lhs > Rhs)
327*58b9f456SAndroid Build Coastguard Worker         continue;
328*58b9f456SAndroid Build Coastguard Worker       const auto RhsString = makeString(Rhs);
329*58b9f456SAndroid Build Coastguard Worker 
330*58b9f456SAndroid Build Coastguard Worker       // The smaller one must be a prefix of the larger one.
331*58b9f456SAndroid Build Coastguard Worker       if (RhsString.find(LhsString) != 0) {
332*58b9f456SAndroid Build Coastguard Worker         fprintf(stderr, "Invalid autogenerated strings for sizes (%d,%d).\n",
333*58b9f456SAndroid Build Coastguard Worker                 static_cast<int>(Lhs), static_cast<int>(Rhs));
334*58b9f456SAndroid Build Coastguard Worker         std::abort();
335*58b9f456SAndroid Build Coastguard Worker       }
336*58b9f456SAndroid Build Coastguard Worker     }
337*58b9f456SAndroid Build Coastguard Worker   }
338*58b9f456SAndroid Build Coastguard Worker   // Verify the autogenerated diffs
339*58b9f456SAndroid Build Coastguard Worker   for (auto L : {Length::Small, Length::Large, Length::Huge}) {
340*58b9f456SAndroid Build Coastguard Worker     const auto Control = makeString(L);
341*58b9f456SAndroid Build Coastguard Worker     const auto Verify = [&](std::string Exp, size_t Pos) {
342*58b9f456SAndroid Build Coastguard Worker       // Only change on the Pos char.
343*58b9f456SAndroid Build Coastguard Worker       if (Control[Pos] != Exp[Pos]) {
344*58b9f456SAndroid Build Coastguard Worker         Exp[Pos] = Control[Pos];
345*58b9f456SAndroid Build Coastguard Worker         if (Control == Exp)
346*58b9f456SAndroid Build Coastguard Worker           return;
347*58b9f456SAndroid Build Coastguard Worker       }
348*58b9f456SAndroid Build Coastguard Worker       fprintf(stderr, "Invalid autogenerated diff with size %d\n",
349*58b9f456SAndroid Build Coastguard Worker               static_cast<int>(L));
350*58b9f456SAndroid Build Coastguard Worker       std::abort();
351*58b9f456SAndroid Build Coastguard Worker     };
352*58b9f456SAndroid Build Coastguard Worker     Verify(makeString(L, DiffType::ChangeFirst), 0);
353*58b9f456SAndroid Build Coastguard Worker     Verify(makeString(L, DiffType::ChangeMiddle), Control.size() / 2);
354*58b9f456SAndroid Build Coastguard Worker     Verify(makeString(L, DiffType::ChangeLast), Control.size() - 1);
355*58b9f456SAndroid Build Coastguard Worker   }
356*58b9f456SAndroid Build Coastguard Worker }
357*58b9f456SAndroid Build Coastguard Worker 
main(int argc,char ** argv)358*58b9f456SAndroid Build Coastguard Worker int main(int argc, char** argv) {
359*58b9f456SAndroid Build Coastguard Worker   benchmark::Initialize(&argc, argv);
360*58b9f456SAndroid Build Coastguard Worker   if (benchmark::ReportUnrecognizedArguments(argc, argv))
361*58b9f456SAndroid Build Coastguard Worker     return 1;
362*58b9f456SAndroid Build Coastguard Worker 
363*58b9f456SAndroid Build Coastguard Worker   sanityCheckGeneratedStrings();
364*58b9f456SAndroid Build Coastguard Worker 
365*58b9f456SAndroid Build Coastguard Worker   makeCartesianProductBenchmark<StringConstructDestroyCStr, AllLengths,
366*58b9f456SAndroid Build Coastguard Worker                                 AllOpacity>();
367*58b9f456SAndroid Build Coastguard Worker   makeCartesianProductBenchmark<StringCopy, AllLengths>();
368*58b9f456SAndroid Build Coastguard Worker   makeCartesianProductBenchmark<StringMove, AllLengths>();
369*58b9f456SAndroid Build Coastguard Worker   makeCartesianProductBenchmark<StringDestroy, AllLengths>();
370*58b9f456SAndroid Build Coastguard Worker   makeCartesianProductBenchmark<StringRelational, AllRelations, AllLengths,
371*58b9f456SAndroid Build Coastguard Worker                                 AllLengths, AllDiffTypes>();
372*58b9f456SAndroid Build Coastguard Worker   makeCartesianProductBenchmark<StringRead, AllTemperatures, AllDepths,
373*58b9f456SAndroid Build Coastguard Worker                                 AllLengths>();
374*58b9f456SAndroid Build Coastguard Worker   benchmark::RunSpecifiedBenchmarks();
375*58b9f456SAndroid Build Coastguard Worker }
376