xref: /aosp_15_r20/system/media/audio_utils/benchmarks/statistics_benchmark.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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