1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker *
4*b9df5ad1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker *
8*b9df5ad1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker *
10*b9df5ad1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker */
16*b9df5ad1SAndroid Build Coastguard Worker
17*b9df5ad1SAndroid Build Coastguard Worker #include <cstddef>
18*b9df5ad1SAndroid Build Coastguard Worker #include <random>
19*b9df5ad1SAndroid Build Coastguard Worker #include <vector>
20*b9df5ad1SAndroid Build Coastguard Worker
21*b9df5ad1SAndroid Build Coastguard Worker #include <benchmark/benchmark.h>
22*b9df5ad1SAndroid Build Coastguard Worker
23*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/Statistics.h>
24*b9df5ad1SAndroid Build Coastguard Worker
25*b9df5ad1SAndroid Build Coastguard Worker template <typename T>
initUniform(std::vector<T> & data,T rangeMin,T rangeMax)26*b9df5ad1SAndroid Build Coastguard Worker static void initUniform(std::vector<T> &data, T rangeMin, T rangeMax) {
27*b9df5ad1SAndroid Build Coastguard Worker const size_t count = data.capacity();
28*b9df5ad1SAndroid Build Coastguard Worker std::minstd_rand gen(count);
29*b9df5ad1SAndroid Build Coastguard Worker std::uniform_real_distribution<T> dis(rangeMin, rangeMax);
30*b9df5ad1SAndroid Build Coastguard Worker for (auto &datum : data) {
31*b9df5ad1SAndroid Build Coastguard Worker datum = dis(gen);
32*b9df5ad1SAndroid Build Coastguard Worker }
33*b9df5ad1SAndroid Build Coastguard Worker }
34*b9df5ad1SAndroid Build Coastguard Worker
35*b9df5ad1SAndroid Build Coastguard Worker template <typename Stats>
BM_MeanVariance(benchmark::State & state,int iterlimit,int alphalimit)36*b9df5ad1SAndroid Build Coastguard Worker static void BM_MeanVariance(benchmark::State& state, int iterlimit, int alphalimit) {
37*b9df5ad1SAndroid Build Coastguard Worker const float alpha = 1. - alphalimit * std::numeric_limits<float>::epsilon();
38*b9df5ad1SAndroid Build Coastguard Worker Stats stat(alpha);
39*b9df5ad1SAndroid Build Coastguard Worker using T = decltype(stat.getMin());
40*b9df5ad1SAndroid Build Coastguard Worker constexpr size_t count = 1 << 20; // exactly one "mega" samples from the distribution.
41*b9df5ad1SAndroid Build Coastguard Worker constexpr T range = 1.;
42*b9df5ad1SAndroid Build Coastguard Worker std::vector<T> data(count);
43*b9df5ad1SAndroid Build Coastguard Worker initUniform(data, -range, range);
44*b9df5ad1SAndroid Build Coastguard Worker
45*b9df5ad1SAndroid Build Coastguard Worker // Run the test
46*b9df5ad1SAndroid Build Coastguard Worker int iters = 0;
47*b9df5ad1SAndroid Build Coastguard Worker while (state.KeepRunning()) {
48*b9df5ad1SAndroid Build Coastguard Worker benchmark::DoNotOptimize(data.data());
49*b9df5ad1SAndroid Build Coastguard Worker for (const auto &datum : data) {
50*b9df5ad1SAndroid Build Coastguard Worker stat.add(datum);
51*b9df5ad1SAndroid Build Coastguard Worker }
52*b9df5ad1SAndroid Build Coastguard Worker benchmark::ClobberMemory();
53*b9df5ad1SAndroid Build Coastguard Worker if (++iters % iterlimit == 0) {
54*b9df5ad1SAndroid Build Coastguard Worker printf("%d> alpha:%f mean:%.17g variance:%.17g\n",
55*b9df5ad1SAndroid Build Coastguard Worker iters, alpha, (double)stat.getMean(), (double)stat.getPopVariance());
56*b9df5ad1SAndroid Build Coastguard Worker stat.reset();
57*b9df5ad1SAndroid Build Coastguard Worker }
58*b9df5ad1SAndroid Build Coastguard Worker }
59*b9df5ad1SAndroid Build Coastguard Worker state.SetComplexityN(count);
60*b9df5ad1SAndroid Build Coastguard Worker }
61*b9df5ad1SAndroid Build Coastguard Worker
62*b9df5ad1SAndroid Build Coastguard Worker
63*b9df5ad1SAndroid Build Coastguard Worker // Test case:
64*b9df5ad1SAndroid Build Coastguard Worker // Do we work correctly within the capacity of float statistics when alpha == 1?
65*b9df5ad1SAndroid Build Coastguard Worker //
66*b9df5ad1SAndroid Build Coastguard Worker // 1 << 23 samples is the mantissa limited capacity of float statistics if alpha == 1.
67*b9df5ad1SAndroid Build Coastguard Worker static constexpr int float_iterlimit = 8;
68*b9df5ad1SAndroid Build Coastguard Worker // alphalimit of 0 means alpha exactly equals one.
69*b9df5ad1SAndroid Build Coastguard Worker static constexpr int alpha_equals_one_alphalimit = 0;
70*b9df5ad1SAndroid Build Coastguard Worker
71*b9df5ad1SAndroid Build Coastguard Worker // benchmark running float
BM_MeanVariance_float_float_float(benchmark::State & state)72*b9df5ad1SAndroid Build Coastguard Worker static void BM_MeanVariance_float_float_float(benchmark::State &state) {
73*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::Statistics<float, float, float>>(state,
74*b9df5ad1SAndroid Build Coastguard Worker float_iterlimit, alpha_equals_one_alphalimit);
75*b9df5ad1SAndroid Build Coastguard Worker }
76*b9df5ad1SAndroid Build Coastguard Worker
77*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_MeanVariance_float_float_float);
78*b9df5ad1SAndroid Build Coastguard Worker
79*b9df5ad1SAndroid Build Coastguard Worker // benchmark reference float
BM_RefMeanVariance_float_float(benchmark::State & state)80*b9df5ad1SAndroid Build Coastguard Worker static void BM_RefMeanVariance_float_float(benchmark::State &state) {
81*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::ReferenceStatistics<float, float>>(state,
82*b9df5ad1SAndroid Build Coastguard Worker float_iterlimit, alpha_equals_one_alphalimit);
83*b9df5ad1SAndroid Build Coastguard Worker }
84*b9df5ad1SAndroid Build Coastguard Worker
85*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_RefMeanVariance_float_float);
86*b9df5ad1SAndroid Build Coastguard Worker
87*b9df5ad1SAndroid Build Coastguard Worker // benchmark running double
BM_MeanVariance_float_double_double(benchmark::State & state)88*b9df5ad1SAndroid Build Coastguard Worker static auto BM_MeanVariance_float_double_double(benchmark::State &state) {
89*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::Statistics<float, double, double>>(state,
90*b9df5ad1SAndroid Build Coastguard Worker float_iterlimit, alpha_equals_one_alphalimit);
91*b9df5ad1SAndroid Build Coastguard Worker }
92*b9df5ad1SAndroid Build Coastguard Worker
93*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_MeanVariance_float_double_double);
94*b9df5ad1SAndroid Build Coastguard Worker
95*b9df5ad1SAndroid Build Coastguard Worker // benchmark reference double
BM_RefMeanVariance_float_double(benchmark::State & state)96*b9df5ad1SAndroid Build Coastguard Worker static auto BM_RefMeanVariance_float_double(benchmark::State &state) {
97*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::ReferenceStatistics<float, double>>(state,
98*b9df5ad1SAndroid Build Coastguard Worker float_iterlimit, alpha_equals_one_alphalimit);
99*b9df5ad1SAndroid Build Coastguard Worker }
100*b9df5ad1SAndroid Build Coastguard Worker
101*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_RefMeanVariance_float_double);
102*b9df5ad1SAndroid Build Coastguard Worker
103*b9df5ad1SAndroid Build Coastguard Worker // benchmark running float + kahan
BM_MeanVariance_float_float_Kahan(benchmark::State & state)104*b9df5ad1SAndroid Build Coastguard Worker static auto BM_MeanVariance_float_float_Kahan(benchmark::State &state) {
105*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::Statistics<float, float,
106*b9df5ad1SAndroid Build Coastguard Worker android::audio_utils::KahanSum<float>>>(state,
107*b9df5ad1SAndroid Build Coastguard Worker float_iterlimit, alpha_equals_one_alphalimit);
108*b9df5ad1SAndroid Build Coastguard Worker }
109*b9df5ad1SAndroid Build Coastguard Worker
110*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_MeanVariance_float_float_Kahan);
111*b9df5ad1SAndroid Build Coastguard Worker
112*b9df5ad1SAndroid Build Coastguard Worker // benchmark running float + Neumaier
BM_MeanVariance_float_float_Neumaier(benchmark::State & state)113*b9df5ad1SAndroid Build Coastguard Worker static auto BM_MeanVariance_float_float_Neumaier(benchmark::State &state) {
114*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::Statistics<float, float,
115*b9df5ad1SAndroid Build Coastguard Worker android::audio_utils::NeumaierSum<float>>>(state,
116*b9df5ad1SAndroid Build Coastguard Worker float_iterlimit, alpha_equals_one_alphalimit);
117*b9df5ad1SAndroid Build Coastguard Worker }
118*b9df5ad1SAndroid Build Coastguard Worker
119*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_MeanVariance_float_float_Neumaier);
120*b9df5ad1SAndroid Build Coastguard Worker
121*b9df5ad1SAndroid Build Coastguard Worker // Test case:
122*b9df5ad1SAndroid Build Coastguard Worker // Do we work correctly for very large N statistics when alpha is 1 - 32 * epsilon?
123*b9df5ad1SAndroid Build Coastguard Worker // This simulates long term statistics collection, where the alpha weighted windowing
124*b9df5ad1SAndroid Build Coastguard Worker // permits us to exceed 1 << 23 samples reliably.
125*b9df5ad1SAndroid Build Coastguard Worker //
126*b9df5ad1SAndroid Build Coastguard Worker // 1 << 25 samples exceeds the mantissa limited capacity of float statistics if alpha == 1...
127*b9df5ad1SAndroid Build Coastguard Worker static constexpr int float_overflow_iterlimit = 32;
128*b9df5ad1SAndroid Build Coastguard Worker // but we use an alphalimit of 32, means 1. - (alphalimit * epsilon) approx = 0.999996.
129*b9df5ad1SAndroid Build Coastguard Worker // This should allow statistics collection indefinitely.
130*b9df5ad1SAndroid Build Coastguard Worker static constexpr int alpha_safe_upperbound_iterlimit = 32;
131*b9df5ad1SAndroid Build Coastguard Worker
132*b9df5ad1SAndroid Build Coastguard Worker // benchmark running float at alpha
BM_MeanVariance_float_float_float_alpha(benchmark::State & state)133*b9df5ad1SAndroid Build Coastguard Worker static auto BM_MeanVariance_float_float_float_alpha(benchmark::State &state) {
134*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::Statistics<float, float, float>>(state,
135*b9df5ad1SAndroid Build Coastguard Worker float_overflow_iterlimit, alpha_safe_upperbound_iterlimit);
136*b9df5ad1SAndroid Build Coastguard Worker }
137*b9df5ad1SAndroid Build Coastguard Worker
138*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_MeanVariance_float_float_float_alpha);
139*b9df5ad1SAndroid Build Coastguard Worker
140*b9df5ad1SAndroid Build Coastguard Worker // benchmark running double
BM_MeanVariance_float_double_double_alpha(benchmark::State & state)141*b9df5ad1SAndroid Build Coastguard Worker static auto BM_MeanVariance_float_double_double_alpha(benchmark::State &state) {
142*b9df5ad1SAndroid Build Coastguard Worker BM_MeanVariance<android::audio_utils::Statistics<float, double, double>>(state,
143*b9df5ad1SAndroid Build Coastguard Worker float_overflow_iterlimit, alpha_safe_upperbound_iterlimit);
144*b9df5ad1SAndroid Build Coastguard Worker }
145*b9df5ad1SAndroid Build Coastguard Worker
146*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK(BM_MeanVariance_float_double_double_alpha);
147*b9df5ad1SAndroid Build Coastguard Worker
148*b9df5ad1SAndroid Build Coastguard Worker BENCHMARK_MAIN();
149