tor-browser

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

randen_benchmarks.cc (5898B)


      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 <cstdint>
     16 #include <cstdio>
     17 #include <cstring>
     18 
     19 #include "absl/base/internal/raw_logging.h"
     20 #include "absl/random/internal/nanobenchmark.h"
     21 #include "absl/random/internal/platform.h"
     22 #include "absl/random/internal/randen.h"
     23 #include "absl/random/internal/randen_detect.h"
     24 #include "absl/random/internal/randen_engine.h"
     25 #include "absl/random/internal/randen_hwaes.h"
     26 #include "absl/random/internal/randen_slow.h"
     27 #include "absl/strings/numbers.h"
     28 
     29 namespace {
     30 
     31 using absl::random_internal::CPUSupportsRandenHwAes;
     32 using absl::random_internal::Randen;
     33 using absl::random_internal::RandenHwAes;
     34 using absl::random_internal::RandenSlow;
     35 
     36 using absl::random_internal_nanobenchmark::FuncInput;
     37 using absl::random_internal_nanobenchmark::FuncOutput;
     38 using absl::random_internal_nanobenchmark::InvariantTicksPerSecond;
     39 using absl::random_internal_nanobenchmark::MeasureClosure;
     40 using absl::random_internal_nanobenchmark::Params;
     41 using absl::random_internal_nanobenchmark::PinThreadToCPU;
     42 using absl::random_internal_nanobenchmark::Result;
     43 
     44 // Local state parameters.
     45 static constexpr size_t kStateSizeT = Randen::kStateBytes / sizeof(uint64_t);
     46 static constexpr size_t kSeedSizeT = Randen::kSeedBytes / sizeof(uint32_t);
     47 
     48 // Randen implementation benchmarks.
     49 template <typename T>
     50 struct AbsorbFn : public T {
     51  // These are both cast to uint128* in the RandenHwAes implementation, so
     52  // ensure they are 16 byte aligned.
     53  alignas(16) mutable uint64_t state[kStateSizeT] = {};
     54  alignas(16) mutable uint32_t seed[kSeedSizeT] = {};
     55 
     56  static constexpr size_t bytes() { return sizeof(seed); }
     57 
     58  FuncOutput operator()(const FuncInput num_iters) const {
     59    for (size_t i = 0; i < num_iters; ++i) {
     60      this->Absorb(seed, state);
     61    }
     62    return state[0];
     63  }
     64 };
     65 
     66 template <typename T>
     67 struct GenerateFn : public T {
     68  mutable uint64_t state[kStateSizeT];
     69  GenerateFn() { std::memset(state, 0, sizeof(state)); }
     70 
     71  static constexpr size_t bytes() { return sizeof(state); }
     72 
     73  FuncOutput operator()(const FuncInput num_iters) const {
     74    const auto* keys = this->GetKeys();
     75    for (size_t i = 0; i < num_iters; ++i) {
     76      this->Generate(keys, state);
     77    }
     78    return state[0];
     79  }
     80 };
     81 
     82 template <typename UInt>
     83 struct Engine {
     84  mutable absl::random_internal::randen_engine<UInt> rng;
     85 
     86  static constexpr size_t bytes() { return sizeof(UInt); }
     87 
     88  FuncOutput operator()(const FuncInput num_iters) const {
     89    for (size_t i = 0; i < num_iters - 1; ++i) {
     90      rng();
     91    }
     92    return rng();
     93  }
     94 };
     95 
     96 template <size_t N>
     97 void Print(const char* name, const size_t n, const Result (&results)[N],
     98           const size_t bytes) {
     99  if (n == 0) {
    100    ABSL_RAW_LOG(
    101        WARNING,
    102        "WARNING: Measurement failed, should not happen when using "
    103        "PinThreadToCPU unless the region to measure takes > 1 second.\n");
    104    return;
    105  }
    106 
    107  static const double ns_per_tick = 1e9 / InvariantTicksPerSecond();
    108  static constexpr const double kNsPerS = 1e9;                 // ns/s
    109  static constexpr const double kMBPerByte = 1.0 / 1048576.0;  // Mb / b
    110  static auto header = [] {
    111    return printf("%20s %8s: %12s ticks; %9s  (%9s) %8s\n", "Name", "Count",
    112                  "Total", "Variance", "Time", "bytes/s");
    113  }();
    114  (void)header;
    115 
    116  for (size_t i = 0; i < n; ++i) {
    117    const double ticks_per_call = results[i].ticks / results[i].input;
    118    const double ns_per_call = ns_per_tick * ticks_per_call;
    119    const double bytes_per_ns = bytes / ns_per_call;
    120    const double mb_per_s = bytes_per_ns * kNsPerS * kMBPerByte;
    121    // Output
    122    printf("%20s %8zu: %12.2f ticks; MAD=%4.2f%%  (%6.1f ns) %8.1f Mb/s\n",
    123           name, results[i].input, results[i].ticks,
    124           results[i].variability * 100.0, ns_per_call, mb_per_s);
    125  }
    126 }
    127 
    128 // Fails here
    129 template <typename Op, size_t N>
    130 void Measure(const char* name, const FuncInput (&inputs)[N]) {
    131  Op op;
    132 
    133  Result results[N];
    134  Params params;
    135  params.verbose = false;
    136  params.max_evals = 6;  // avoid test timeout
    137  const size_t num_results = MeasureClosure(op, inputs, N, results, params);
    138  Print(name, num_results, results, op.bytes());
    139 }
    140 
    141 // unpredictable == 1 but the compiler does not know that.
    142 void RunAll(const int argc, char* argv[]) {
    143  if (argc == 2) {
    144    int cpu = -1;
    145    if (!absl::SimpleAtoi(argv[1], &cpu)) {
    146      ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n");
    147    }
    148    PinThreadToCPU(cpu);
    149  }
    150 
    151  // The compiler cannot reduce this to a constant.
    152  const FuncInput unpredictable = (argc != 999);
    153  static const FuncInput inputs[] = {unpredictable * 100, unpredictable * 1000};
    154 
    155  if (CPUSupportsRandenHwAes()) {
    156    Measure<AbsorbFn<RandenHwAes>>("Absorb (HwAes)", inputs);
    157  }
    158  Measure<AbsorbFn<RandenSlow>>("Absorb (Slow)", inputs);
    159 
    160  if (CPUSupportsRandenHwAes()) {
    161    Measure<GenerateFn<RandenHwAes>>("Generate (HwAes)", inputs);
    162  }
    163  Measure<GenerateFn<RandenSlow>>("Generate (Slow)", inputs);
    164 
    165  // Measure the production engine.
    166  static const FuncInput inputs1[] = {unpredictable * 1000,
    167                                      unpredictable * 10000};
    168  Measure<Engine<uint64_t>>("randen_engine<uint64_t>", inputs1);
    169  Measure<Engine<uint32_t>>("randen_engine<uint32_t>", inputs1);
    170 }
    171 
    172 }  // namespace
    173 
    174 int main(int argc, char* argv[]) {
    175  RunAll(argc, argv);
    176  return 0;
    177 }