tor-browser

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

int128_benchmark.cc (9891B)


      1 // Copyright 2017 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 <algorithm>
     16 #include <cstdint>
     17 #include <limits>
     18 #include <random>
     19 #include <vector>
     20 
     21 #include "absl/base/config.h"
     22 #include "absl/numeric/int128.h"
     23 #include "benchmark/benchmark.h"
     24 
     25 namespace {
     26 
     27 constexpr size_t kSampleSize = 1000000;
     28 
     29 std::mt19937 MakeRandomEngine() {
     30  std::random_device r;
     31  std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
     32  return std::mt19937(seed);
     33 }
     34 
     35 template <typename T,
     36          typename H = typename std::conditional<
     37              std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
     38 std::vector<std::pair<T, T>> GetRandomClass128SampleUniformDivisor() {
     39  std::vector<std::pair<T, T>> values;
     40  std::mt19937 random = MakeRandomEngine();
     41  std::uniform_int_distribution<H> uniform_h;
     42  values.reserve(kSampleSize);
     43  for (size_t i = 0; i < kSampleSize; ++i) {
     44    T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
     45    T b{absl::MakeUint128(uniform_h(random), uniform_h(random))};
     46    values.emplace_back(std::max(a, b), std::max(T(2), std::min(a, b)));
     47  }
     48  return values;
     49 }
     50 
     51 template <typename T>
     52 void BM_DivideClass128UniformDivisor(benchmark::State& state) {
     53  auto values = GetRandomClass128SampleUniformDivisor<T>();
     54  while (state.KeepRunningBatch(values.size())) {
     55    for (const auto& pair : values) {
     56      benchmark::DoNotOptimize(pair.first / pair.second);
     57    }
     58  }
     59 }
     60 BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::uint128);
     61 BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::int128);
     62 
     63 template <typename T>
     64 void BM_RemainderClass128UniformDivisor(benchmark::State& state) {
     65  auto values = GetRandomClass128SampleUniformDivisor<T>();
     66  while (state.KeepRunningBatch(values.size())) {
     67    for (const auto& pair : values) {
     68      benchmark::DoNotOptimize(pair.first % pair.second);
     69    }
     70  }
     71 }
     72 BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::uint128);
     73 BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::int128);
     74 
     75 template <typename T,
     76          typename H = typename std::conditional<
     77              std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
     78 std::vector<std::pair<T, H>> GetRandomClass128SampleSmallDivisor() {
     79  std::vector<std::pair<T, H>> values;
     80  std::mt19937 random = MakeRandomEngine();
     81  std::uniform_int_distribution<H> uniform_h;
     82  values.reserve(kSampleSize);
     83  for (size_t i = 0; i < kSampleSize; ++i) {
     84    T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
     85    H b{std::max(H{2}, uniform_h(random))};
     86    values.emplace_back(std::max(a, T(b)), b);
     87  }
     88  return values;
     89 }
     90 
     91 template <typename T>
     92 void BM_DivideClass128SmallDivisor(benchmark::State& state) {
     93  auto values = GetRandomClass128SampleSmallDivisor<T>();
     94  while (state.KeepRunningBatch(values.size())) {
     95    for (const auto& pair : values) {
     96      benchmark::DoNotOptimize(pair.first / pair.second);
     97    }
     98  }
     99 }
    100 BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::uint128);
    101 BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::int128);
    102 
    103 template <typename T>
    104 void BM_RemainderClass128SmallDivisor(benchmark::State& state) {
    105  auto values = GetRandomClass128SampleSmallDivisor<T>();
    106  while (state.KeepRunningBatch(values.size())) {
    107    for (const auto& pair : values) {
    108      benchmark::DoNotOptimize(pair.first % pair.second);
    109    }
    110  }
    111 }
    112 BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::uint128);
    113 BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::int128);
    114 
    115 std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
    116  std::vector<std::pair<absl::uint128, absl::uint128>> values;
    117  std::mt19937 random = MakeRandomEngine();
    118  std::uniform_int_distribution<uint64_t> uniform_uint64;
    119  values.reserve(kSampleSize);
    120  for (size_t i = 0; i < kSampleSize; ++i) {
    121    values.emplace_back(
    122        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
    123        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
    124  }
    125  return values;
    126 }
    127 
    128 void BM_MultiplyClass128(benchmark::State& state) {
    129  auto values = GetRandomClass128Sample();
    130  while (state.KeepRunningBatch(values.size())) {
    131    for (const auto& pair : values) {
    132      benchmark::DoNotOptimize(pair.first * pair.second);
    133    }
    134  }
    135 }
    136 BENCHMARK(BM_MultiplyClass128);
    137 
    138 void BM_AddClass128(benchmark::State& state) {
    139  auto values = GetRandomClass128Sample();
    140  while (state.KeepRunningBatch(values.size())) {
    141    for (const auto& pair : values) {
    142      benchmark::DoNotOptimize(pair.first + pair.second);
    143    }
    144  }
    145 }
    146 BENCHMARK(BM_AddClass128);
    147 
    148 #ifdef ABSL_HAVE_INTRINSIC_INT128
    149 
    150 // Some implementations of <random> do not support __int128 when it is
    151 // available, so we make our own uniform_int_distribution-like type.
    152 template <typename T,
    153          typename H = typename std::conditional<
    154              std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
    155 class UniformIntDistribution128 {
    156 public:
    157  // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
    158  T operator()(std::mt19937& generator) {
    159    return (static_cast<T>(dist64_(generator)) << 64) | dist64_(generator);
    160  }
    161 
    162 private:
    163  std::uniform_int_distribution<H> dist64_;
    164 };
    165 
    166 template <typename T,
    167          typename H = typename std::conditional<
    168              std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
    169 std::vector<std::pair<T, T>> GetRandomIntrinsic128SampleUniformDivisor() {
    170  std::vector<std::pair<T, T>> values;
    171  std::mt19937 random = MakeRandomEngine();
    172  UniformIntDistribution128<T> uniform_128;
    173  values.reserve(kSampleSize);
    174  for (size_t i = 0; i < kSampleSize; ++i) {
    175    T a = uniform_128(random);
    176    T b = uniform_128(random);
    177    values.emplace_back(std::max(a, b),
    178                        std::max(static_cast<T>(2), std::min(a, b)));
    179  }
    180  return values;
    181 }
    182 
    183 template <typename T>
    184 void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
    185  auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
    186  while (state.KeepRunningBatch(values.size())) {
    187    for (const auto& pair : values) {
    188      benchmark::DoNotOptimize(pair.first / pair.second);
    189    }
    190  }
    191 }
    192 BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, unsigned __int128);
    193 BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, __int128);
    194 
    195 template <typename T>
    196 void BM_RemainderIntrinsic128UniformDivisor(benchmark::State& state) {
    197  auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
    198  while (state.KeepRunningBatch(values.size())) {
    199    for (const auto& pair : values) {
    200      benchmark::DoNotOptimize(pair.first % pair.second);
    201    }
    202  }
    203 }
    204 BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, unsigned __int128);
    205 BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, __int128);
    206 
    207 template <typename T,
    208          typename H = typename std::conditional<
    209              std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
    210 std::vector<std::pair<T, H>> GetRandomIntrinsic128SampleSmallDivisor() {
    211  std::vector<std::pair<T, H>> values;
    212  std::mt19937 random = MakeRandomEngine();
    213  UniformIntDistribution128<T> uniform_int128;
    214  std::uniform_int_distribution<H> uniform_int64;
    215  values.reserve(kSampleSize);
    216  for (size_t i = 0; i < kSampleSize; ++i) {
    217    T a = uniform_int128(random);
    218    H b = std::max(H{2}, uniform_int64(random));
    219    values.emplace_back(std::max(a, static_cast<T>(b)), b);
    220  }
    221  return values;
    222 }
    223 
    224 template <typename T>
    225 void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
    226  auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
    227  while (state.KeepRunningBatch(values.size())) {
    228    for (const auto& pair : values) {
    229      benchmark::DoNotOptimize(pair.first / pair.second);
    230    }
    231  }
    232 }
    233 BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, unsigned __int128);
    234 BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, __int128);
    235 
    236 template <typename T>
    237 void BM_RemainderIntrinsic128SmallDivisor(benchmark::State& state) {
    238  auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
    239  while (state.KeepRunningBatch(values.size())) {
    240    for (const auto& pair : values) {
    241      benchmark::DoNotOptimize(pair.first % pair.second);
    242    }
    243  }
    244 }
    245 BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, unsigned __int128);
    246 BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __int128);
    247 
    248 std::vector<std::pair<unsigned __int128, unsigned __int128>>
    249      GetRandomIntrinsic128Sample() {
    250  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
    251  std::mt19937 random = MakeRandomEngine();
    252  UniformIntDistribution128<unsigned __int128> uniform_uint128;
    253  values.reserve(kSampleSize);
    254  for (size_t i = 0; i < kSampleSize; ++i) {
    255    values.emplace_back(uniform_uint128(random), uniform_uint128(random));
    256  }
    257  return values;
    258 }
    259 
    260 void BM_MultiplyIntrinsic128(benchmark::State& state) {
    261  auto values = GetRandomIntrinsic128Sample();
    262  while (state.KeepRunningBatch(values.size())) {
    263    for (const auto& pair : values) {
    264      benchmark::DoNotOptimize(pair.first * pair.second);
    265    }
    266  }
    267 }
    268 BENCHMARK(BM_MultiplyIntrinsic128);
    269 
    270 void BM_AddIntrinsic128(benchmark::State& state) {
    271  auto values = GetRandomIntrinsic128Sample();
    272  while (state.KeepRunningBatch(values.size())) {
    273    for (const auto& pair : values) {
    274      benchmark::DoNotOptimize(pair.first + pair.second);
    275    }
    276  }
    277 }
    278 BENCHMARK(BM_AddIntrinsic128);
    279 
    280 #endif  // ABSL_HAVE_INTRINSIC_INT128
    281 
    282 }  // namespace