blob: c4e0d6585d77d5fccb3a93c84cf6cb2888f34879 [file] [log] [blame]
/*
* Copyright 2021 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 <random>
#include <vector>
#include <audio_effects/effect_downmix.h>
#include <audio_utils/channels.h>
#include <audio_utils/primitives.h>
#include <audio_utils/Statistics.h>
#include <benchmark/benchmark.h>
#include <log/log.h>
#include <system/audio.h>
#include "EffectDownmix.h"
extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
static constexpr audio_channel_mask_t kChannelPositionMasks[] = {
AUDIO_CHANNEL_OUT_FRONT_LEFT,
AUDIO_CHANNEL_OUT_FRONT_CENTER,
AUDIO_CHANNEL_OUT_STEREO,
AUDIO_CHANNEL_OUT_2POINT1,
AUDIO_CHANNEL_OUT_2POINT0POINT2,
AUDIO_CHANNEL_OUT_QUAD, // AUDIO_CHANNEL_OUT_QUAD_BACK
AUDIO_CHANNEL_OUT_QUAD_SIDE,
AUDIO_CHANNEL_OUT_SURROUND,
AUDIO_CHANNEL_OUT_2POINT1POINT2,
AUDIO_CHANNEL_OUT_3POINT0POINT2,
AUDIO_CHANNEL_OUT_PENTA,
AUDIO_CHANNEL_OUT_3POINT1POINT2,
AUDIO_CHANNEL_OUT_5POINT1, // AUDIO_CHANNEL_OUT_5POINT1_BACK
AUDIO_CHANNEL_OUT_5POINT1_SIDE,
AUDIO_CHANNEL_OUT_6POINT1,
AUDIO_CHANNEL_OUT_5POINT1POINT2,
AUDIO_CHANNEL_OUT_7POINT1,
AUDIO_CHANNEL_OUT_5POINT1POINT4,
AUDIO_CHANNEL_OUT_7POINT1POINT2,
AUDIO_CHANNEL_OUT_7POINT1POINT4,
AUDIO_CHANNEL_OUT_13POINT_360RA,
AUDIO_CHANNEL_OUT_22POINT2,
};
static constexpr effect_uuid_t downmix_uuid = {
0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
static constexpr size_t kFrameCount = 1000;
/*
Pixel 7
$ atest downmix_benchmark
--------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------
downmix_benchmark:
#BM_Downmix/0 2216 ns 2208 ns 308323
#BM_Downmix/1 2237 ns 2228 ns 314730
#BM_Downmix/2 270 ns 268 ns 2681469
#BM_Downmix/3 3016 ns 2999 ns 234146
#BM_Downmix/4 3331 ns 3313 ns 212026
#BM_Downmix/5 816 ns 809 ns 864395
#BM_Downmix/6 813 ns 809 ns 863876
#BM_Downmix/7 3336 ns 3319 ns 211938
#BM_Downmix/8 3786 ns 3762 ns 185047
#BM_Downmix/9 3810 ns 3797 ns 186840
#BM_Downmix/10 3767 ns 3746 ns 187015
#BM_Downmix/11 4212 ns 4191 ns 166119
#BM_Downmix/12 1245 ns 1231 ns 574388
#BM_Downmix/13 1234 ns 1228 ns 574743
#BM_Downmix/14 4795 ns 4771 ns 147157
#BM_Downmix/15 1334 ns 1327 ns 527728
#BM_Downmix/16 1346 ns 1332 ns 525444
#BM_Downmix/17 2144 ns 2121 ns 333343
#BM_Downmix/18 2133 ns 2118 ns 330391
#BM_Downmix/19 2527 ns 2513 ns 278553
#BM_Downmix/20 8148 ns 8113 ns 86136
#BM_Downmix/21 6332 ns 6301 ns 111134
*/
static void BM_Downmix(benchmark::State& state) {
const audio_channel_mask_t channelMask = kChannelPositionMasks[state.range(0)];
const size_t channelCount = audio_channel_count_from_out_mask(channelMask);
const int sampleRate = 48000;
// Initialize input buffer with deterministic pseudo-random values
std::minstd_rand gen(channelMask);
std::uniform_real_distribution<> dis(-1.0f, 1.0f);
std::vector<float> input(kFrameCount * channelCount);
std::vector<float> output(kFrameCount * FCC_2);
for (auto& in : input) {
in = dis(gen);
}
effect_handle_t effectHandle = nullptr;
if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
&downmix_uuid, 1, 1, &effectHandle);
status != 0) {
ALOGE("create_effect returned an error = %d\n", status);
return;
}
effect_config_t config{};
config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
config.inputCfg.bufferProvider.getBuffer = nullptr;
config.inputCfg.bufferProvider.releaseBuffer = nullptr;
config.inputCfg.bufferProvider.cookie = nullptr;
config.inputCfg.mask = EFFECT_CONFIG_ALL;
config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
config.outputCfg.bufferProvider.getBuffer = nullptr;
config.outputCfg.bufferProvider.releaseBuffer = nullptr;
config.outputCfg.bufferProvider.cookie = nullptr;
config.outputCfg.mask = EFFECT_CONFIG_ALL;
config.inputCfg.samplingRate = sampleRate;
config.inputCfg.channels = channelMask;
config.outputCfg.samplingRate = sampleRate;
config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; // output always stereo
int reply = 0;
uint32_t replySize = sizeof(reply);
if (int status = (*effectHandle)
->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
&config, &replySize, &reply);
status != 0) {
ALOGE("command returned an error = %d\n", status);
return;
}
if (int status = (*effectHandle)
->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
status != 0) {
ALOGE("Command enable call returned error %d\n", reply);
return;
}
// Run the test
for (auto _ : state) {
benchmark::DoNotOptimize(input.data());
benchmark::DoNotOptimize(output.data());
audio_buffer_t inBuffer = {.frameCount = kFrameCount, .f32 = input.data()};
audio_buffer_t outBuffer = {.frameCount = kFrameCount, .f32 = output.data()};
(*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
benchmark::ClobberMemory();
}
state.SetComplexityN(channelCount);
state.SetLabel(audio_channel_out_mask_to_string(channelMask));
if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
ALOGE("release_effect returned an error = %d\n", status);
return;
}
}
static void DownmixArgs(benchmark::internal::Benchmark* b) {
for (int i = 0; i < (int)std::size(kChannelPositionMasks); i++) {
b->Args({i});
}
}
BENCHMARK(BM_Downmix)->Apply(DownmixArgs);
BENCHMARK_MAIN();