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 #include <log/log.h>
23 #include <benchmark/benchmark.h>
24 #include <hardware/audio_effect.h>
25 #include <system/audio.h>
26 #include "EffectReverb.h"
27
28 extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
29 constexpr effect_uuid_t kEffectUuids[] = {
30 {0x172cdf00,
31 0xa3bc,
32 0x11df,
33 0xa72f,
34 {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-insert mode
35 {0xf29a1400,
36 0xa3bb,
37 0x11df,
38 0x8ddc,
39 {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-aux mode
40 };
41
42 constexpr size_t kNumEffectUuids = std::size(kEffectUuids);
43
44 constexpr size_t kFrameCount = 2048;
45
46 constexpr int kPresets[] = {
47 REVERB_PRESET_NONE, REVERB_PRESET_SMALLROOM, REVERB_PRESET_MEDIUMROOM,
48 REVERB_PRESET_LARGEROOM, REVERB_PRESET_MEDIUMHALL, REVERB_PRESET_LARGEHALL,
49 REVERB_PRESET_PLATE,
50 };
51
52 constexpr size_t kNumPresets = std::size(kPresets);
53
54 constexpr int kSampleRate = 44100;
55
reverbSetConfigParam(uint32_t paramType,uint32_t paramValue,effect_handle_t effectHandle)56 int reverbSetConfigParam(uint32_t paramType, uint32_t paramValue, effect_handle_t effectHandle) {
57 int reply = 0;
58 uint32_t replySize = sizeof(reply);
59 uint32_t paramData[2] = {paramType, paramValue};
60 auto effectParam = (effect_param_t*)malloc(sizeof(effect_param_t) + sizeof(paramData));
61 memcpy(&effectParam->data[0], ¶mData[0], sizeof(paramData));
62 effectParam->psize = sizeof(paramData[0]);
63 effectParam->vsize = sizeof(paramData[1]);
64 int status = (*effectHandle)
65 ->command(effectHandle, EFFECT_CMD_SET_PARAM,
66 sizeof(effect_param_t) + sizeof(paramData), effectParam,
67 &replySize, &reply);
68 free(effectParam);
69 if (status != 0) {
70 ALOGE("Reverb set config returned an error = %d\n", status);
71 return status;
72 }
73 return reply;
74 }
75
76 /*******************************************************************
77 * A test result running on Pixel 3 with for comparison.
78 * The first parameter indicates the preset level id.
79 * The second parameter indicates the effect.
80 * 0: preset-insert mode, 1: preset-aux mode
81 * --------------------------------------------------------
82 * Benchmark Time CPU Iterations
83 * --------------------------------------------------------
84 * BM_REVERB/0/0 19312 ns 19249 ns 36282
85 * BM_REVERB/0/1 5613 ns 5596 ns 125032
86 * BM_REVERB/1/0 605453 ns 603714 ns 1131
87 * BM_REVERB/1/1 589421 ns 587758 ns 1161
88 * BM_REVERB/2/0 605760 ns 604006 ns 1131
89 * BM_REVERB/2/1 589434 ns 587777 ns 1161
90 * BM_REVERB/3/0 605574 ns 603828 ns 1131
91 * BM_REVERB/3/1 589566 ns 587862 ns 1162
92 * BM_REVERB/4/0 605634 ns 603894 ns 1131
93 * BM_REVERB/4/1 589506 ns 587856 ns 1161
94 * BM_REVERB/5/0 605644 ns 603929 ns 1131
95 * BM_REVERB/5/1 589592 ns 587863 ns 1161
96 * BM_REVERB/6/0 610544 ns 608561 ns 1131
97 * BM_REVERB/6/1 589686 ns 587871 ns 1161
98 *******************************************************************/
99
BM_REVERB(benchmark::State & state)100 static void BM_REVERB(benchmark::State& state) {
101 const size_t chMask = AUDIO_CHANNEL_OUT_STEREO;
102 const size_t preset = kPresets[state.range(0)];
103 const effect_uuid_t uuid = kEffectUuids[state.range(1)];
104 const size_t channelCount = audio_channel_count_from_out_mask(chMask);
105
106 // Initialize input buffer with deterministic pseudo-random values
107 std::minstd_rand gen(chMask);
108 std::uniform_real_distribution<> dis(-1.0f, 1.0f);
109 std::vector<float> input(kFrameCount * channelCount);
110 std::vector<float> output(kFrameCount * channelCount);
111 for (auto& in : input) {
112 in = dis(gen);
113 }
114
115 effect_handle_t effectHandle = nullptr;
116 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&uuid, 1, 1, &effectHandle);
117 status != 0) {
118 ALOGE("create_effect returned an error = %d\n", status);
119 return;
120 }
121
122 effect_config_t config{};
123 config.inputCfg.samplingRate = config.outputCfg.samplingRate = kSampleRate;
124 config.inputCfg.channels = config.outputCfg.channels = chMask;
125 config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
126
127 int reply = 0;
128 uint32_t replySize = sizeof(reply);
129 if (int status = (*effectHandle)
130 ->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
131 &config, &replySize, &reply);
132 status != 0) {
133 ALOGE("command returned an error = %d\n", status);
134 return;
135 }
136
137 if (int status =
138 (*effectHandle)
139 ->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
140 status != 0) {
141 ALOGE("Command enable call returned error %d\n", reply);
142 return;
143 }
144
145 if (int status = reverbSetConfigParam(REVERB_PARAM_PRESET, preset, effectHandle); status != 0) {
146 ALOGE("Invalid reverb preset. Error %d\n", status);
147 return;
148 }
149
150 // Run the test
151 for (auto _ : state) {
152 benchmark::DoNotOptimize(input.data());
153 benchmark::DoNotOptimize(output.data());
154
155 audio_buffer_t inBuffer = {.frameCount = kFrameCount, .f32 = input.data()};
156 audio_buffer_t outBuffer = {.frameCount = kFrameCount, .f32 = output.data()};
157 (*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
158
159 benchmark::ClobberMemory();
160 }
161
162 state.SetComplexityN(state.range(0));
163
164 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
165 ALOGE("release_effect returned an error = %d\n", status);
166 return;
167 }
168 }
169
REVERBArgs(benchmark::internal::Benchmark * b)170 static void REVERBArgs(benchmark::internal::Benchmark* b) {
171 for (int i = 0; i < kNumPresets; i++) {
172 for (int j = 0; j < kNumEffectUuids; ++j) {
173 b->Args({i, j});
174 }
175 }
176 }
177
178 BENCHMARK(BM_REVERB)->Apply(REVERBArgs);
179
180 BENCHMARK_MAIN();
181