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