tor-browser

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

str_cat_benchmark.cc (8626B)


      1 // Copyright 2018 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <array>
     16 #include <cstdint>
     17 #include <cstdio>
     18 #include <cstdlib>
     19 #include <cstring>
     20 #include <string>
     21 #include <tuple>
     22 #include <utility>
     23 
     24 #include "absl/random/log_uniform_int_distribution.h"
     25 #include "absl/random/random.h"
     26 #include "absl/strings/str_cat.h"
     27 #include "absl/strings/str_format.h"
     28 #include "absl/strings/string_view.h"
     29 #include "absl/strings/substitute.h"
     30 #include "benchmark/benchmark.h"
     31 
     32 namespace {
     33 
     34 const char kStringOne[] = "Once Upon A Time, ";
     35 const char kStringTwo[] = "There was a string benchmark";
     36 
     37 // We want to include negative numbers in the benchmark, so this function
     38 // is used to count 0, 1, -1, 2, -2, 3, -3, ...
     39 inline int IncrementAlternatingSign(int i) {
     40  return i > 0 ? -i : 1 - i;
     41 }
     42 
     43 void BM_Sum_By_StrCat(benchmark::State& state) {
     44  int i = 0;
     45  char foo[100];
     46  for (auto _ : state) {
     47    // NOLINTNEXTLINE(runtime/printf)
     48    strcpy(foo, absl::StrCat(kStringOne, i, kStringTwo, i * 65536ULL).c_str());
     49    int sum = 0;
     50    for (char* f = &foo[0]; *f != 0; ++f) {
     51      sum += *f;
     52    }
     53    benchmark::DoNotOptimize(sum);
     54    i = IncrementAlternatingSign(i);
     55  }
     56 }
     57 BENCHMARK(BM_Sum_By_StrCat);
     58 
     59 void BM_StrCat_By_snprintf(benchmark::State& state) {
     60  int i = 0;
     61  char on_stack[1000];
     62  for (auto _ : state) {
     63    snprintf(on_stack, sizeof(on_stack), "%s %s:%d", kStringOne, kStringTwo, i);
     64    i = IncrementAlternatingSign(i);
     65  }
     66 }
     67 BENCHMARK(BM_StrCat_By_snprintf);
     68 
     69 void BM_StrCat_By_Strings(benchmark::State& state) {
     70  int i = 0;
     71  for (auto _ : state) {
     72    std::string result =
     73        std::string(kStringOne) + " " + kStringTwo + ":" + absl::StrCat(i);
     74    benchmark::DoNotOptimize(result);
     75    i = IncrementAlternatingSign(i);
     76  }
     77 }
     78 BENCHMARK(BM_StrCat_By_Strings);
     79 
     80 void BM_StrCat_By_StringOpPlus(benchmark::State& state) {
     81  int i = 0;
     82  for (auto _ : state) {
     83    std::string result = kStringOne;
     84    result += " ";
     85    result += kStringTwo;
     86    result += ":";
     87    result += absl::StrCat(i);
     88    benchmark::DoNotOptimize(result);
     89    i = IncrementAlternatingSign(i);
     90  }
     91 }
     92 BENCHMARK(BM_StrCat_By_StringOpPlus);
     93 
     94 void BM_StrCat_By_StrCat(benchmark::State& state) {
     95  int i = 0;
     96  for (auto _ : state) {
     97    std::string result = absl::StrCat(kStringOne, " ", kStringTwo, ":", i);
     98    benchmark::DoNotOptimize(result);
     99    i = IncrementAlternatingSign(i);
    100  }
    101 }
    102 BENCHMARK(BM_StrCat_By_StrCat);
    103 
    104 void BM_HexCat_By_StrCat(benchmark::State& state) {
    105  int i = 0;
    106  for (auto _ : state) {
    107    std::string result =
    108        absl::StrCat(kStringOne, " ", absl::Hex(int64_t{i} + 0x10000000));
    109    benchmark::DoNotOptimize(result);
    110    i = IncrementAlternatingSign(i);
    111  }
    112 }
    113 BENCHMARK(BM_HexCat_By_StrCat);
    114 
    115 void BM_HexCat_By_StrFormat(benchmark::State& state) {
    116  int i = 0;
    117  for (auto _ : state) {
    118    std::string result =
    119        absl::StrFormat("%s %x", kStringOne, int64_t{i} + 0x10000000);
    120    benchmark::DoNotOptimize(result);
    121    i = IncrementAlternatingSign(i);
    122  }
    123 }
    124 BENCHMARK(BM_HexCat_By_StrFormat);
    125 
    126 void BM_HexCat_By_Substitute(benchmark::State& state) {
    127  int i = 0;
    128  for (auto _ : state) {
    129    std::string result = absl::Substitute(
    130        "$0 $1", kStringOne, reinterpret_cast<void*>(int64_t{i} + 0x10000000));
    131    benchmark::DoNotOptimize(result);
    132    i = IncrementAlternatingSign(i);
    133  }
    134 }
    135 BENCHMARK(BM_HexCat_By_Substitute);
    136 
    137 void BM_FloatToString_By_StrCat(benchmark::State& state) {
    138  int i = 0;
    139  float foo = 0.0f;
    140  for (auto _ : state) {
    141    std::string result = absl::StrCat(foo += 1.001f, " != ", int64_t{i});
    142    benchmark::DoNotOptimize(result);
    143    i = IncrementAlternatingSign(i);
    144  }
    145 }
    146 BENCHMARK(BM_FloatToString_By_StrCat);
    147 
    148 void BM_DoubleToString_By_SixDigits(benchmark::State& state) {
    149  int i = 0;
    150  double foo = 0.0;
    151  for (auto _ : state) {
    152    std::string result =
    153        absl::StrCat(absl::SixDigits(foo += 1.001), " != ", int64_t{i});
    154    benchmark::DoNotOptimize(result);
    155    i = IncrementAlternatingSign(i);
    156  }
    157 }
    158 BENCHMARK(BM_DoubleToString_By_SixDigits);
    159 
    160 void BM_FloatToString_By_StrFormat(benchmark::State& state) {
    161  int i = 0;
    162  float foo = 0.0f;
    163  for (auto _ : state) {
    164    std::string result =
    165        absl::StrFormat("%f != %lld", foo += 1.001f, int64_t{i});
    166    benchmark::DoNotOptimize(result);
    167    i = IncrementAlternatingSign(i);
    168  }
    169 }
    170 BENCHMARK(BM_FloatToString_By_StrFormat);
    171 
    172 template <typename Table, size_t... Index>
    173 void BM_StrAppendImpl(benchmark::State& state, Table table, size_t total_bytes,
    174                      std::index_sequence<Index...>) {
    175  for (auto s : state) {
    176    const size_t table_size = table.size();
    177    size_t i = 0;
    178    std::string result;
    179    while (result.size() < total_bytes) {
    180      absl::StrAppend(&result, std::get<Index>(table[i])...);
    181      benchmark::DoNotOptimize(result);
    182      ++i;
    183      i -= i >= table_size ? table_size : 0;
    184    }
    185  }
    186 }
    187 
    188 template <typename Array>
    189 void BM_StrAppend(benchmark::State& state, Array&& table) {
    190  const size_t total_bytes = state.range(0);
    191  const int chunks_at_a_time = state.range(1);
    192 
    193  switch (chunks_at_a_time) {
    194    case 1:
    195      return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
    196                              std::make_index_sequence<1>());
    197    case 2:
    198      return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
    199                              std::make_index_sequence<2>());
    200    case 4:
    201      return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
    202                              std::make_index_sequence<4>());
    203    case 8:
    204      return BM_StrAppendImpl(state, std::forward<Array>(table), total_bytes,
    205                              std::make_index_sequence<8>());
    206    default:
    207      std::abort();
    208  }
    209 }
    210 
    211 void BM_StrAppendStr(benchmark::State& state) {
    212  using T = absl::string_view;
    213  using Row = std::tuple<T, T, T, T, T, T, T, T>;
    214  constexpr absl::string_view kChunk = "0123456789";
    215  Row row = {kChunk, kChunk, kChunk, kChunk, kChunk, kChunk, kChunk, kChunk};
    216  return BM_StrAppend(state, std::array<Row, 1>({row}));
    217 }
    218 
    219 template <typename T>
    220 void BM_StrAppendInt(benchmark::State& state) {
    221  absl::BitGen rng;
    222  absl::log_uniform_int_distribution<T> dist;
    223  std::array<std::tuple<T, T, T, T, T, T, T, T>, (1 << 7)> table;
    224  for (size_t i = 0; i < table.size(); ++i) {
    225    table[i] = {dist(rng), dist(rng), dist(rng), dist(rng),
    226                dist(rng), dist(rng), dist(rng), dist(rng)};
    227  }
    228  return BM_StrAppend(state, table);
    229 }
    230 
    231 template <typename B>
    232 void StrAppendConfig(B* benchmark) {
    233  for (int bytes : {10, 100, 1000, 10000}) {
    234    for (int chunks : {1, 2, 4, 8}) {
    235      // Only add the ones that divide properly. Otherwise we are over counting.
    236      if (bytes % (10 * chunks) == 0) {
    237        benchmark->Args({bytes, chunks});
    238      }
    239    }
    240  }
    241 }
    242 
    243 BENCHMARK(BM_StrAppendStr)->Apply(StrAppendConfig);
    244 BENCHMARK(BM_StrAppendInt<int64_t>)->Apply(StrAppendConfig);
    245 BENCHMARK(BM_StrAppendInt<uint64_t>)->Apply(StrAppendConfig);
    246 BENCHMARK(BM_StrAppendInt<int32_t>)->Apply(StrAppendConfig);
    247 BENCHMARK(BM_StrAppendInt<uint32_t>)->Apply(StrAppendConfig);
    248 
    249 template <typename... Chunks>
    250 void BM_StrCatImpl(benchmark::State& state,
    251                      Chunks... chunks) {
    252  for (auto s : state) {
    253    std::string result = absl::StrCat(chunks...);
    254    benchmark::DoNotOptimize(result);
    255  }
    256 }
    257 
    258 void BM_StrCat(benchmark::State& state) {
    259  const int chunks_at_a_time = state.range(0);
    260  const absl::string_view kChunk = "0123456789";
    261 
    262  switch (chunks_at_a_time) {
    263    case 1:
    264      return BM_StrCatImpl(state, kChunk);
    265    case 2:
    266      return BM_StrCatImpl(state, kChunk, kChunk);
    267    case 3:
    268      return BM_StrCatImpl(state, kChunk, kChunk, kChunk);
    269    case 4:
    270      return BM_StrCatImpl(state, kChunk, kChunk, kChunk, kChunk);
    271    default:
    272      std::abort();
    273  }
    274 }
    275 
    276 BENCHMARK(BM_StrCat)->Arg(1)->Arg(2)->Arg(3)->Arg(4);
    277 
    278 void BM_StrCat_int(benchmark::State& state) {
    279  int i = 0;
    280  for (auto s : state) {
    281    std::string result = absl::StrCat(i);
    282    benchmark::DoNotOptimize(result);
    283    i = IncrementAlternatingSign(i);
    284  }
    285 }
    286 
    287 BENCHMARK(BM_StrCat_int);
    288 
    289 }  // namespace