xref: /aosp_15_r20/external/abseil-cpp/absl/flags/flag_benchmark.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker //
2*9356374aSAndroid Build Coastguard Worker // Copyright 2020 The Abseil Authors.
3*9356374aSAndroid Build Coastguard Worker //
4*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*9356374aSAndroid Build Coastguard Worker //
8*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
9*9356374aSAndroid Build Coastguard Worker //
10*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*9356374aSAndroid Build Coastguard Worker // limitations under the License.
15*9356374aSAndroid Build Coastguard Worker 
16*9356374aSAndroid Build Coastguard Worker #include <stdint.h>
17*9356374aSAndroid Build Coastguard Worker 
18*9356374aSAndroid Build Coastguard Worker #include <string>
19*9356374aSAndroid Build Coastguard Worker #include <vector>
20*9356374aSAndroid Build Coastguard Worker 
21*9356374aSAndroid Build Coastguard Worker #include "absl/flags/flag.h"
22*9356374aSAndroid Build Coastguard Worker #include "absl/flags/marshalling.h"
23*9356374aSAndroid Build Coastguard Worker #include "absl/flags/parse.h"
24*9356374aSAndroid Build Coastguard Worker #include "absl/flags/reflection.h"
25*9356374aSAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
26*9356374aSAndroid Build Coastguard Worker #include "absl/time/time.h"
27*9356374aSAndroid Build Coastguard Worker #include "absl/types/optional.h"
28*9356374aSAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
29*9356374aSAndroid Build Coastguard Worker 
30*9356374aSAndroid Build Coastguard Worker namespace {
31*9356374aSAndroid Build Coastguard Worker using String = std::string;
32*9356374aSAndroid Build Coastguard Worker using VectorOfStrings = std::vector<std::string>;
33*9356374aSAndroid Build Coastguard Worker using AbslDuration = absl::Duration;
34*9356374aSAndroid Build Coastguard Worker 
35*9356374aSAndroid Build Coastguard Worker // We do not want to take over marshalling for the types absl::optional<int>,
36*9356374aSAndroid Build Coastguard Worker // absl::optional<std::string> which we do not own. Instead we introduce unique
37*9356374aSAndroid Build Coastguard Worker // "aliases" to these types, which we do.
38*9356374aSAndroid Build Coastguard Worker using AbslOptionalInt = absl::optional<int>;
39*9356374aSAndroid Build Coastguard Worker struct OptionalInt : AbslOptionalInt {
40*9356374aSAndroid Build Coastguard Worker   using AbslOptionalInt::AbslOptionalInt;
41*9356374aSAndroid Build Coastguard Worker };
42*9356374aSAndroid Build Coastguard Worker // Next two functions represent Abseil Flags marshalling for OptionalInt.
AbslParseFlag(absl::string_view src,OptionalInt * flag,std::string * error)43*9356374aSAndroid Build Coastguard Worker bool AbslParseFlag(absl::string_view src, OptionalInt* flag,
44*9356374aSAndroid Build Coastguard Worker                    std::string* error) {
45*9356374aSAndroid Build Coastguard Worker   int val;
46*9356374aSAndroid Build Coastguard Worker   if (src.empty())
47*9356374aSAndroid Build Coastguard Worker     flag->reset();
48*9356374aSAndroid Build Coastguard Worker   else if (!absl::ParseFlag(src, &val, error))
49*9356374aSAndroid Build Coastguard Worker     return false;
50*9356374aSAndroid Build Coastguard Worker   *flag = val;
51*9356374aSAndroid Build Coastguard Worker   return true;
52*9356374aSAndroid Build Coastguard Worker }
AbslUnparseFlag(const OptionalInt & flag)53*9356374aSAndroid Build Coastguard Worker std::string AbslUnparseFlag(const OptionalInt& flag) {
54*9356374aSAndroid Build Coastguard Worker   return !flag ? "" : absl::UnparseFlag(*flag);
55*9356374aSAndroid Build Coastguard Worker }
56*9356374aSAndroid Build Coastguard Worker 
57*9356374aSAndroid Build Coastguard Worker using AbslOptionalString = absl::optional<std::string>;
58*9356374aSAndroid Build Coastguard Worker struct OptionalString : AbslOptionalString {
59*9356374aSAndroid Build Coastguard Worker   using AbslOptionalString::AbslOptionalString;
60*9356374aSAndroid Build Coastguard Worker };
61*9356374aSAndroid Build Coastguard Worker // Next two functions represent Abseil Flags marshalling for OptionalString.
AbslParseFlag(absl::string_view src,OptionalString * flag,std::string * error)62*9356374aSAndroid Build Coastguard Worker bool AbslParseFlag(absl::string_view src, OptionalString* flag,
63*9356374aSAndroid Build Coastguard Worker                    std::string* error) {
64*9356374aSAndroid Build Coastguard Worker   std::string val;
65*9356374aSAndroid Build Coastguard Worker   if (src.empty())
66*9356374aSAndroid Build Coastguard Worker     flag->reset();
67*9356374aSAndroid Build Coastguard Worker   else if (!absl::ParseFlag(src, &val, error))
68*9356374aSAndroid Build Coastguard Worker     return false;
69*9356374aSAndroid Build Coastguard Worker   *flag = val;
70*9356374aSAndroid Build Coastguard Worker   return true;
71*9356374aSAndroid Build Coastguard Worker }
AbslUnparseFlag(const OptionalString & flag)72*9356374aSAndroid Build Coastguard Worker std::string AbslUnparseFlag(const OptionalString& flag) {
73*9356374aSAndroid Build Coastguard Worker   return !flag ? "" : absl::UnparseFlag(*flag);
74*9356374aSAndroid Build Coastguard Worker }
75*9356374aSAndroid Build Coastguard Worker 
76*9356374aSAndroid Build Coastguard Worker struct UDT {
77*9356374aSAndroid Build Coastguard Worker   UDT() = default;
UDT__anon9f4c3b3b0111::UDT78*9356374aSAndroid Build Coastguard Worker   UDT(const UDT&) {}
operator =__anon9f4c3b3b0111::UDT79*9356374aSAndroid Build Coastguard Worker   UDT& operator=(const UDT&) { return *this; }
80*9356374aSAndroid Build Coastguard Worker };
81*9356374aSAndroid Build Coastguard Worker // Next two functions represent Abseil Flags marshalling for UDT.
AbslParseFlag(absl::string_view,UDT *,std::string *)82*9356374aSAndroid Build Coastguard Worker bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
AbslUnparseFlag(const UDT &)83*9356374aSAndroid Build Coastguard Worker std::string AbslUnparseFlag(const UDT&) { return ""; }
84*9356374aSAndroid Build Coastguard Worker 
85*9356374aSAndroid Build Coastguard Worker }  // namespace
86*9356374aSAndroid Build Coastguard Worker 
87*9356374aSAndroid Build Coastguard Worker #define BENCHMARKED_TYPES(A) \
88*9356374aSAndroid Build Coastguard Worker   A(bool)                    \
89*9356374aSAndroid Build Coastguard Worker   A(int16_t)                 \
90*9356374aSAndroid Build Coastguard Worker   A(uint16_t)                \
91*9356374aSAndroid Build Coastguard Worker   A(int32_t)                 \
92*9356374aSAndroid Build Coastguard Worker   A(uint32_t)                \
93*9356374aSAndroid Build Coastguard Worker   A(int64_t)                 \
94*9356374aSAndroid Build Coastguard Worker   A(uint64_t)                \
95*9356374aSAndroid Build Coastguard Worker   A(double)                  \
96*9356374aSAndroid Build Coastguard Worker   A(float)                   \
97*9356374aSAndroid Build Coastguard Worker   A(String)                  \
98*9356374aSAndroid Build Coastguard Worker   A(VectorOfStrings)         \
99*9356374aSAndroid Build Coastguard Worker   A(OptionalInt)             \
100*9356374aSAndroid Build Coastguard Worker   A(OptionalString)          \
101*9356374aSAndroid Build Coastguard Worker   A(AbslDuration)            \
102*9356374aSAndroid Build Coastguard Worker   A(UDT)
103*9356374aSAndroid Build Coastguard Worker 
104*9356374aSAndroid Build Coastguard Worker #define REPLICATE_0(A, T, name, index) A(T, name, index)
105*9356374aSAndroid Build Coastguard Worker #define REPLICATE_1(A, T, name, index) \
106*9356374aSAndroid Build Coastguard Worker   REPLICATE_0(A, T, name, index##0) REPLICATE_0(A, T, name, index##1)
107*9356374aSAndroid Build Coastguard Worker #define REPLICATE_2(A, T, name, index) \
108*9356374aSAndroid Build Coastguard Worker   REPLICATE_1(A, T, name, index##0) REPLICATE_1(A, T, name, index##1)
109*9356374aSAndroid Build Coastguard Worker #define REPLICATE_3(A, T, name, index) \
110*9356374aSAndroid Build Coastguard Worker   REPLICATE_2(A, T, name, index##0) REPLICATE_2(A, T, name, index##1)
111*9356374aSAndroid Build Coastguard Worker #define REPLICATE_4(A, T, name, index) \
112*9356374aSAndroid Build Coastguard Worker   REPLICATE_3(A, T, name, index##0) REPLICATE_3(A, T, name, index##1)
113*9356374aSAndroid Build Coastguard Worker #define REPLICATE_5(A, T, name, index) \
114*9356374aSAndroid Build Coastguard Worker   REPLICATE_4(A, T, name, index##0) REPLICATE_4(A, T, name, index##1)
115*9356374aSAndroid Build Coastguard Worker #define REPLICATE_6(A, T, name, index) \
116*9356374aSAndroid Build Coastguard Worker   REPLICATE_5(A, T, name, index##0) REPLICATE_5(A, T, name, index##1)
117*9356374aSAndroid Build Coastguard Worker #define REPLICATE_7(A, T, name, index) \
118*9356374aSAndroid Build Coastguard Worker   REPLICATE_6(A, T, name, index##0) REPLICATE_6(A, T, name, index##1)
119*9356374aSAndroid Build Coastguard Worker #define REPLICATE_8(A, T, name, index) \
120*9356374aSAndroid Build Coastguard Worker   REPLICATE_7(A, T, name, index##0) REPLICATE_7(A, T, name, index##1)
121*9356374aSAndroid Build Coastguard Worker #define REPLICATE_9(A, T, name, index) \
122*9356374aSAndroid Build Coastguard Worker   REPLICATE_8(A, T, name, index##0) REPLICATE_8(A, T, name, index##1)
123*9356374aSAndroid Build Coastguard Worker #if defined(_MSC_VER)
124*9356374aSAndroid Build Coastguard Worker #define REPLICATE(A, T, name) \
125*9356374aSAndroid Build Coastguard Worker   REPLICATE_7(A, T, name, 0) REPLICATE_7(A, T, name, 1)
126*9356374aSAndroid Build Coastguard Worker #define SINGLE_FLAG(T) FLAGS_##T##_flag_00000000
127*9356374aSAndroid Build Coastguard Worker #else
128*9356374aSAndroid Build Coastguard Worker #define REPLICATE(A, T, name) \
129*9356374aSAndroid Build Coastguard Worker   REPLICATE_9(A, T, name, 0) REPLICATE_9(A, T, name, 1)
130*9356374aSAndroid Build Coastguard Worker #define SINGLE_FLAG(T) FLAGS_##T##_flag_0000000000
131*9356374aSAndroid Build Coastguard Worker #endif
132*9356374aSAndroid Build Coastguard Worker #define REPLICATE_ALL(A, T, name) \
133*9356374aSAndroid Build Coastguard Worker   REPLICATE_9(A, T, name, 0) REPLICATE_9(A, T, name, 1)
134*9356374aSAndroid Build Coastguard Worker 
135*9356374aSAndroid Build Coastguard Worker #define COUNT(T, name, index) +1
136*9356374aSAndroid Build Coastguard Worker constexpr size_t kNumFlags = 0 REPLICATE(COUNT, _, _);
137*9356374aSAndroid Build Coastguard Worker 
138*9356374aSAndroid Build Coastguard Worker #if defined(__clang__) && defined(__linux__)
139*9356374aSAndroid Build Coastguard Worker // Force the flags used for benchmarks into a separate ELF section.
140*9356374aSAndroid Build Coastguard Worker // This ensures that, even when other parts of the code might change size,
141*9356374aSAndroid Build Coastguard Worker // the layout of the flags across cachelines is kept constant. This makes
142*9356374aSAndroid Build Coastguard Worker // benchmark results more reproducible across unrelated code changes.
143*9356374aSAndroid Build Coastguard Worker #pragma clang section data = ".benchmark_flags"
144*9356374aSAndroid Build Coastguard Worker #endif
145*9356374aSAndroid Build Coastguard Worker #define DEFINE_FLAG(T, name, index) ABSL_FLAG(T, name##_##index, {}, "");
146*9356374aSAndroid Build Coastguard Worker #define FLAG_DEF(T) REPLICATE(DEFINE_FLAG, T, T##_flag)
147*9356374aSAndroid Build Coastguard Worker BENCHMARKED_TYPES(FLAG_DEF)
148*9356374aSAndroid Build Coastguard Worker #if defined(__clang__) && defined(__linux__)
149*9356374aSAndroid Build Coastguard Worker #pragma clang section data = ""
150*9356374aSAndroid Build Coastguard Worker #endif
151*9356374aSAndroid Build Coastguard Worker // Register thousands of flags to bloat up the size of the registry.
152*9356374aSAndroid Build Coastguard Worker // This mimics real life production binaries.
153*9356374aSAndroid Build Coastguard Worker #define BLOAT_FLAG(_unused1, _unused2, index) \
154*9356374aSAndroid Build Coastguard Worker   ABSL_FLAG(int, bloat_flag_##index, 0, "");
155*9356374aSAndroid Build Coastguard Worker REPLICATE_ALL(BLOAT_FLAG, _, _)
156*9356374aSAndroid Build Coastguard Worker 
157*9356374aSAndroid Build Coastguard Worker namespace {
158*9356374aSAndroid Build Coastguard Worker 
159*9356374aSAndroid Build Coastguard Worker #define FLAG_PTR(T, name, index) &FLAGS_##name##_##index,
160*9356374aSAndroid Build Coastguard Worker #define FLAG_PTR_ARR(T)                              \
161*9356374aSAndroid Build Coastguard Worker   static constexpr absl::Flag<T>* FlagPtrs_##T[] = { \
162*9356374aSAndroid Build Coastguard Worker       REPLICATE(FLAG_PTR, T, T##_flag)};
163*9356374aSAndroid Build Coastguard Worker BENCHMARKED_TYPES(FLAG_PTR_ARR)
164*9356374aSAndroid Build Coastguard Worker 
165*9356374aSAndroid Build Coastguard Worker #define BM_SingleGetFlag(T)                                    \
166*9356374aSAndroid Build Coastguard Worker   void BM_SingleGetFlag_##T(benchmark::State& state) {         \
167*9356374aSAndroid Build Coastguard Worker     for (auto _ : state) {                                     \
168*9356374aSAndroid Build Coastguard Worker       benchmark::DoNotOptimize(absl::GetFlag(SINGLE_FLAG(T))); \
169*9356374aSAndroid Build Coastguard Worker     }                                                          \
170*9356374aSAndroid Build Coastguard Worker   }                                                            \
171*9356374aSAndroid Build Coastguard Worker   BENCHMARK(BM_SingleGetFlag_##T)->ThreadRange(1, 16);
172*9356374aSAndroid Build Coastguard Worker 
173*9356374aSAndroid Build Coastguard Worker BENCHMARKED_TYPES(BM_SingleGetFlag)
174*9356374aSAndroid Build Coastguard Worker 
175*9356374aSAndroid Build Coastguard Worker template <typename T>
176*9356374aSAndroid Build Coastguard Worker struct Accumulator {
177*9356374aSAndroid Build Coastguard Worker   using type = T;
178*9356374aSAndroid Build Coastguard Worker };
179*9356374aSAndroid Build Coastguard Worker template <>
180*9356374aSAndroid Build Coastguard Worker struct Accumulator<String> {
181*9356374aSAndroid Build Coastguard Worker   using type = size_t;
182*9356374aSAndroid Build Coastguard Worker };
183*9356374aSAndroid Build Coastguard Worker template <>
184*9356374aSAndroid Build Coastguard Worker struct Accumulator<VectorOfStrings> {
185*9356374aSAndroid Build Coastguard Worker   using type = size_t;
186*9356374aSAndroid Build Coastguard Worker };
187*9356374aSAndroid Build Coastguard Worker template <>
188*9356374aSAndroid Build Coastguard Worker struct Accumulator<OptionalInt> {
189*9356374aSAndroid Build Coastguard Worker   using type = bool;
190*9356374aSAndroid Build Coastguard Worker };
191*9356374aSAndroid Build Coastguard Worker template <>
192*9356374aSAndroid Build Coastguard Worker struct Accumulator<OptionalString> {
193*9356374aSAndroid Build Coastguard Worker   using type = bool;
194*9356374aSAndroid Build Coastguard Worker };
195*9356374aSAndroid Build Coastguard Worker template <>
196*9356374aSAndroid Build Coastguard Worker struct Accumulator<UDT> {
197*9356374aSAndroid Build Coastguard Worker   using type = bool;
198*9356374aSAndroid Build Coastguard Worker };
199*9356374aSAndroid Build Coastguard Worker 
200*9356374aSAndroid Build Coastguard Worker template <typename T>
Accumulate(typename Accumulator<T>::type & a,const T & f)201*9356374aSAndroid Build Coastguard Worker void Accumulate(typename Accumulator<T>::type& a, const T& f) {
202*9356374aSAndroid Build Coastguard Worker   a += f;
203*9356374aSAndroid Build Coastguard Worker }
Accumulate(bool & a,bool f)204*9356374aSAndroid Build Coastguard Worker void Accumulate(bool& a, bool f) { a = a || f; }
Accumulate(size_t & a,const std::string & f)205*9356374aSAndroid Build Coastguard Worker void Accumulate(size_t& a, const std::string& f) { a += f.size(); }
Accumulate(size_t & a,const std::vector<std::string> & f)206*9356374aSAndroid Build Coastguard Worker void Accumulate(size_t& a, const std::vector<std::string>& f) { a += f.size(); }
Accumulate(bool & a,const OptionalInt & f)207*9356374aSAndroid Build Coastguard Worker void Accumulate(bool& a, const OptionalInt& f) { a |= f.has_value(); }
Accumulate(bool & a,const OptionalString & f)208*9356374aSAndroid Build Coastguard Worker void Accumulate(bool& a, const OptionalString& f) { a |= f.has_value(); }
Accumulate(bool & a,const UDT & f)209*9356374aSAndroid Build Coastguard Worker void Accumulate(bool& a, const UDT& f) {
210*9356374aSAndroid Build Coastguard Worker   a |= reinterpret_cast<int64_t>(&f) & 0x1;
211*9356374aSAndroid Build Coastguard Worker }
212*9356374aSAndroid Build Coastguard Worker 
213*9356374aSAndroid Build Coastguard Worker #define BM_ManyGetFlag(T)                            \
214*9356374aSAndroid Build Coastguard Worker   void BM_ManyGetFlag_##T(benchmark::State& state) { \
215*9356374aSAndroid Build Coastguard Worker     Accumulator<T>::type res = {};                   \
216*9356374aSAndroid Build Coastguard Worker     while (state.KeepRunningBatch(kNumFlags)) {      \
217*9356374aSAndroid Build Coastguard Worker       for (auto* flag_ptr : FlagPtrs_##T) {          \
218*9356374aSAndroid Build Coastguard Worker         Accumulate(res, absl::GetFlag(*flag_ptr));   \
219*9356374aSAndroid Build Coastguard Worker       }                                              \
220*9356374aSAndroid Build Coastguard Worker     }                                                \
221*9356374aSAndroid Build Coastguard Worker     benchmark::DoNotOptimize(res);                   \
222*9356374aSAndroid Build Coastguard Worker   }                                                  \
223*9356374aSAndroid Build Coastguard Worker   BENCHMARK(BM_ManyGetFlag_##T)->ThreadRange(1, 8);
224*9356374aSAndroid Build Coastguard Worker 
BENCHMARKED_TYPES(BM_ManyGetFlag)225*9356374aSAndroid Build Coastguard Worker BENCHMARKED_TYPES(BM_ManyGetFlag)
226*9356374aSAndroid Build Coastguard Worker 
227*9356374aSAndroid Build Coastguard Worker void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
228*9356374aSAndroid Build Coastguard Worker   char dummy[] = "dummy";
229*9356374aSAndroid Build Coastguard Worker   char* argv[] = {dummy};
230*9356374aSAndroid Build Coastguard Worker   // We need to ensure that flags have been parsed. That is where the registry
231*9356374aSAndroid Build Coastguard Worker   // is finalized.
232*9356374aSAndroid Build Coastguard Worker   absl::ParseCommandLine(1, argv);
233*9356374aSAndroid Build Coastguard Worker 
234*9356374aSAndroid Build Coastguard Worker   while (state.KeepRunningBatch(kNumFlags)) {
235*9356374aSAndroid Build Coastguard Worker     for (auto* flag_ptr : FlagPtrs_bool) {
236*9356374aSAndroid Build Coastguard Worker       benchmark::DoNotOptimize(absl::FindCommandLineFlag(flag_ptr->Name()));
237*9356374aSAndroid Build Coastguard Worker     }
238*9356374aSAndroid Build Coastguard Worker   }
239*9356374aSAndroid Build Coastguard Worker }
240*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
241*9356374aSAndroid Build Coastguard Worker 
242*9356374aSAndroid Build Coastguard Worker }  // namespace
243*9356374aSAndroid Build Coastguard Worker 
244*9356374aSAndroid Build Coastguard Worker #ifdef __llvm__
245*9356374aSAndroid Build Coastguard Worker // To view disassembly use: gdb ${BINARY}  -batch -ex "disassemble /s $FUNC"
246*9356374aSAndroid Build Coastguard Worker #define InvokeGetFlag(T)                                             \
247*9356374aSAndroid Build Coastguard Worker   T AbslInvokeGetFlag##T() { return absl::GetFlag(SINGLE_FLAG(T)); } \
248*9356374aSAndroid Build Coastguard Worker   int odr##T = (benchmark::DoNotOptimize(AbslInvokeGetFlag##T), 1);
249*9356374aSAndroid Build Coastguard Worker 
250*9356374aSAndroid Build Coastguard Worker BENCHMARKED_TYPES(InvokeGetFlag)
251*9356374aSAndroid Build Coastguard Worker #endif  // __llvm__
252