1 /*
2 * Copyright 2021 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 <random>
18 #include <vector>
19
20 #include <audio_effects/effect_downmix.h>
21 #include <audio_utils/channels.h>
22 #include <audio_utils/primitives.h>
23 #include <audio_utils/Statistics.h>
24 #include <benchmark/benchmark.h>
25 #include <log/log.h>
26 #include <system/audio.h>
27
28 #include "EffectDownmix.h"
29
30 extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
31
32 static constexpr audio_channel_mask_t kChannelPositionMasks[] = {
33 AUDIO_CHANNEL_OUT_FRONT_LEFT,
34 AUDIO_CHANNEL_OUT_FRONT_CENTER,
35 AUDIO_CHANNEL_OUT_STEREO,
36 AUDIO_CHANNEL_OUT_2POINT1,
37 AUDIO_CHANNEL_OUT_2POINT0POINT2,
38 AUDIO_CHANNEL_OUT_QUAD,
39 AUDIO_CHANNEL_OUT_QUAD_BACK,
40 AUDIO_CHANNEL_OUT_QUAD_SIDE,
41 AUDIO_CHANNEL_OUT_SURROUND,
42 AUDIO_CHANNEL_OUT_2POINT1POINT2,
43 AUDIO_CHANNEL_OUT_3POINT0POINT2,
44 AUDIO_CHANNEL_OUT_PENTA,
45 AUDIO_CHANNEL_OUT_3POINT1POINT2,
46 AUDIO_CHANNEL_OUT_5POINT1,
47 AUDIO_CHANNEL_OUT_5POINT1_BACK,
48 AUDIO_CHANNEL_OUT_5POINT1_SIDE,
49 AUDIO_CHANNEL_OUT_6POINT1,
50 AUDIO_CHANNEL_OUT_5POINT1POINT2,
51 AUDIO_CHANNEL_OUT_7POINT1,
52 AUDIO_CHANNEL_OUT_5POINT1POINT4,
53 AUDIO_CHANNEL_OUT_7POINT1POINT2,
54 AUDIO_CHANNEL_OUT_7POINT1POINT4,
55 AUDIO_CHANNEL_OUT_13POINT_360RA,
56 AUDIO_CHANNEL_OUT_22POINT2,
57 };
58
59 static constexpr effect_uuid_t downmix_uuid = {
60 0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
61
62 static constexpr size_t kFrameCount = 1000;
63
64 /*
65 Pixel 3XL
66 downmix_benchmark:
67 #BM_Downmix/0 4723 ns 4708 ns 148694
68 #BM_Downmix/1 4717 ns 4702 ns 148873
69 #BM_Downmix/2 4803 ns 4788 ns 145893
70 #BM_Downmix/3 5056 ns 5041 ns 139110
71 #BM_Downmix/4 4710 ns 4696 ns 149625
72 #BM_Downmix/5 1514 ns 1509 ns 463694
73 #BM_Downmix/6 1513 ns 1509 ns 463451
74 #BM_Downmix/7 1516 ns 1511 ns 463899
75 #BM_Downmix/8 4445 ns 4431 ns 157831
76 #BM_Downmix/9 5081 ns 5065 ns 138412
77 #BM_Downmix/10 4354 ns 4341 ns 161247
78 #BM_Downmix/11 4411 ns 4397 ns 158893
79 #BM_Downmix/12 4434 ns 4420 ns 157992
80 #BM_Downmix/13 4845 ns 4830 ns 144873
81 #BM_Downmix/14 4851 ns 4835 ns 144954
82 #BM_Downmix/15 4884 ns 4870 ns 144233
83 #BM_Downmix/16 5832 ns 5813 ns 120565
84 #BM_Downmix/17 5241 ns 5224 ns 133927
85 #BM_Downmix/18 5044 ns 5028 ns 139131
86 #BM_Downmix/19 5244 ns 5227 ns 132315
87 #BM_Downmix/20 5943 ns 5923 ns 117759
88 #BM_Downmix/21 5990 ns 5971 ns 117263
89 #BM_Downmix/22 4468 ns 4454 ns 156689
90 #BM_Downmix/23 7306 ns 7286 ns 95911
91 --
92 downmix_benchmark: (generic fold)
93 #BM_Downmix/0 4722 ns 4707 ns 149847
94 #BM_Downmix/1 4714 ns 4698 ns 148748
95 #BM_Downmix/2 4794 ns 4779 ns 145661
96 #BM_Downmix/3 5053 ns 5035 ns 139172
97 #BM_Downmix/4 4695 ns 4678 ns 149762
98 #BM_Downmix/5 4381 ns 4368 ns 159675
99 #BM_Downmix/6 4387 ns 4373 ns 160267
100 #BM_Downmix/7 4732 ns 4717 ns 148514
101 #BM_Downmix/8 4430 ns 4415 ns 158133
102 #BM_Downmix/9 5101 ns 5084 ns 138353
103 #BM_Downmix/10 4356 ns 4343 ns 160821
104 #BM_Downmix/11 4397 ns 4383 ns 159995
105 #BM_Downmix/12 4438 ns 4424 ns 158117
106 #BM_Downmix/13 5243 ns 5226 ns 133863
107 #BM_Downmix/14 5259 ns 5242 ns 131855
108 #BM_Downmix/15 5245 ns 5228 ns 133686
109 #BM_Downmix/16 5829 ns 5809 ns 120543
110 #BM_Downmix/17 5245 ns 5228 ns 133533
111 #BM_Downmix/18 5935 ns 5916 ns 118282
112 #BM_Downmix/19 5263 ns 5245 ns 133657
113 #BM_Downmix/20 5998 ns 5978 ns 114693
114 #BM_Downmix/21 5989 ns 5969 ns 117450
115 #BM_Downmix/22 4442 ns 4431 ns 157913
116 #BM_Downmix/23 7309 ns 7290 ns 95797
117 */
118
BM_Downmix(benchmark::State & state)119 static void BM_Downmix(benchmark::State& state) {
120 const audio_channel_mask_t channelMask = kChannelPositionMasks[state.range(0)];
121 const size_t channelCount = audio_channel_count_from_out_mask(channelMask);
122 const int sampleRate = 48000;
123
124 // Initialize input buffer with deterministic pseudo-random values
125 std::minstd_rand gen(channelMask);
126 std::uniform_real_distribution<> dis(-1.0f, 1.0f);
127 std::vector<float> input(kFrameCount * channelCount);
128 std::vector<float> output(kFrameCount * 2);
129 for (auto& in : input) {
130 in = dis(gen);
131 }
132 effect_handle_t effectHandle = nullptr;
133 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
134 &downmix_uuid, 1, 1, &effectHandle);
135 status != 0) {
136 ALOGE("create_effect returned an error = %d\n", status);
137 return;
138 }
139
140 effect_config_t config{};
141 config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
142 config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
143 config.inputCfg.bufferProvider.getBuffer = nullptr;
144 config.inputCfg.bufferProvider.releaseBuffer = nullptr;
145 config.inputCfg.bufferProvider.cookie = nullptr;
146 config.inputCfg.mask = EFFECT_CONFIG_ALL;
147
148 config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
149 config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
150 config.outputCfg.bufferProvider.getBuffer = nullptr;
151 config.outputCfg.bufferProvider.releaseBuffer = nullptr;
152 config.outputCfg.bufferProvider.cookie = nullptr;
153 config.outputCfg.mask = EFFECT_CONFIG_ALL;
154
155 config.inputCfg.samplingRate = sampleRate;
156 config.inputCfg.channels = channelMask;
157
158 config.outputCfg.samplingRate = sampleRate;
159 config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; // output always stereo
160
161 int reply = 0;
162 uint32_t replySize = sizeof(reply);
163 if (int status = (*effectHandle)
164 ->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
165 &config, &replySize, &reply);
166 status != 0) {
167 ALOGE("command returned an error = %d\n", status);
168 return;
169 }
170
171 if (int status = (*effectHandle)
172 ->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
173 status != 0) {
174 ALOGE("Command enable call returned error %d\n", reply);
175 return;
176 }
177
178 // Run the test
179 for (auto _ : state) {
180 benchmark::DoNotOptimize(input.data());
181 benchmark::DoNotOptimize(output.data());
182
183 audio_buffer_t inBuffer = {.frameCount = kFrameCount, .f32 = input.data()};
184 audio_buffer_t outBuffer = {.frameCount = kFrameCount, .f32 = output.data()};
185 (*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
186
187 benchmark::ClobberMemory();
188 }
189
190 state.SetComplexityN(state.range(0));
191
192 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
193 ALOGE("release_effect returned an error = %d\n", status);
194 return;
195 }
196 }
197
DownmixArgs(benchmark::internal::Benchmark * b)198 static void DownmixArgs(benchmark::internal::Benchmark* b) {
199 for (int i = 0; i < (int)std::size(kChannelPositionMasks); i++) {
200 b->Args({i});
201 }
202 }
203
204 BENCHMARK(BM_Downmix)->Apply(DownmixArgs);
205
206 BENCHMARK_MAIN();
207