1 /*
2 * Copyright (C) 2019 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 "benchmark/benchmark.h"
18
19 #include <android/hardware/vibrator/1.3/IVibrator.h>
20 #include <android/hardware/vibrator/BnVibratorCallback.h>
21 #include <android/hardware/vibrator/IVibrator.h>
22 #include <binder/IServiceManager.h>
23
24 using ::android::enum_range;
25 using ::android::sp;
26 using ::android::hardware::hidl_enum_range;
27 using ::android::hardware::Return;
28 using ::android::hardware::details::hidl_enum_values;
29 using ::benchmark::Counter;
30 using ::benchmark::Fixture;
31 using ::benchmark::kMicrosecond;
32 using ::benchmark::State;
33 using ::benchmark::internal::Benchmark;
34 using ::std::chrono::duration;
35 using ::std::chrono::duration_cast;
36 using ::std::chrono::high_resolution_clock;
37
38 namespace Aidl = ::android::hardware::vibrator;
39 namespace V1_0 = ::android::hardware::vibrator::V1_0;
40 namespace V1_1 = ::android::hardware::vibrator::V1_1;
41 namespace V1_2 = ::android::hardware::vibrator::V1_2;
42 namespace V1_3 = ::android::hardware::vibrator::V1_3;
43
44 template <typename I>
45 class BaseBench : public Fixture {
46 public:
TearDown(State &)47 void TearDown(State& /*state*/) override {
48 if (!mVibrator) {
49 return;
50 }
51 mVibrator->off();
52 }
53
DefaultConfig(Benchmark * b)54 static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); }
55
DefaultArgs(Benchmark *)56 static void DefaultArgs(Benchmark* /*b*/) { /* none */
57 }
58
59 protected:
getOtherArg(const State & state,std::size_t index) const60 auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
61
62 protected:
63 sp<I> mVibrator;
64 };
65
66 template <typename I>
67 class VibratorBench : public BaseBench<I> {
68 public:
SetUp(State &)69 void SetUp(State& /*state*/) override { this->mVibrator = I::getService(); }
70 };
71
72 enum class EmptyEnum : uint32_t;
73 template <>
74 inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
75
76 template <typename T, typename U>
difference(const hidl_enum_range<T> & t,const hidl_enum_range<U> & u)77 std::set<T> difference(const hidl_enum_range<T>& t, const hidl_enum_range<U>& u) {
78 class Compare {
79 public:
80 bool operator()(const T& a, const U& b) { return a < static_cast<T>(b); }
81 bool operator()(const U& a, const T& b) { return static_cast<T>(a) < b; }
82 };
83 std::set<T> ret;
84
85 std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
86 std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
87
88 return ret;
89 }
90
91 template <typename I, typename E1, typename E2 = EmptyEnum>
92 class VibratorEffectsBench : public VibratorBench<I> {
93 public:
94 using Effect = E1;
95 using EffectStrength = V1_0::EffectStrength;
96 using Status = V1_0::Status;
97
98 public:
DefaultArgs(Benchmark * b)99 static void DefaultArgs(Benchmark* b) {
100 b->ArgNames({"Effect", "Strength"});
101 for (const auto& effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
102 for (const auto& strength : hidl_enum_range<EffectStrength>()) {
103 b->Args({static_cast<long>(effect), static_cast<long>(strength)});
104 }
105 }
106 }
107
performBench(State * state,Return<void> (I::* performApi)(Effect,EffectStrength,typename I::perform_cb))108 void performBench(State* state, Return<void> (I::*performApi)(Effect, EffectStrength,
109 typename I::perform_cb)) {
110 auto effect = getEffect(*state);
111 auto strength = getStrength(*state);
112 bool supported = true;
113
114 (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
115 if (status == Status::UNSUPPORTED_OPERATION) {
116 supported = false;
117 }
118 });
119
120 if (!supported) {
121 return;
122 }
123
124 for (auto _ : *state) {
125 state->ResumeTiming();
126 (*this->mVibrator.*performApi)(effect, strength,
127 [](Status /*status*/, uint32_t /*lengthMs*/) {});
128 state->PauseTiming();
129 this->mVibrator->off();
130 }
131 }
132
133 protected:
getEffect(const State & state) const134 auto getEffect(const State& state) const {
135 return static_cast<Effect>(this->getOtherArg(state, 0));
136 }
137
getStrength(const State & state) const138 auto getStrength(const State& state) const {
139 return static_cast<EffectStrength>(this->getOtherArg(state, 1));
140 }
141 };
142
143 #define BENCHMARK_WRAPPER(fixt, test, code) \
144 BENCHMARK_DEFINE_F(fixt, test) \
145 /* NOLINTNEXTLINE */ \
146 (State & state) { \
147 if (!mVibrator) { \
148 return; \
149 } \
150 \
151 code \
152 } \
153 BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
154
155 using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
156
157 BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
158 uint32_t ms = UINT32_MAX;
159
160 for (auto _ : state) {
161 state.ResumeTiming();
162 mVibrator->on(ms);
163 state.PauseTiming();
164 mVibrator->off();
165 }
166 });
167
168 BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
169 uint32_t ms = UINT32_MAX;
170
171 for (auto _ : state) {
172 state.PauseTiming();
173 mVibrator->on(ms);
174 state.ResumeTiming();
175 mVibrator->off();
176 }
177 });
178
179 BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
180 for (auto _ : state) {
181 mVibrator->supportsAmplitudeControl();
182 }
183 });
184
185 BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
186 uint8_t amplitude = UINT8_MAX;
187
188 if (!mVibrator->supportsAmplitudeControl()) {
189 return;
190 }
191
192 mVibrator->on(UINT32_MAX);
193
194 for (auto _ : state) {
195 mVibrator->setAmplitude(amplitude);
196 }
197
198 mVibrator->off();
199 });
200
201 using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
202
203 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
204 { performBench(&state, &V1_0::IVibrator::perform); });
205
206 using VibratorEffectsBench_V1_1 =
207 VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
208
209 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
210 { performBench(&state, &V1_1::IVibrator::perform_1_1); });
211
212 using VibratorEffectsBench_V1_2 =
213 VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
214
215 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
216 { performBench(&state, &V1_2::IVibrator::perform_1_2); });
217
218 using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
219
220 BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
221 for (auto _ : state) {
222 mVibrator->supportsExternalControl();
223 }
224 });
225
226 BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
227 bool enable = true;
228
229 if (!mVibrator->supportsExternalControl()) {
230 return;
231 }
232
233 for (auto _ : state) {
234 state.ResumeTiming();
235 mVibrator->setExternalControl(enable);
236 state.PauseTiming();
237 mVibrator->setExternalControl(false);
238 }
239 });
240
241 BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
242 if (!mVibrator->supportsExternalControl()) {
243 return;
244 }
245
246 mVibrator->setExternalControl(true);
247
248 for (auto _ : state) {
249 mVibrator->supportsAmplitudeControl();
250 }
251
252 mVibrator->setExternalControl(false);
253 });
254
255 BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
256 uint8_t amplitude = UINT8_MAX;
257
258 if (!mVibrator->supportsExternalControl()) {
259 return;
260 }
261
262 mVibrator->setExternalControl(true);
263
264 if (!mVibrator->supportsAmplitudeControl()) {
265 return;
266 }
267
268 for (auto _ : state) {
269 mVibrator->setAmplitude(amplitude);
270 }
271
272 mVibrator->setExternalControl(false);
273 });
274
275 using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
276
277 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
278 { performBench(&state, &V1_3::IVibrator::perform_1_3); });
279
280 class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
281 public:
SetUp(State &)282 void SetUp(State& /*state*/) override {
283 this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
284 }
285 };
286
287 class HalCallback : public Aidl::BnVibratorCallback {
288 public:
289 HalCallback() = default;
290 ~HalCallback() = default;
291
onComplete()292 android::binder::Status onComplete() override { return android::binder::Status::ok(); }
293 };
294
295 BENCHMARK_WRAPPER(VibratorBench_Aidl, on, {
296 int32_t capabilities = 0;
297 mVibrator->getCapabilities(&capabilities);
298
299 int32_t ms = INT32_MAX;
300 auto cb = (capabilities & Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
301
302 for (auto _ : state) {
303 state.ResumeTiming();
304 mVibrator->on(ms, cb);
305 state.PauseTiming();
306 mVibrator->off();
307 }
308 });
309
310 BENCHMARK_WRAPPER(VibratorBench_Aidl, off, {
311 for (auto _ : state) {
312 state.PauseTiming();
313 mVibrator->on(INT32_MAX, nullptr);
314 state.ResumeTiming();
315 mVibrator->off();
316 }
317 });
318
319 BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
320 int32_t capabilities = 0;
321
322 for (auto _ : state) {
323 mVibrator->getCapabilities(&capabilities);
324 }
325 });
326
327 BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
328 int32_t capabilities = 0;
329 mVibrator->getCapabilities(&capabilities);
330 if ((capabilities & Aidl::IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
331 return;
332 }
333
334 float amplitude = 1.0f;
335 mVibrator->on(INT32_MAX, nullptr);
336
337 for (auto _ : state) {
338 mVibrator->setAmplitude(amplitude);
339 }
340
341 mVibrator->off();
342 });
343
344 BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
345 int32_t capabilities = 0;
346 mVibrator->getCapabilities(&capabilities);
347 if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
348 return;
349 }
350
351 for (auto _ : state) {
352 state.ResumeTiming();
353 mVibrator->setExternalControl(true);
354 state.PauseTiming();
355 mVibrator->setExternalControl(false);
356 }
357 });
358
359 BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
360 int32_t capabilities = 0;
361 mVibrator->getCapabilities(&capabilities);
362 if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0 ||
363 (capabilities & Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) == 0) {
364 return;
365 }
366
367 float amplitude = 1.0f;
368 mVibrator->setExternalControl(true);
369
370 for (auto _ : state) {
371 mVibrator->setAmplitude(amplitude);
372 }
373
374 mVibrator->setExternalControl(false);
375 });
376
377 BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedEffects, {
378 std::vector<Aidl::Effect> supportedEffects;
379
380 for (auto _ : state) {
381 mVibrator->getSupportedEffects(&supportedEffects);
382 }
383 });
384
385 BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedAlwaysOnEffects, {
386 std::vector<Aidl::Effect> supportedEffects;
387
388 for (auto _ : state) {
389 mVibrator->getSupportedAlwaysOnEffects(&supportedEffects);
390 }
391 });
392
393 BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
394 std::vector<Aidl::CompositePrimitive> supportedPrimitives;
395
396 for (auto _ : state) {
397 mVibrator->getSupportedPrimitives(&supportedPrimitives);
398 }
399 });
400
401 class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {
402 public:
DefaultArgs(Benchmark * b)403 static void DefaultArgs(Benchmark* b) {
404 b->ArgNames({"Effect", "Strength"});
405 for (const auto& effect : enum_range<Aidl::Effect>()) {
406 for (const auto& strength : enum_range<Aidl::EffectStrength>()) {
407 b->Args({static_cast<long>(effect), static_cast<long>(strength)});
408 }
409 }
410 }
411
412 protected:
getEffect(const State & state) const413 auto getEffect(const State& state) const {
414 return static_cast<Aidl::Effect>(this->getOtherArg(state, 0));
415 }
416
getStrength(const State & state) const417 auto getStrength(const State& state) const {
418 return static_cast<Aidl::EffectStrength>(this->getOtherArg(state, 1));
419 }
420 };
421
422 BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
423 int32_t capabilities = 0;
424 mVibrator->getCapabilities(&capabilities);
425 if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
426 return;
427 }
428
429 int32_t id = 1;
430 auto effect = getEffect(state);
431 auto strength = getStrength(state);
432
433 std::vector<Aidl::Effect> supported;
434 mVibrator->getSupportedAlwaysOnEffects(&supported);
435 if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
436 return;
437 }
438
439 for (auto _ : state) {
440 state.ResumeTiming();
441 mVibrator->alwaysOnEnable(id, effect, strength);
442 state.PauseTiming();
443 mVibrator->alwaysOnDisable(id);
444 }
445 });
446
447 BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
448 int32_t capabilities = 0;
449 mVibrator->getCapabilities(&capabilities);
450 if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
451 return;
452 }
453
454 int32_t id = 1;
455 auto effect = getEffect(state);
456 auto strength = getStrength(state);
457
458 std::vector<Aidl::Effect> supported;
459 mVibrator->getSupportedAlwaysOnEffects(&supported);
460 if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
461 return;
462 }
463
464 for (auto _ : state) {
465 state.PauseTiming();
466 mVibrator->alwaysOnEnable(id, effect, strength);
467 state.ResumeTiming();
468 mVibrator->alwaysOnDisable(id);
469 }
470 });
471
472 BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, perform, {
473 int32_t capabilities = 0;
474 mVibrator->getCapabilities(&capabilities);
475
476 auto effect = getEffect(state);
477 auto strength = getStrength(state);
478 auto cb = (capabilities & Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback() : nullptr;
479 int32_t lengthMs = 0;
480
481 std::vector<Aidl::Effect> supported;
482 mVibrator->getSupportedEffects(&supported);
483 if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
484 return;
485 }
486
487 for (auto _ : state) {
488 state.ResumeTiming();
489 mVibrator->perform(effect, strength, cb, &lengthMs);
490 state.PauseTiming();
491 mVibrator->off();
492 }
493 });
494
495 class VibratorPrimitivesBench_Aidl : public VibratorBench_Aidl {
496 public:
DefaultArgs(Benchmark * b)497 static void DefaultArgs(Benchmark* b) {
498 b->ArgNames({"Primitive"});
499 for (const auto& primitive : enum_range<Aidl::CompositePrimitive>()) {
500 b->Args({static_cast<long>(primitive)});
501 }
502 }
503
504 protected:
getPrimitive(const State & state) const505 auto getPrimitive(const State& state) const {
506 return static_cast<Aidl::CompositePrimitive>(this->getOtherArg(state, 0));
507 }
508 };
509
510 BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionDelayMax, {
511 int32_t ms = 0;
512
513 for (auto _ : state) {
514 mVibrator->getCompositionDelayMax(&ms);
515 }
516 });
517
518 BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
519 int32_t size = 0;
520
521 for (auto _ : state) {
522 mVibrator->getCompositionSizeMax(&size);
523 }
524 });
525
526 BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
527 int32_t capabilities = 0;
528 mVibrator->getCapabilities(&capabilities);
529 if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
530 return;
531 }
532
533 auto primitive = getPrimitive(state);
534 int32_t ms = 0;
535
536 std::vector<Aidl::CompositePrimitive> supported;
537 mVibrator->getSupportedPrimitives(&supported);
538 if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
539 return;
540 }
541
542 for (auto _ : state) {
543 mVibrator->getPrimitiveDuration(primitive, &ms);
544 }
545 });
546
547 BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, compose, {
548 int32_t capabilities = 0;
549 mVibrator->getCapabilities(&capabilities);
550 if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
551 return;
552 }
553
554 Aidl::CompositeEffect effect;
555 effect.primitive = getPrimitive(state);
556 effect.scale = 1.0f;
557 effect.delayMs = 0;
558
559 std::vector<Aidl::CompositePrimitive> supported;
560 mVibrator->getSupportedPrimitives(&supported);
561 if (std::find(supported.begin(), supported.end(), effect.primitive) == supported.end()) {
562 return;
563 }
564
565 auto cb = new HalCallback();
566 std::vector<Aidl::CompositeEffect> effects;
567 effects.push_back(effect);
568
569 for (auto _ : state) {
570 state.ResumeTiming();
571 mVibrator->compose(effects, cb);
572 state.PauseTiming();
573 mVibrator->off();
574 }
575 });
576
577 BENCHMARK_MAIN();
578