tor-browser

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

no_destructor_benchmark.cc (5089B)


      1 // Copyright 2023 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 
     17 #include "absl/base/internal/raw_logging.h"
     18 #include "absl/base/no_destructor.h"
     19 #include "benchmark/benchmark.h"
     20 
     21 namespace {
     22 
     23 // Number of static-NoDestructor-in-a-function to exercise.
     24 // This must be low enough not to hit template instantiation limits
     25 // (happens around 1000).
     26 constexpr int kNumObjects = 1;  // set to 512 when doing benchmarks
     27                                // 1 is faster to compile: just one templated
     28                                // function instantiation
     29 
     30 // Size of individual objects to benchmark static-NoDestructor-in-a-function
     31 // usage with.
     32 constexpr int kObjSize = sizeof(void*)*1;
     33 
     34 // Simple object of kObjSize bytes (rounded to int).
     35 // We benchmark complete reading of its state via Verify().
     36 class BM_Blob {
     37 public:
     38  BM_Blob(int val) { for (auto& d : data_) d = val; }
     39  BM_Blob() : BM_Blob(-1) {}
     40  void Verify(int val) const {  // val must be the c-tor argument
     41    for (auto& d : data_) ABSL_INTERNAL_CHECK(d == val, "");
     42  }
     43 private:
     44  int data_[kObjSize / sizeof(int) > 0 ? kObjSize / sizeof(int) : 1];
     45 };
     46 
     47 // static-NoDestructor-in-a-function pattern instances.
     48 // We'll instantiate kNumObjects of them.
     49 template<int i>
     50 const BM_Blob& NoDestrBlobFunc() {
     51  static absl::NoDestructor<BM_Blob> x(i);
     52  return *x;
     53 }
     54 
     55 // static-heap-ptr-in-a-function pattern instances
     56 // We'll instantiate kNumObjects of them.
     57 template<int i>
     58 const BM_Blob& OnHeapBlobFunc() {
     59  static BM_Blob* x = new BM_Blob(i);
     60  return *x;
     61 }
     62 
     63 // Type for NoDestrBlobFunc or OnHeapBlobFunc.
     64 typedef const BM_Blob& (*FuncType)();
     65 
     66 // ========================================================================= //
     67 // Simple benchmarks that read a single BM_Blob over and over, hence
     68 // all they touch fits into L1 CPU cache:
     69 
     70 // Direct non-POD global variable (style guide violation) as a baseline.
     71 static BM_Blob direct_blob(0);
     72 
     73 void BM_Direct(benchmark::State& state) {
     74  for (auto s : state) {
     75    direct_blob.Verify(0);
     76  }
     77 }
     78 BENCHMARK(BM_Direct);
     79 
     80 void BM_NoDestr(benchmark::State& state) {
     81  for (auto s : state) {
     82    NoDestrBlobFunc<0>().Verify(0);
     83  }
     84 }
     85 BENCHMARK(BM_NoDestr);
     86 
     87 void BM_OnHeap(benchmark::State& state) {
     88  for (auto s : state) {
     89    OnHeapBlobFunc<0>().Verify(0);
     90  }
     91 }
     92 BENCHMARK(BM_OnHeap);
     93 
     94 // ========================================================================= //
     95 // Benchmarks that read kNumObjects of BM_Blob over and over, hence with
     96 // appropriate values of sizeof(BM_Blob) and kNumObjects their working set
     97 // can exceed a given layer of CPU cache.
     98 
     99 // Type of benchmark to select between NoDestrBlobFunc and OnHeapBlobFunc.
    100 enum BM_Type { kNoDestr, kOnHeap, kDirect };
    101 
    102 // BlobFunc<n>(t, i) returns the i-th function of type t.
    103 // n must be larger than i (we'll use kNumObjects for n).
    104 template<int n>
    105 FuncType BlobFunc(BM_Type t, int i) {
    106  if (i == n) {
    107    switch (t) {
    108      case kNoDestr:  return &NoDestrBlobFunc<n>;
    109      case kOnHeap:   return &OnHeapBlobFunc<n>;
    110      case kDirect:   return nullptr;
    111    }
    112  }
    113  return BlobFunc<n-1>(t, i);
    114 }
    115 
    116 template<>
    117 FuncType BlobFunc<0>(BM_Type t, int i) {
    118  ABSL_INTERNAL_CHECK(i == 0, "");
    119  switch (t) {
    120    case kNoDestr:  return &NoDestrBlobFunc<0>;
    121    case kOnHeap:   return &OnHeapBlobFunc<0>;
    122    case kDirect:   return nullptr;
    123  }
    124  return nullptr;
    125 }
    126 
    127 // Direct non-POD global variables (style guide violation) as a baseline.
    128 static BM_Blob direct_blobs[kNumObjects];
    129 
    130 // Helper that cheaply maps benchmark iteration to randomish index in
    131 // [0, kNumObjects).
    132 int RandIdx(int i) {
    133  // int64 is to avoid overflow and generating negative return values:
    134  return (static_cast<int64_t>(i) * 13) % kNumObjects;
    135 }
    136 
    137 // Generic benchmark working with kNumObjects for any of the possible BM_Type.
    138 template <BM_Type t>
    139 void BM_Many(benchmark::State& state) {
    140  FuncType funcs[kNumObjects];
    141  for (int i = 0; i < kNumObjects; ++i) {
    142    funcs[i] = BlobFunc<kNumObjects-1>(t, i);
    143  }
    144  if (t == kDirect) {
    145    for (auto s : state) {
    146      int idx = RandIdx(state.iterations());
    147      direct_blobs[idx].Verify(-1);
    148    }
    149  } else {
    150    for (auto s : state) {
    151      int idx = RandIdx(state.iterations());
    152      funcs[idx]().Verify(idx);
    153    }
    154  }
    155 }
    156 
    157 void BM_DirectMany(benchmark::State& state) { BM_Many<kDirect>(state); }
    158 void BM_NoDestrMany(benchmark::State& state) { BM_Many<kNoDestr>(state); }
    159 void BM_OnHeapMany(benchmark::State& state) { BM_Many<kOnHeap>(state); }
    160 
    161 BENCHMARK(BM_DirectMany);
    162 BENCHMARK(BM_NoDestrMany);
    163 BENCHMARK(BM_OnHeapMany);
    164 
    165 }  // namespace