tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

flag_benchmark.cc (8799B)


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