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