blob: 0a61593973aaaf713a0d6e81f515b2ce93d27093 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <array>
#include <climits>
#include <cstdlib>
#include <random>
#include <vector>
#include <benchmark/benchmark.h>
#include <audio_utils/BiquadFilter.h>
#include <audio_utils/format.h>
static constexpr size_t DATA_SIZE = 1024;
// The coefficients is a HPF with sampling frequency as 48000, center frequency as 600,
// and Q as 0.707. As all the coefficients are not zero, they can be used to benchmark
// the non-zero optimization of BiquadFilter.
// The benchmark test will iterate the channel count from 1 to 2. The occupancy will be
// iterate from 1 to 31. In that case, it is possible to test the performance of cases
// with different coefficients as zero.
static constexpr float REF_COEFS[] = {0.9460f, -1.8919f, 0.9460f, -1.8890f, 0.8949f};
static void BM_BiquadFilter1D(benchmark::State& state) {
using android::audio_utils::BiquadFilter;
bool doParallel = (state.range(0) == 1);
// const size_t channelCount = state.range(1);
const size_t filters = 1;
std::vector<float> input(DATA_SIZE);
std::array<float, android::audio_utils::kBiquadNumCoefs> coefs;
// Initialize input buffer and coefs with deterministic pseudo-random values
constexpr std::minstd_rand::result_type SEED = 42; // arbitrary choice.
std::minstd_rand gen(SEED);
constexpr float amplitude = 1.0f;
std::uniform_real_distribution<> dis(-amplitude, amplitude);
for (size_t i = 0; i < DATA_SIZE; ++i) {
input[i] = dis(gen);
}
android::audio_utils::BiquadFilter parallel(filters, coefs);
std::vector<std::unique_ptr<BiquadFilter<float>>> biquads(filters);
for (auto& biquad : biquads) {
biquad.reset(new BiquadFilter<float>(1, coefs));
}
// Run the test
float *data = input.data();
while (state.KeepRunning()) {
benchmark::DoNotOptimize(data);
if (doParallel) {
parallel.process1D(data, DATA_SIZE);
} else {
for (auto& biquad : biquads) {
biquad->process(data, data, DATA_SIZE);
}
}
benchmark::ClobberMemory();
}
}
static void BiquadFilter1DArgs(benchmark::internal::Benchmark* b) {
for (int k = 0; k < 2; k++) // 0 for normal random data, 1 for subnormal random data
b->Args({k});
}
BENCHMARK(BM_BiquadFilter1D)->Apply(BiquadFilter1DArgs);
/*******************************************************************
* A test result running on Pixel 4 for comparison.
* The first parameter indicates the input data is subnormal or not.
* 0 for normal input data, 1 for subnormal input data.
* The second parameter indicates the channel count.
* The third parameter indicates the occupancy of the coefficients.
* -----------------------------------------------------------------
* Benchmark Time CPU Iterations
* -----------------------------------------------------------------
* BM_BiquadFilter/0/1/1 734 ns 732 ns 740671
* BM_BiquadFilter/0/1/2 554 ns 553 ns 1266836
* BM_BiquadFilter/0/1/3 647 ns 645 ns 1085314
* BM_BiquadFilter/0/1/4 834 ns 832 ns 841345
* BM_BiquadFilter/0/1/5 1068 ns 1065 ns 657343
* BM_BiquadFilter/0/1/6 767 ns 765 ns 915223
* BM_BiquadFilter/0/1/7 929 ns 926 ns 756405
* BM_BiquadFilter/0/1/8 2173 ns 2168 ns 322949
* BM_BiquadFilter/0/1/9 1831 ns 1826 ns 383304
* BM_BiquadFilter/0/1/10 1931 ns 1927 ns 363386
* BM_BiquadFilter/0/1/11 2536 ns 2529 ns 276783
* BM_BiquadFilter/0/1/12 2535 ns 2529 ns 276826
* BM_BiquadFilter/0/1/13 2174 ns 2169 ns 322755
* BM_BiquadFilter/0/1/14 3257 ns 3250 ns 215383
* BM_BiquadFilter/0/1/15 2175 ns 2169 ns 322711
* BM_BiquadFilter/0/1/16 1494 ns 1491 ns 469625
* BM_BiquadFilter/0/1/17 2176 ns 2171 ns 322423
* BM_BiquadFilter/0/1/18 1568 ns 1564 ns 447467
* BM_BiquadFilter/0/1/19 1325 ns 1322 ns 529762
* BM_BiquadFilter/0/1/20 1926 ns 1921 ns 364534
* BM_BiquadFilter/0/1/21 2630 ns 2623 ns 266027
* BM_BiquadFilter/0/1/22 1998 ns 1993 ns 351210
* BM_BiquadFilter/0/1/23 1882 ns 1877 ns 373028
* BM_BiquadFilter/0/1/24 2536 ns 2529 ns 276818
* BM_BiquadFilter/0/1/25 2176 ns 2170 ns 322627
* BM_BiquadFilter/0/1/26 3258 ns 3250 ns 215440
* BM_BiquadFilter/0/1/27 2175 ns 2169 ns 322724
* BM_BiquadFilter/0/1/28 2535 ns 2529 ns 276823
* BM_BiquadFilter/0/1/29 2175 ns 2170 ns 322560
* BM_BiquadFilter/0/1/30 3259 ns 3250 ns 215354
* BM_BiquadFilter/0/1/31 2176 ns 2171 ns 322492
* BM_BiquadFilter/0/2/1 1470 ns 1466 ns 477411
* BM_BiquadFilter/0/2/2 1109 ns 1107 ns 632666
* BM_BiquadFilter/0/2/3 1297 ns 1294 ns 540804
* BM_BiquadFilter/0/2/4 1681 ns 1677 ns 417675
* BM_BiquadFilter/0/2/5 2137 ns 2132 ns 328721
* BM_BiquadFilter/0/2/6 1572 ns 1569 ns 447114
* BM_BiquadFilter/0/2/7 1736 ns 1732 ns 385563
* BM_BiquadFilter/0/2/8 4331 ns 4320 ns 162048
* BM_BiquadFilter/0/2/9 3795 ns 3785 ns 184166
* BM_BiquadFilter/0/2/10 3832 ns 3823 ns 183015
* BM_BiquadFilter/0/2/11 5060 ns 5047 ns 138660
* BM_BiquadFilter/0/2/12 5046 ns 5034 ns 139033
* BM_BiquadFilter/0/2/13 4333 ns 4322 ns 161952
* BM_BiquadFilter/0/2/14 6500 ns 6482 ns 108022
* BM_BiquadFilter/0/2/15 4335 ns 4324 ns 161915
* BM_BiquadFilter/0/2/16 2965 ns 2957 ns 236771
* BM_BiquadFilter/0/2/17 4368 ns 4358 ns 160829
* BM_BiquadFilter/0/2/18 3193 ns 3186 ns 219766
* BM_BiquadFilter/0/2/19 2804 ns 2798 ns 250201
* BM_BiquadFilter/0/2/20 3839 ns 3830 ns 182731
* BM_BiquadFilter/0/2/21 5310 ns 5296 ns 133012
* BM_BiquadFilter/0/2/22 3995 ns 3984 ns 175672
* BM_BiquadFilter/0/2/23 3755 ns 3745 ns 186960
* BM_BiquadFilter/0/2/24 5060 ns 5045 ns 138733
* BM_BiquadFilter/0/2/25 4343 ns 4330 ns 161632
* BM_BiquadFilter/0/2/26 6505 ns 6489 ns 107871
* BM_BiquadFilter/0/2/27 4348 ns 4336 ns 161436
* BM_BiquadFilter/0/2/28 5068 ns 5054 ns 138515
* BM_BiquadFilter/0/2/29 4401 ns 4389 ns 158834
* BM_BiquadFilter/0/2/30 6514 ns 6497 ns 107752
* BM_BiquadFilter/0/2/31 4352 ns 4341 ns 161242
* BM_BiquadFilter/1/1/1 734 ns 732 ns 955891
* BM_BiquadFilter/1/1/2 554 ns 552 ns 1267096
* BM_BiquadFilter/1/1/3 647 ns 645 ns 1084919
* BM_BiquadFilter/1/1/4 834 ns 832 ns 841505
* BM_BiquadFilter/1/1/5 1068 ns 1065 ns 657299
* BM_BiquadFilter/1/1/6 767 ns 765 ns 915192
* BM_BiquadFilter/1/1/7 927 ns 924 ns 761606
* BM_BiquadFilter/1/1/8 2174 ns 2168 ns 322888
* BM_BiquadFilter/1/1/9 1832 ns 1826 ns 383311
* BM_BiquadFilter/1/1/10 1932 ns 1926 ns 363384
* BM_BiquadFilter/1/1/11 2536 ns 2529 ns 276796
* BM_BiquadFilter/1/1/12 2536 ns 2529 ns 276843
* BM_BiquadFilter/1/1/13 2175 ns 2169 ns 322743
* BM_BiquadFilter/1/1/14 3259 ns 3250 ns 215420
* BM_BiquadFilter/1/1/15 2175 ns 2169 ns 322745
* BM_BiquadFilter/1/1/16 1495 ns 1491 ns 469661
* BM_BiquadFilter/1/1/17 2177 ns 2171 ns 322388
* BM_BiquadFilter/1/1/18 1569 ns 1564 ns 447468
* BM_BiquadFilter/1/1/19 1325 ns 1322 ns 529736
* BM_BiquadFilter/1/1/20 1927 ns 1922 ns 363962
* BM_BiquadFilter/1/1/21 2624 ns 2617 ns 267102
* BM_BiquadFilter/1/1/22 1999 ns 1993 ns 351169
* BM_BiquadFilter/1/1/23 1882 ns 1877 ns 372944
* BM_BiquadFilter/1/1/24 2536 ns 2529 ns 276751
* BM_BiquadFilter/1/1/25 2176 ns 2170 ns 322560
* BM_BiquadFilter/1/1/26 3259 ns 3250 ns 215389
* BM_BiquadFilter/1/1/27 2175 ns 2169 ns 322640
* BM_BiquadFilter/1/1/28 2536 ns 2529 ns 276786
* BM_BiquadFilter/1/1/29 2176 ns 2170 ns 322533
* BM_BiquadFilter/1/1/30 3260 ns 3251 ns 215325
* BM_BiquadFilter/1/1/31 2177 ns 2171 ns 322425
* BM_BiquadFilter/1/2/1 1471 ns 1467 ns 477222
* BM_BiquadFilter/1/2/2 1109 ns 1107 ns 632565
* BM_BiquadFilter/1/2/3 1298 ns 1294 ns 541051
* BM_BiquadFilter/1/2/4 1682 ns 1678 ns 417354
* BM_BiquadFilter/1/2/5 2136 ns 2129 ns 328967
* BM_BiquadFilter/1/2/6 1572 ns 1568 ns 446095
* BM_BiquadFilter/1/2/7 1792 ns 1788 ns 399598
* BM_BiquadFilter/1/2/8 4333 ns 4320 ns 162032
* BM_BiquadFilter/1/2/9 3807 ns 3797 ns 184097
* BM_BiquadFilter/1/2/10 3842 ns 3831 ns 182711
* BM_BiquadFilter/1/2/11 5062 ns 5048 ns 138636
* BM_BiquadFilter/1/2/12 5050 ns 5036 ns 139031
* BM_BiquadFilter/1/2/13 4335 ns 4323 ns 161943
* BM_BiquadFilter/1/2/14 6500 ns 6483 ns 108020
* BM_BiquadFilter/1/2/15 4336 ns 4324 ns 161873
* BM_BiquadFilter/1/2/16 2966 ns 2957 ns 236709
* BM_BiquadFilter/1/2/17 4359 ns 4348 ns 160581
* BM_BiquadFilter/1/2/18 3196 ns 3187 ns 219532
* BM_BiquadFilter/1/2/19 2805 ns 2798 ns 250157
* BM_BiquadFilter/1/2/20 3839 ns 3829 ns 182628
* BM_BiquadFilter/1/2/21 5291 ns 5276 ns 131153
* BM_BiquadFilter/1/2/22 3994 ns 3984 ns 175699
* BM_BiquadFilter/1/2/23 3757 ns 3747 ns 186864
* BM_BiquadFilter/1/2/24 5060 ns 5046 ns 138754
* BM_BiquadFilter/1/2/25 4343 ns 4331 ns 161614
* BM_BiquadFilter/1/2/26 6512 ns 6491 ns 107852
* BM_BiquadFilter/1/2/27 4348 ns 4336 ns 161419
* BM_BiquadFilter/1/2/28 5068 ns 5055 ns 138481
* BM_BiquadFilter/1/2/29 4386 ns 4374 ns 159635
* BM_BiquadFilter/1/2/30 6514 ns 6498 ns 107752
* BM_BiquadFilter/1/2/31 4353 ns 4342 ns 161227
*******************************************************************/
template <typename F>
static void BM_BiquadFilter(benchmark::State& state, bool optimized) {
bool isSubnormal = (state.range(0) == 1);
const size_t channelCount = state.range(1);
const size_t occupancy = state.range(2);
std::vector<F> input(DATA_SIZE * channelCount);
std::vector<F> output(DATA_SIZE * channelCount);
std::array<F, android::audio_utils::kBiquadNumCoefs> coefs;
// Initialize input buffer and coefs with deterministic pseudo-random values
std::minstd_rand gen(occupancy);
const F amplitude = isSubnormal ? std::numeric_limits<F>::min() * 0.1 : 1.;
std::uniform_real_distribution<> dis(-amplitude, amplitude);
for (size_t i = 0; i < DATA_SIZE * channelCount; ++i) {
input[i] = dis(gen);
}
for (size_t i = 0; i < coefs.size(); ++i) {
coefs[i] = (occupancy >> i & 1) * REF_COEFS[i];
}
android::audio_utils::BiquadFilter<F> biquadFilter(channelCount, coefs, optimized);
// Run the test
while (state.KeepRunning()) {
benchmark::DoNotOptimize(input.data());
benchmark::DoNotOptimize(output.data());
biquadFilter.process(output.data(), input.data(), DATA_SIZE);
benchmark::ClobberMemory();
}
state.SetComplexityN(state.range(1)); // O(channelCount)
}
static void BM_BiquadFilterFloatOptimized(benchmark::State& state) {
BM_BiquadFilter<float>(state, true /* optimized */);
}
static void BM_BiquadFilterFloatNonOptimized(benchmark::State& state) {
BM_BiquadFilter<float>(state, false /* optimized */);
}
static void BM_BiquadFilterDoubleOptimized(benchmark::State& state) {
BM_BiquadFilter<double>(state, true /* optimized */);
}
static void BM_BiquadFilterDoubleNonOptimized(benchmark::State& state) {
BM_BiquadFilter<double>(state, false /* optimized */);
}
static void BiquadFilterQuickArgs(benchmark::internal::Benchmark* b) {
constexpr int CHANNEL_COUNT_BEGIN = 1;
constexpr int CHANNEL_COUNT_END = 24;
for (int k = 0; k < 1; k++) { // 0 for normal random data, 1 for subnormal random data
for (int i = CHANNEL_COUNT_BEGIN; i <= CHANNEL_COUNT_END; ++i) {
int j = (1 << android::audio_utils::kBiquadNumCoefs) - 1; // Full
b->Args({k, i, j});
}
}
}
static void BiquadFilterFullArgs(benchmark::internal::Benchmark* b) {
constexpr int CHANNEL_COUNT_BEGIN = 1;
constexpr int CHANNEL_COUNT_END = 4;
for (int k = 0; k < 2; k++) { // 0 for normal random data, 1 for subnormal random data
for (int i = CHANNEL_COUNT_BEGIN; i <= CHANNEL_COUNT_END; ++i) {
for (int j = 1; j < (1 << android::audio_utils::kBiquadNumCoefs); ++j) { // Occupancy
b->Args({k, i, j});
}
}
}
}
static void BiquadFilterDoubleArgs(benchmark::internal::Benchmark* b) {
constexpr int CHANNEL_COUNT_BEGIN = 1;
constexpr int CHANNEL_COUNT_END = 4;
for (int k = 0; k < 1; k++) { // 0 for normal random data, 1 for subnormal random data
for (int i = CHANNEL_COUNT_BEGIN; i <= CHANNEL_COUNT_END; ++i) {
int j = (1 << android::audio_utils::kBiquadNumCoefs) - 1; // Full
b->Args({k, i, j});
}
}
}
BENCHMARK(BM_BiquadFilterDoubleOptimized)->Apply(BiquadFilterDoubleArgs);
BENCHMARK(BM_BiquadFilterDoubleNonOptimized)->Apply(BiquadFilterDoubleArgs);
BENCHMARK(BM_BiquadFilterFloatOptimized)->Apply(BiquadFilterQuickArgs);
BENCHMARK(BM_BiquadFilterFloatNonOptimized)->Apply(BiquadFilterQuickArgs);
BENCHMARK(BM_BiquadFilterFloatOptimized)->Apply(BiquadFilterFullArgs);
BENCHMARK_MAIN();