1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 Google Inc. All Rights Reserved.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_
16*9356374aSAndroid Build Coastguard Worker #define ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_
17*9356374aSAndroid Build Coastguard Worker
18*9356374aSAndroid Build Coastguard Worker // Benchmarks functions of a single integer argument with realistic branch
19*9356374aSAndroid Build Coastguard Worker // prediction hit rates. Uses a robust estimator to summarize the measurements.
20*9356374aSAndroid Build Coastguard Worker // The precision is about 0.2%.
21*9356374aSAndroid Build Coastguard Worker //
22*9356374aSAndroid Build Coastguard Worker // Examples: see nanobenchmark_test.cc.
23*9356374aSAndroid Build Coastguard Worker //
24*9356374aSAndroid Build Coastguard Worker // Background: Microbenchmarks such as http://github.com/google/benchmark
25*9356374aSAndroid Build Coastguard Worker // can measure elapsed times on the order of a microsecond. Shorter functions
26*9356374aSAndroid Build Coastguard Worker // are typically measured by repeating them thousands of times and dividing
27*9356374aSAndroid Build Coastguard Worker // the total elapsed time by this count. Unfortunately, repetition (especially
28*9356374aSAndroid Build Coastguard Worker // with the same input parameter!) influences the runtime. In time-critical
29*9356374aSAndroid Build Coastguard Worker // code, it is reasonable to expect warm instruction/data caches and TLBs,
30*9356374aSAndroid Build Coastguard Worker // but a perfect record of which branches will be taken is unrealistic.
31*9356374aSAndroid Build Coastguard Worker // Unless the application also repeatedly invokes the measured function with
32*9356374aSAndroid Build Coastguard Worker // the same parameter, the benchmark is measuring something very different -
33*9356374aSAndroid Build Coastguard Worker // a best-case result, almost as if the parameter were made a compile-time
34*9356374aSAndroid Build Coastguard Worker // constant. This may lead to erroneous conclusions about branch-heavy
35*9356374aSAndroid Build Coastguard Worker // algorithms outperforming branch-free alternatives.
36*9356374aSAndroid Build Coastguard Worker //
37*9356374aSAndroid Build Coastguard Worker // Our approach differs in three ways. Adding fences to the timer functions
38*9356374aSAndroid Build Coastguard Worker // reduces variability due to instruction reordering, improving the timer
39*9356374aSAndroid Build Coastguard Worker // resolution to about 40 CPU cycles. However, shorter functions must still
40*9356374aSAndroid Build Coastguard Worker // be invoked repeatedly. For more realistic branch prediction performance,
41*9356374aSAndroid Build Coastguard Worker // we vary the input parameter according to a user-specified distribution.
42*9356374aSAndroid Build Coastguard Worker // Thus, instead of VaryInputs(Measure(Repeat(func))), we change the
43*9356374aSAndroid Build Coastguard Worker // loop nesting to Measure(Repeat(VaryInputs(func))). We also estimate the
44*9356374aSAndroid Build Coastguard Worker // central tendency of the measurement samples with the "half sample mode",
45*9356374aSAndroid Build Coastguard Worker // which is more robust to outliers and skewed data than the mean or median.
46*9356374aSAndroid Build Coastguard Worker
47*9356374aSAndroid Build Coastguard Worker // NOTE: for compatibility with multiple translation units compiled with
48*9356374aSAndroid Build Coastguard Worker // distinct flags, avoid #including headers that define functions.
49*9356374aSAndroid Build Coastguard Worker
50*9356374aSAndroid Build Coastguard Worker #include <stddef.h>
51*9356374aSAndroid Build Coastguard Worker #include <stdint.h>
52*9356374aSAndroid Build Coastguard Worker
53*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
54*9356374aSAndroid Build Coastguard Worker
55*9356374aSAndroid Build Coastguard Worker namespace absl {
56*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
57*9356374aSAndroid Build Coastguard Worker namespace random_internal_nanobenchmark {
58*9356374aSAndroid Build Coastguard Worker
59*9356374aSAndroid Build Coastguard Worker // Input influencing the function being measured (e.g. number of bytes to copy).
60*9356374aSAndroid Build Coastguard Worker using FuncInput = size_t;
61*9356374aSAndroid Build Coastguard Worker
62*9356374aSAndroid Build Coastguard Worker // "Proof of work" returned by Func to ensure the compiler does not elide it.
63*9356374aSAndroid Build Coastguard Worker using FuncOutput = uint64_t;
64*9356374aSAndroid Build Coastguard Worker
65*9356374aSAndroid Build Coastguard Worker // Function to measure: either 1) a captureless lambda or function with two
66*9356374aSAndroid Build Coastguard Worker // arguments or 2) a lambda with capture, in which case the first argument
67*9356374aSAndroid Build Coastguard Worker // is reserved for use by MeasureClosure.
68*9356374aSAndroid Build Coastguard Worker using Func = FuncOutput (*)(const void*, FuncInput);
69*9356374aSAndroid Build Coastguard Worker
70*9356374aSAndroid Build Coastguard Worker // Internal parameters that determine precision/resolution/measuring time.
71*9356374aSAndroid Build Coastguard Worker struct Params {
72*9356374aSAndroid Build Coastguard Worker // For measuring timer overhead/resolution. Used in a nested loop =>
73*9356374aSAndroid Build Coastguard Worker // quadratic time, acceptable because we know timer overhead is "low".
74*9356374aSAndroid Build Coastguard Worker // constexpr because this is used to define array bounds.
75*9356374aSAndroid Build Coastguard Worker static constexpr size_t kTimerSamples = 256;
76*9356374aSAndroid Build Coastguard Worker
77*9356374aSAndroid Build Coastguard Worker // Best-case precision, expressed as a divisor of the timer resolution.
78*9356374aSAndroid Build Coastguard Worker // Larger => more calls to Func and higher precision.
79*9356374aSAndroid Build Coastguard Worker size_t precision_divisor = 1024;
80*9356374aSAndroid Build Coastguard Worker
81*9356374aSAndroid Build Coastguard Worker // Ratio between full and subset input distribution sizes. Cannot be less
82*9356374aSAndroid Build Coastguard Worker // than 2; larger values increase measurement time but more faithfully
83*9356374aSAndroid Build Coastguard Worker // model the given input distribution.
84*9356374aSAndroid Build Coastguard Worker size_t subset_ratio = 2;
85*9356374aSAndroid Build Coastguard Worker
86*9356374aSAndroid Build Coastguard Worker // Together with the estimated Func duration, determines how many times to
87*9356374aSAndroid Build Coastguard Worker // call Func before checking the sample variability. Larger values increase
88*9356374aSAndroid Build Coastguard Worker // measurement time, memory/cache use and precision.
89*9356374aSAndroid Build Coastguard Worker double seconds_per_eval = 4E-3;
90*9356374aSAndroid Build Coastguard Worker
91*9356374aSAndroid Build Coastguard Worker // The minimum number of samples before estimating the central tendency.
92*9356374aSAndroid Build Coastguard Worker size_t min_samples_per_eval = 7;
93*9356374aSAndroid Build Coastguard Worker
94*9356374aSAndroid Build Coastguard Worker // The mode is better than median for estimating the central tendency of
95*9356374aSAndroid Build Coastguard Worker // skewed/fat-tailed distributions, but it requires sufficient samples
96*9356374aSAndroid Build Coastguard Worker // relative to the width of half-ranges.
97*9356374aSAndroid Build Coastguard Worker size_t min_mode_samples = 64;
98*9356374aSAndroid Build Coastguard Worker
99*9356374aSAndroid Build Coastguard Worker // Maximum permissible variability (= median absolute deviation / center).
100*9356374aSAndroid Build Coastguard Worker double target_rel_mad = 0.002;
101*9356374aSAndroid Build Coastguard Worker
102*9356374aSAndroid Build Coastguard Worker // Abort after this many evals without reaching target_rel_mad. This
103*9356374aSAndroid Build Coastguard Worker // prevents infinite loops.
104*9356374aSAndroid Build Coastguard Worker size_t max_evals = 9;
105*9356374aSAndroid Build Coastguard Worker
106*9356374aSAndroid Build Coastguard Worker // Retry the measure loop up to this many times.
107*9356374aSAndroid Build Coastguard Worker size_t max_measure_retries = 2;
108*9356374aSAndroid Build Coastguard Worker
109*9356374aSAndroid Build Coastguard Worker // Whether to print additional statistics to stdout.
110*9356374aSAndroid Build Coastguard Worker bool verbose = true;
111*9356374aSAndroid Build Coastguard Worker };
112*9356374aSAndroid Build Coastguard Worker
113*9356374aSAndroid Build Coastguard Worker // Measurement result for each unique input.
114*9356374aSAndroid Build Coastguard Worker struct Result {
115*9356374aSAndroid Build Coastguard Worker FuncInput input;
116*9356374aSAndroid Build Coastguard Worker
117*9356374aSAndroid Build Coastguard Worker // Robust estimate (mode or median) of duration.
118*9356374aSAndroid Build Coastguard Worker float ticks;
119*9356374aSAndroid Build Coastguard Worker
120*9356374aSAndroid Build Coastguard Worker // Measure of variability (median absolute deviation relative to "ticks").
121*9356374aSAndroid Build Coastguard Worker float variability;
122*9356374aSAndroid Build Coastguard Worker };
123*9356374aSAndroid Build Coastguard Worker
124*9356374aSAndroid Build Coastguard Worker // Ensures the thread is running on the specified cpu, and no others.
125*9356374aSAndroid Build Coastguard Worker // Reduces noise due to desynchronized socket RDTSC and context switches.
126*9356374aSAndroid Build Coastguard Worker // If "cpu" is negative, pin to the currently running core.
127*9356374aSAndroid Build Coastguard Worker void PinThreadToCPU(const int cpu = -1);
128*9356374aSAndroid Build Coastguard Worker
129*9356374aSAndroid Build Coastguard Worker // Returns tick rate, useful for converting measurements to seconds. Invariant
130*9356374aSAndroid Build Coastguard Worker // means the tick counter frequency is independent of CPU throttling or sleep.
131*9356374aSAndroid Build Coastguard Worker // This call may be expensive, callers should cache the result.
132*9356374aSAndroid Build Coastguard Worker double InvariantTicksPerSecond();
133*9356374aSAndroid Build Coastguard Worker
134*9356374aSAndroid Build Coastguard Worker // Precisely measures the number of ticks elapsed when calling "func" with the
135*9356374aSAndroid Build Coastguard Worker // given inputs, shuffled to ensure realistic branch prediction hit rates.
136*9356374aSAndroid Build Coastguard Worker //
137*9356374aSAndroid Build Coastguard Worker // "func" returns a 'proof of work' to ensure its computations are not elided.
138*9356374aSAndroid Build Coastguard Worker // "arg" is passed to Func, or reserved for internal use by MeasureClosure.
139*9356374aSAndroid Build Coastguard Worker // "inputs" is an array of "num_inputs" (not necessarily unique) arguments to
140*9356374aSAndroid Build Coastguard Worker // "func". The values should be chosen to maximize coverage of "func". This
141*9356374aSAndroid Build Coastguard Worker // represents a distribution, so a value's frequency should reflect its
142*9356374aSAndroid Build Coastguard Worker // probability in the real application. Order does not matter; for example, a
143*9356374aSAndroid Build Coastguard Worker // uniform distribution over [0, 4) could be represented as {3,0,2,1}.
144*9356374aSAndroid Build Coastguard Worker // Returns how many Result were written to "results": one per unique input, or
145*9356374aSAndroid Build Coastguard Worker // zero if the measurement failed (an error message goes to stderr).
146*9356374aSAndroid Build Coastguard Worker size_t Measure(const Func func, const void* arg, const FuncInput* inputs,
147*9356374aSAndroid Build Coastguard Worker const size_t num_inputs, Result* results,
148*9356374aSAndroid Build Coastguard Worker const Params& p = Params());
149*9356374aSAndroid Build Coastguard Worker
150*9356374aSAndroid Build Coastguard Worker // Calls operator() of the given closure (lambda function).
151*9356374aSAndroid Build Coastguard Worker template <class Closure>
CallClosure(const void * f,const FuncInput input)152*9356374aSAndroid Build Coastguard Worker static FuncOutput CallClosure(const void* f, const FuncInput input) {
153*9356374aSAndroid Build Coastguard Worker return (*reinterpret_cast<const Closure*>(f))(input);
154*9356374aSAndroid Build Coastguard Worker }
155*9356374aSAndroid Build Coastguard Worker
156*9356374aSAndroid Build Coastguard Worker // Same as Measure, except "closure" is typically a lambda function of
157*9356374aSAndroid Build Coastguard Worker // FuncInput -> FuncOutput with a capture list.
158*9356374aSAndroid Build Coastguard Worker template <class Closure>
159*9356374aSAndroid Build Coastguard Worker static inline size_t MeasureClosure(const Closure& closure,
160*9356374aSAndroid Build Coastguard Worker const FuncInput* inputs,
161*9356374aSAndroid Build Coastguard Worker const size_t num_inputs, Result* results,
162*9356374aSAndroid Build Coastguard Worker const Params& p = Params()) {
163*9356374aSAndroid Build Coastguard Worker return Measure(reinterpret_cast<Func>(&CallClosure<Closure>),
164*9356374aSAndroid Build Coastguard Worker reinterpret_cast<const void*>(&closure), inputs, num_inputs,
165*9356374aSAndroid Build Coastguard Worker results, p);
166*9356374aSAndroid Build Coastguard Worker }
167*9356374aSAndroid Build Coastguard Worker
168*9356374aSAndroid Build Coastguard Worker } // namespace random_internal_nanobenchmark
169*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
170*9356374aSAndroid Build Coastguard Worker } // namespace absl
171*9356374aSAndroid Build Coastguard Worker
172*9356374aSAndroid Build Coastguard Worker #endif // ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_
173