xref: /aosp_15_r20/frameworks/av/media/libeffects/spatializer/benchmarks/spatializer_benchmark.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright 2022 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 <dlfcn.h>
19 #include <random>
20 #include <vector>
21 
22 #include <benchmark/benchmark.h>
23 #include <hardware/audio_effect.h>
24 #include <log/log.h>
25 
__anonb8ce4de70102null26 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = [] {
27     audio_effect_library_t symbol{};
28     void* effectLib = dlopen("libspatialaudio.so", RTLD_NOW);
29     if (effectLib) {
30         audio_effect_library_t* effectInterface =
31                 (audio_effect_library_t*)dlsym(effectLib, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
32         if (effectInterface == nullptr) {
33             ALOGE("dlsym failed: %s", dlerror());
34             dlclose(effectLib);
35             exit(-1);
36         }
37         symbol = (audio_effect_library_t)(*effectInterface);
38     } else {
39         ALOGE("dlopen failed: %s", dlerror());
40         exit(-1);
41     }
42     return symbol;
43 }();
44 
45 // channel masks
46 constexpr int kInputChMask = AUDIO_CHANNEL_OUT_5POINT1;
47 
48 // sampleRates
49 constexpr size_t kSampleRates[] = {
50         44100,
51         48000,
52         96000,
53 };
54 constexpr size_t kNumSampleRates = std::size(kSampleRates);
55 
56 // duration in ms
57 constexpr size_t kDurations[] = {2, 5, 10};
58 constexpr size_t kNumDurations = std::size(kDurations);
59 
60 // effect uuids
61 constexpr effect_uuid_t kEffectUuid = {
62         0xcc4677de, 0xff72, 0x11eb, 0x9a03, {0x02, 0x42, 0xac, 0x13, 0x00, 0x03}};
63 
64 constexpr float kMinAmplitude = -1.0f;
65 constexpr float kMaxAmplitude = 1.0f;
66 
67 /*******************************************************************
68  * A test result running on Pixel 5 for comparison.
69  * The first parameter indicates the sample rate.
70  * 0: 44100, 1: 48000, 2: 96000
71  * The second parameter indicates the duration in ms.
72  * 0: 2, 1: 5, 2: 10
73  * -------------------------------------------------------------
74  * Benchmark                   Time             CPU   Iterations
75  * -------------------------------------------------------------
76  * BM_SPATIALIZER/0/0     739848 ns       738497 ns          934
77  * BM_SPATIALIZER/0/1    1250503 ns      1248337 ns          480
78  * BM_SPATIALIZER/0/2    2094092 ns      2090092 ns          310
79  * BM_SPATIALIZER/1/0     783114 ns       781626 ns          683
80  * BM_SPATIALIZER/1/1    1332951 ns      1330473 ns          452
81  * BM_SPATIALIZER/1/2    2258313 ns      2254022 ns          289
82  * BM_SPATIALIZER/2/0    1210332 ns      1207957 ns          477
83  * BM_SPATIALIZER/2/1    2356259 ns      2351764 ns          269
84  * BM_SPATIALIZER/2/2    4267814 ns      4259567 ns          155
85  *******************************************************************/
86 
BM_SPATIALIZER(benchmark::State & state)87 static void BM_SPATIALIZER(benchmark::State& state) {
88     const size_t sampleRate = kSampleRates[state.range(0)];
89     const size_t durationMs = kDurations[state.range(1)];
90     const size_t frameCount = durationMs * sampleRate / 1000;
91     const size_t inputChannelCount = audio_channel_count_from_out_mask(kInputChMask);
92     const size_t outputChannelCount = audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
93 
94     // Initialize input buffer with deterministic pseudo-random values
95     std::minstd_rand gen(kInputChMask);
96     std::uniform_real_distribution<> dis(kMinAmplitude, kMaxAmplitude);
97     std::vector<float> input(frameCount * inputChannelCount);
98     for (auto& in : input) {
99         in = dis(gen);
100     }
101 
102     effect_handle_t effectHandle = nullptr;
103     if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&kEffectUuid, 1 /* sessionId */,
104                                                                  1 /* ioId */, &effectHandle);
105         status != 0) {
106         ALOGE("create_effect returned an error = %d\n", status);
107         return;
108     }
109 
110     effect_config_t config{};
111     config.inputCfg.samplingRate = config.outputCfg.samplingRate = sampleRate;
112     config.inputCfg.channels = kInputChMask;
113     config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
114     config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
115 
116     int reply = 0;
117     uint32_t replySize = sizeof(reply);
118     if (int status = (*effectHandle)
119                              ->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
120                                        &config, &replySize, &reply);
121         status != 0) {
122         ALOGE("command returned an error = %d\n", status);
123         return;
124     }
125 
126     if (int status = (*effectHandle)
127                              ->command(effectHandle, EFFECT_CMD_ENABLE, sizeof(effect_config_t),
128                                        &config, &replySize, &reply);
129         status != 0) {
130         ALOGE("command returned an error = %d\n", status);
131         return;
132     }
133 
134     // Run the test
135     std::vector<float> output(frameCount * outputChannelCount);
136     for (auto _ : state) {
137         benchmark::DoNotOptimize(input.data());
138         benchmark::DoNotOptimize(output.data());
139 
140         audio_buffer_t inBuffer = {.frameCount = frameCount, .f32 = input.data()};
141         audio_buffer_t outBuffer = {.frameCount = frameCount, .f32 = output.data()};
142         (*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
143 
144         benchmark::ClobberMemory();
145     }
146 
147     state.SetComplexityN(frameCount);
148 
149     if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
150         ALOGE("release_effect returned an error = %d\n", status);
151         return;
152     }
153 }
154 
SPATIALIZERArgs(benchmark::internal::Benchmark * b)155 static void SPATIALIZERArgs(benchmark::internal::Benchmark* b) {
156     for (int i = 0; i < kNumSampleRates; i++) {
157         for (int j = 0; j < kNumDurations; ++j) {
158             b->Args({i, j});
159         }
160     }
161 }
162 
163 BENCHMARK(BM_SPATIALIZER)->Apply(SPATIALIZERArgs);
164 
165 BENCHMARK_MAIN();
166