1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <array>
18 #include <climits>
19 #include <cstdlib>
20 #include <random>
21 #include <vector>
22 
23 #include <benchmark/benchmark.h>
24 
25 #include <audio_utils/BiquadFilter.h>
26 #include <audio_utils/format.h>
27 
28 static constexpr size_t DATA_SIZE = 1024;
29 // The coefficients is a HPF with sampling frequency as 48000, center frequency as 600,
30 // and Q as 0.707. As all the coefficients are not zero, they can be used to benchmark
31 // the non-zero optimization of BiquadFilter.
32 // The benchmark test will iterate the channel count from 1 to 2. The occupancy will be
33 // iterate from 1 to 31. In that case, it is possible to test the performance of cases
34 // with different coefficients as zero.
35 static constexpr float REF_COEFS[] = {0.9460f, -1.8919f, 0.9460f, -1.8890f, 0.8949f};
36 
BM_BiquadFilter1D(benchmark::State & state)37 static void BM_BiquadFilter1D(benchmark::State& state) {
38     using android::audio_utils::BiquadFilter;
39 
40     bool doParallel = (state.range(0) == 1);
41     // const size_t channelCount = state.range(1);
42     const size_t filters = 1;
43 
44     std::vector<float> input(DATA_SIZE);
45     std::array<float, android::audio_utils::kBiquadNumCoefs> coefs;
46 
47     // Initialize input buffer and coefs with deterministic pseudo-random values
48     constexpr std::minstd_rand::result_type SEED = 42; // arbitrary choice.
49     std::minstd_rand gen(SEED);
50     constexpr float amplitude = 1.0f;
51     std::uniform_real_distribution<> dis(-amplitude, amplitude);
52     for (size_t i = 0; i < DATA_SIZE; ++i) {
53         input[i] = dis(gen);
54     }
55 
56     android::audio_utils::BiquadFilter parallel(filters, coefs);
57     std::vector<std::unique_ptr<BiquadFilter<float>>> biquads(filters);
58     for (auto& biquad : biquads) {
59         biquad.reset(new BiquadFilter<float>(1, coefs));
60     }
61 
62     // Run the test
63     float *data = input.data();
64     while (state.KeepRunning()) {
65         benchmark::DoNotOptimize(data);
66         if (doParallel) {
67             parallel.process1D(data, DATA_SIZE);
68         } else {
69             for (auto& biquad : biquads) {
70                 biquad->process(data, data, DATA_SIZE);
71             }
72         }
73         benchmark::ClobberMemory();
74     }
75 }
76 
BiquadFilter1DArgs(benchmark::internal::Benchmark * b)77 static void BiquadFilter1DArgs(benchmark::internal::Benchmark* b) {
78     for (int k = 0; k < 2; k++) // 0 for normal random data, 1 for subnormal random data
79          b->Args({k});
80 }
81 
82 BENCHMARK(BM_BiquadFilter1D)->Apply(BiquadFilter1DArgs);
83 
84 /*******************************************************************
85  * A test result running on Pixel 4 for comparison.
86  * The first parameter indicates the input data is subnormal or not.
87  * 0 for normal input data, 1 for subnormal input data.
88  * The second parameter indicates the channel count.
89  * The third parameter indicates the occupancy of the coefficients.
90  * -----------------------------------------------------------------
91  * Benchmark                       Time             CPU   Iterations
92  * -----------------------------------------------------------------
93  * BM_BiquadFilter/0/1/1         734 ns          732 ns       740671
94  * BM_BiquadFilter/0/1/2         554 ns          553 ns      1266836
95  * BM_BiquadFilter/0/1/3         647 ns          645 ns      1085314
96  * BM_BiquadFilter/0/1/4         834 ns          832 ns       841345
97  * BM_BiquadFilter/0/1/5        1068 ns         1065 ns       657343
98  * BM_BiquadFilter/0/1/6         767 ns          765 ns       915223
99  * BM_BiquadFilter/0/1/7         929 ns          926 ns       756405
100  * BM_BiquadFilter/0/1/8        2173 ns         2168 ns       322949
101  * BM_BiquadFilter/0/1/9        1831 ns         1826 ns       383304
102  * BM_BiquadFilter/0/1/10       1931 ns         1927 ns       363386
103  * BM_BiquadFilter/0/1/11       2536 ns         2529 ns       276783
104  * BM_BiquadFilter/0/1/12       2535 ns         2529 ns       276826
105  * BM_BiquadFilter/0/1/13       2174 ns         2169 ns       322755
106  * BM_BiquadFilter/0/1/14       3257 ns         3250 ns       215383
107  * BM_BiquadFilter/0/1/15       2175 ns         2169 ns       322711
108  * BM_BiquadFilter/0/1/16       1494 ns         1491 ns       469625
109  * BM_BiquadFilter/0/1/17       2176 ns         2171 ns       322423
110  * BM_BiquadFilter/0/1/18       1568 ns         1564 ns       447467
111  * BM_BiquadFilter/0/1/19       1325 ns         1322 ns       529762
112  * BM_BiquadFilter/0/1/20       1926 ns         1921 ns       364534
113  * BM_BiquadFilter/0/1/21       2630 ns         2623 ns       266027
114  * BM_BiquadFilter/0/1/22       1998 ns         1993 ns       351210
115  * BM_BiquadFilter/0/1/23       1882 ns         1877 ns       373028
116  * BM_BiquadFilter/0/1/24       2536 ns         2529 ns       276818
117  * BM_BiquadFilter/0/1/25       2176 ns         2170 ns       322627
118  * BM_BiquadFilter/0/1/26       3258 ns         3250 ns       215440
119  * BM_BiquadFilter/0/1/27       2175 ns         2169 ns       322724
120  * BM_BiquadFilter/0/1/28       2535 ns         2529 ns       276823
121  * BM_BiquadFilter/0/1/29       2175 ns         2170 ns       322560
122  * BM_BiquadFilter/0/1/30       3259 ns         3250 ns       215354
123  * BM_BiquadFilter/0/1/31       2176 ns         2171 ns       322492
124  * BM_BiquadFilter/0/2/1        1470 ns         1466 ns       477411
125  * BM_BiquadFilter/0/2/2        1109 ns         1107 ns       632666
126  * BM_BiquadFilter/0/2/3        1297 ns         1294 ns       540804
127  * BM_BiquadFilter/0/2/4        1681 ns         1677 ns       417675
128  * BM_BiquadFilter/0/2/5        2137 ns         2132 ns       328721
129  * BM_BiquadFilter/0/2/6        1572 ns         1569 ns       447114
130  * BM_BiquadFilter/0/2/7        1736 ns         1732 ns       385563
131  * BM_BiquadFilter/0/2/8        4331 ns         4320 ns       162048
132  * BM_BiquadFilter/0/2/9        3795 ns         3785 ns       184166
133  * BM_BiquadFilter/0/2/10       3832 ns         3823 ns       183015
134  * BM_BiquadFilter/0/2/11       5060 ns         5047 ns       138660
135  * BM_BiquadFilter/0/2/12       5046 ns         5034 ns       139033
136  * BM_BiquadFilter/0/2/13       4333 ns         4322 ns       161952
137  * BM_BiquadFilter/0/2/14       6500 ns         6482 ns       108022
138  * BM_BiquadFilter/0/2/15       4335 ns         4324 ns       161915
139  * BM_BiquadFilter/0/2/16       2965 ns         2957 ns       236771
140  * BM_BiquadFilter/0/2/17       4368 ns         4358 ns       160829
141  * BM_BiquadFilter/0/2/18       3193 ns         3186 ns       219766
142  * BM_BiquadFilter/0/2/19       2804 ns         2798 ns       250201
143  * BM_BiquadFilter/0/2/20       3839 ns         3830 ns       182731
144  * BM_BiquadFilter/0/2/21       5310 ns         5296 ns       133012
145  * BM_BiquadFilter/0/2/22       3995 ns         3984 ns       175672
146  * BM_BiquadFilter/0/2/23       3755 ns         3745 ns       186960
147  * BM_BiquadFilter/0/2/24       5060 ns         5045 ns       138733
148  * BM_BiquadFilter/0/2/25       4343 ns         4330 ns       161632
149  * BM_BiquadFilter/0/2/26       6505 ns         6489 ns       107871
150  * BM_BiquadFilter/0/2/27       4348 ns         4336 ns       161436
151  * BM_BiquadFilter/0/2/28       5068 ns         5054 ns       138515
152  * BM_BiquadFilter/0/2/29       4401 ns         4389 ns       158834
153  * BM_BiquadFilter/0/2/30       6514 ns         6497 ns       107752
154  * BM_BiquadFilter/0/2/31       4352 ns         4341 ns       161242
155  * BM_BiquadFilter/1/1/1         734 ns          732 ns       955891
156  * BM_BiquadFilter/1/1/2         554 ns          552 ns      1267096
157  * BM_BiquadFilter/1/1/3         647 ns          645 ns      1084919
158  * BM_BiquadFilter/1/1/4         834 ns          832 ns       841505
159  * BM_BiquadFilter/1/1/5        1068 ns         1065 ns       657299
160  * BM_BiquadFilter/1/1/6         767 ns          765 ns       915192
161  * BM_BiquadFilter/1/1/7         927 ns          924 ns       761606
162  * BM_BiquadFilter/1/1/8        2174 ns         2168 ns       322888
163  * BM_BiquadFilter/1/1/9        1832 ns         1826 ns       383311
164  * BM_BiquadFilter/1/1/10       1932 ns         1926 ns       363384
165  * BM_BiquadFilter/1/1/11       2536 ns         2529 ns       276796
166  * BM_BiquadFilter/1/1/12       2536 ns         2529 ns       276843
167  * BM_BiquadFilter/1/1/13       2175 ns         2169 ns       322743
168  * BM_BiquadFilter/1/1/14       3259 ns         3250 ns       215420
169  * BM_BiquadFilter/1/1/15       2175 ns         2169 ns       322745
170  * BM_BiquadFilter/1/1/16       1495 ns         1491 ns       469661
171  * BM_BiquadFilter/1/1/17       2177 ns         2171 ns       322388
172  * BM_BiquadFilter/1/1/18       1569 ns         1564 ns       447468
173  * BM_BiquadFilter/1/1/19       1325 ns         1322 ns       529736
174  * BM_BiquadFilter/1/1/20       1927 ns         1922 ns       363962
175  * BM_BiquadFilter/1/1/21       2624 ns         2617 ns       267102
176  * BM_BiquadFilter/1/1/22       1999 ns         1993 ns       351169
177  * BM_BiquadFilter/1/1/23       1882 ns         1877 ns       372944
178  * BM_BiquadFilter/1/1/24       2536 ns         2529 ns       276751
179  * BM_BiquadFilter/1/1/25       2176 ns         2170 ns       322560
180  * BM_BiquadFilter/1/1/26       3259 ns         3250 ns       215389
181  * BM_BiquadFilter/1/1/27       2175 ns         2169 ns       322640
182  * BM_BiquadFilter/1/1/28       2536 ns         2529 ns       276786
183  * BM_BiquadFilter/1/1/29       2176 ns         2170 ns       322533
184  * BM_BiquadFilter/1/1/30       3260 ns         3251 ns       215325
185  * BM_BiquadFilter/1/1/31       2177 ns         2171 ns       322425
186  * BM_BiquadFilter/1/2/1        1471 ns         1467 ns       477222
187  * BM_BiquadFilter/1/2/2        1109 ns         1107 ns       632565
188  * BM_BiquadFilter/1/2/3        1298 ns         1294 ns       541051
189  * BM_BiquadFilter/1/2/4        1682 ns         1678 ns       417354
190  * BM_BiquadFilter/1/2/5        2136 ns         2129 ns       328967
191  * BM_BiquadFilter/1/2/6        1572 ns         1568 ns       446095
192  * BM_BiquadFilter/1/2/7        1792 ns         1788 ns       399598
193  * BM_BiquadFilter/1/2/8        4333 ns         4320 ns       162032
194  * BM_BiquadFilter/1/2/9        3807 ns         3797 ns       184097
195  * BM_BiquadFilter/1/2/10       3842 ns         3831 ns       182711
196  * BM_BiquadFilter/1/2/11       5062 ns         5048 ns       138636
197  * BM_BiquadFilter/1/2/12       5050 ns         5036 ns       139031
198  * BM_BiquadFilter/1/2/13       4335 ns         4323 ns       161943
199  * BM_BiquadFilter/1/2/14       6500 ns         6483 ns       108020
200  * BM_BiquadFilter/1/2/15       4336 ns         4324 ns       161873
201  * BM_BiquadFilter/1/2/16       2966 ns         2957 ns       236709
202  * BM_BiquadFilter/1/2/17       4359 ns         4348 ns       160581
203  * BM_BiquadFilter/1/2/18       3196 ns         3187 ns       219532
204  * BM_BiquadFilter/1/2/19       2805 ns         2798 ns       250157
205  * BM_BiquadFilter/1/2/20       3839 ns         3829 ns       182628
206  * BM_BiquadFilter/1/2/21       5291 ns         5276 ns       131153
207  * BM_BiquadFilter/1/2/22       3994 ns         3984 ns       175699
208  * BM_BiquadFilter/1/2/23       3757 ns         3747 ns       186864
209  * BM_BiquadFilter/1/2/24       5060 ns         5046 ns       138754
210  * BM_BiquadFilter/1/2/25       4343 ns         4331 ns       161614
211  * BM_BiquadFilter/1/2/26       6512 ns         6491 ns       107852
212  * BM_BiquadFilter/1/2/27       4348 ns         4336 ns       161419
213  * BM_BiquadFilter/1/2/28       5068 ns         5055 ns       138481
214  * BM_BiquadFilter/1/2/29       4386 ns         4374 ns       159635
215  * BM_BiquadFilter/1/2/30       6514 ns         6498 ns       107752
216  * BM_BiquadFilter/1/2/31       4353 ns         4342 ns       161227
217  *******************************************************************/
218 
219 template <typename F>
BM_BiquadFilter(benchmark::State & state,bool optimized)220 static void BM_BiquadFilter(benchmark::State& state, bool optimized) {
221     bool isSubnormal = (state.range(0) == 1);
222     const size_t channelCount = state.range(1);
223     const size_t occupancy = state.range(2);
224 
225     std::vector<F> input(DATA_SIZE * channelCount);
226     std::vector<F> output(DATA_SIZE * channelCount);
227     std::array<F, android::audio_utils::kBiquadNumCoefs> coefs;
228 
229     // Initialize input buffer and coefs with deterministic pseudo-random values
230     std::minstd_rand gen(occupancy);
231     const F amplitude = isSubnormal ? std::numeric_limits<F>::min() * 0.1 : 1.;
232     std::uniform_real_distribution<> dis(-amplitude, amplitude);
233     for (size_t i = 0; i < DATA_SIZE * channelCount; ++i) {
234         input[i] = dis(gen);
235     }
236     for (size_t i = 0; i < coefs.size(); ++i) {
237         coefs[i] = (occupancy >> i & 1) * REF_COEFS[i];
238     }
239 
240     android::audio_utils::BiquadFilter<F> biquadFilter(channelCount, coefs, optimized);
241 
242     // Run the test
243     while (state.KeepRunning()) {
244         benchmark::DoNotOptimize(input.data());
245         benchmark::DoNotOptimize(output.data());
246         biquadFilter.process(output.data(), input.data(), DATA_SIZE);
247         benchmark::ClobberMemory();
248     }
249     state.SetComplexityN(state.range(1));  // O(channelCount)
250 }
251 
BM_BiquadFilterFloatOptimized(benchmark::State & state)252 static void BM_BiquadFilterFloatOptimized(benchmark::State& state) {
253     BM_BiquadFilter<float>(state, true /* optimized */);
254 }
255 
BM_BiquadFilterFloatNonOptimized(benchmark::State & state)256 static void BM_BiquadFilterFloatNonOptimized(benchmark::State& state) {
257     BM_BiquadFilter<float>(state, false /* optimized */);
258 }
259 
BM_BiquadFilterDoubleOptimized(benchmark::State & state)260 static void BM_BiquadFilterDoubleOptimized(benchmark::State& state) {
261     BM_BiquadFilter<double>(state, true /* optimized */);
262 }
263 
BM_BiquadFilterDoubleNonOptimized(benchmark::State & state)264 static void BM_BiquadFilterDoubleNonOptimized(benchmark::State& state) {
265     BM_BiquadFilter<double>(state, false /* optimized */);
266 }
267 
BiquadFilterQuickArgs(benchmark::internal::Benchmark * b)268 static void BiquadFilterQuickArgs(benchmark::internal::Benchmark* b) {
269     constexpr int CHANNEL_COUNT_BEGIN = 1;
270     constexpr int CHANNEL_COUNT_END = 24;
271     for (int k = 0; k < 1; k++) { // 0 for normal random data, 1 for subnormal random data
272         for (int i = CHANNEL_COUNT_BEGIN; i <= CHANNEL_COUNT_END; ++i) {
273             int j = (1 << android::audio_utils::kBiquadNumCoefs) - 1; // Full
274             b->Args({k, i, j});
275         }
276     }
277 }
278 
BiquadFilterFullArgs(benchmark::internal::Benchmark * b)279 static void BiquadFilterFullArgs(benchmark::internal::Benchmark* b) {
280     constexpr int CHANNEL_COUNT_BEGIN = 1;
281     constexpr int CHANNEL_COUNT_END = 4;
282     for (int k = 0; k < 2; k++) { // 0 for normal random data, 1 for subnormal random data
283         for (int i = CHANNEL_COUNT_BEGIN; i <= CHANNEL_COUNT_END; ++i) {
284             for (int j = 1; j < (1 << android::audio_utils::kBiquadNumCoefs); ++j) { // Occupancy
285                 b->Args({k, i, j});
286             }
287         }
288     }
289 }
290 
BiquadFilterDoubleArgs(benchmark::internal::Benchmark * b)291 static void BiquadFilterDoubleArgs(benchmark::internal::Benchmark* b) {
292     constexpr int CHANNEL_COUNT_BEGIN = 1;
293     constexpr int CHANNEL_COUNT_END = 4;
294     for (int k = 0; k < 1; k++) { // 0 for normal random data, 1 for subnormal random data
295         for (int i = CHANNEL_COUNT_BEGIN; i <= CHANNEL_COUNT_END; ++i) {
296             int j = (1 << android::audio_utils::kBiquadNumCoefs) - 1; // Full
297             b->Args({k, i, j});
298         }
299     }
300 }
301 
302 BENCHMARK(BM_BiquadFilterDoubleOptimized)->Apply(BiquadFilterDoubleArgs);
303 BENCHMARK(BM_BiquadFilterDoubleNonOptimized)->Apply(BiquadFilterDoubleArgs);
304 BENCHMARK(BM_BiquadFilterFloatOptimized)->Apply(BiquadFilterQuickArgs);
305 BENCHMARK(BM_BiquadFilterFloatNonOptimized)->Apply(BiquadFilterQuickArgs);
306 BENCHMARK(BM_BiquadFilterFloatOptimized)->Apply(BiquadFilterFullArgs);
307 
308 BENCHMARK_MAIN();
309