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 <aidl/android/hardware/vibrator/BnVibratorCallback.h>
20 #include <aidl/android/hardware/vibrator/IVibrator.h>
21
22 #include <android/binder_manager.h>
23 #include <android/binder_process.h>
24 #include <android/hardware/vibrator/1.3/IVibrator.h>
25 #include <future>
26
27 using ::android::hardware::hidl_enum_range;
28 using ::android::hardware::Return;
29 using ::android::hardware::details::hidl_enum_values;
30 using ::benchmark::Counter;
31 using ::benchmark::Fixture;
32 using ::benchmark::kMicrosecond;
33 using ::benchmark::State;
34 using ::benchmark::internal::Benchmark;
35 using ::ndk::enum_range;
36
37 using namespace ::std::chrono_literals;
38
39 namespace Aidl = ::aidl::android::hardware::vibrator;
40 namespace V1_0 = ::android::hardware::vibrator::V1_0;
41 namespace V1_1 = ::android::hardware::vibrator::V1_1;
42 namespace V1_2 = ::android::hardware::vibrator::V1_2;
43 namespace V1_3 = ::android::hardware::vibrator::V1_3;
44
45 // Fixed number of iterations for benchmarks that trigger a vibration on the loop.
46 // They require slow cleanup to ensure a stable state on each run and less noisy metrics.
47 static constexpr auto VIBRATION_ITERATIONS = 500;
48
49 // Timeout to wait for vibration callback completion.
50 static constexpr auto VIBRATION_CALLBACK_TIMEOUT = 100ms;
51
52 // Max duration the vibrator can be turned on, in milliseconds.
53 static constexpr uint32_t MAX_ON_DURATION_MS = UINT16_MAX;
54
55 template <typename I>
56 class BaseBench : public Fixture {
57 public:
SetUp(State &)58 void SetUp(State& /*state*/) override {
59 ABinderProcess_setThreadPoolMaxThreadCount(1);
60 ABinderProcess_startThreadPool();
61 }
62
TearDown(State &)63 void TearDown(State& /*state*/) override {
64 if (mVibrator) {
65 mVibrator->off();
66 }
67 }
68
DefaultConfig(Benchmark * b)69 static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); }
70
DefaultArgs(Benchmark *)71 static void DefaultArgs(Benchmark* /*b*/) { /* none */
72 }
73
74 protected:
getOtherArg(const State & state,std::size_t index) const75 auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
76
77 protected:
78 std::shared_ptr<I> mVibrator;
79 };
80
81 template <typename I>
82 class VibratorBench : public BaseBench<I> {
83 public:
SetUp(State & state)84 void SetUp(State& state) override {
85 BaseBench<I>::SetUp(state);
86 auto service = I::getService();
87 if (service) {
88 this->mVibrator = std::shared_ptr<I>(service.release());
89 } else {
90 this->mVibrator = nullptr;
91 }
92 }
93
94 protected:
shouldSkipWithError(State & state,const android::hardware::Return<V1_0::Status> && ret)95 bool shouldSkipWithError(State& state, const android::hardware::Return<V1_0::Status>&& ret) {
96 if (!ret.isOk()) {
97 state.SkipWithError(ret.description());
98 return true;
99 }
100 return false;
101 }
102 };
103
104 enum class EmptyEnum : uint32_t;
105 template <>
106 inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
107
108 template <typename T, typename U>
difference(const hidl_enum_range<T> & t,const hidl_enum_range<U> & u)109 std::set<T> difference(const hidl_enum_range<T>& t, const hidl_enum_range<U>& u) {
110 class Compare {
111 public:
112 bool operator()(const T& a, const U& b) { return a < static_cast<T>(b); }
113 bool operator()(const U& a, const T& b) { return static_cast<T>(a) < b; }
114 };
115 std::set<T> ret;
116
117 std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
118 std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
119
120 return ret;
121 }
122
123 template <typename I, typename E1, typename E2 = EmptyEnum>
124 class VibratorEffectsBench : public VibratorBench<I> {
125 public:
126 using Effect = E1;
127 using EffectStrength = V1_0::EffectStrength;
128 using Status = V1_0::Status;
129
130 public:
DefaultArgs(Benchmark * b)131 static void DefaultArgs(Benchmark* b) {
132 b->ArgNames({"Effect", "Strength"});
133 for (const auto& effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
134 for (const auto& strength : hidl_enum_range<EffectStrength>()) {
135 b->Args({static_cast<long>(effect), static_cast<long>(strength)});
136 }
137 }
138 }
139
performBench(State * state,Return<void> (I::* performApi)(Effect,EffectStrength,typename I::perform_cb))140 void performBench(State* state, Return<void> (I::*performApi)(Effect, EffectStrength,
141 typename I::perform_cb)) {
142 auto effect = getEffect(*state);
143 auto strength = getStrength(*state);
144 bool supported = true;
145
146 (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
147 if (status == Status::UNSUPPORTED_OPERATION) {
148 supported = false;
149 }
150 });
151
152 if (!supported) {
153 state->SkipWithMessage("effect unsupported");
154 return;
155 }
156
157 for (auto _ : *state) {
158 // Test
159 auto ret = (*this->mVibrator.*performApi)(
160 effect, strength, [](Status /*status*/, uint32_t /*lengthMs*/) {});
161
162 // Cleanup
163 state->PauseTiming();
164 if (!ret.isOk()) {
165 state->SkipWithError(ret.description());
166 return;
167 }
168 if (this->shouldSkipWithError(*state, this->mVibrator->off())) {
169 return;
170 }
171 state->ResumeTiming();
172 }
173 }
174
175 protected:
getEffect(const State & state) const176 auto getEffect(const State& state) const {
177 return static_cast<Effect>(this->getOtherArg(state, 0));
178 }
179
getStrength(const State & state) const180 auto getStrength(const State& state) const {
181 return static_cast<EffectStrength>(this->getOtherArg(state, 1));
182 }
183 };
184
185 #define BENCHMARK_WRAPPER(fixt, test, code) \
186 BENCHMARK_DEFINE_F(fixt, test) \
187 /* NOLINTNEXTLINE */ \
188 (State & state) { \
189 if (!mVibrator) { \
190 state.SkipWithMessage("HAL unavailable"); \
191 return; \
192 } \
193 \
194 code \
195 } \
196 BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
197
198 using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
199
200 BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
201 auto ms = MAX_ON_DURATION_MS;
202
203 for (auto _ : state) {
204 // Test
205 if (shouldSkipWithError(state, mVibrator->on(ms))) {
206 return;
207 }
208
209 // Cleanup
210 state.PauseTiming();
211 if (shouldSkipWithError(state, mVibrator->off())) {
212 return;
213 }
214 state.ResumeTiming();
215 }
216 });
217
218 BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
219 auto ms = MAX_ON_DURATION_MS;
220
221 for (auto _ : state) {
222 // Setup
223 state.PauseTiming();
224 if (shouldSkipWithError(state, mVibrator->on(ms))) {
225 return;
226 }
227 state.ResumeTiming();
228
229 // Test
230 if (shouldSkipWithError(state, mVibrator->off())) {
231 return;
232 }
233 }
234 });
235
236 BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
237 for (auto _ : state) {
238 mVibrator->supportsAmplitudeControl();
239 }
240 });
241
242 BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
243 auto ms = MAX_ON_DURATION_MS;
244 uint8_t amplitude = UINT8_MAX;
245
246 if (!mVibrator->supportsAmplitudeControl()) {
247 state.SkipWithMessage("amplitude control unavailable");
248 return;
249 }
250
251 if (shouldSkipWithError(state, mVibrator->on(ms))) {
252 return;
253 }
254
255 for (auto _ : state) {
256 if (shouldSkipWithError(state, mVibrator->setAmplitude(amplitude))) {
257 return;
258 }
259 }
260 });
261
262 using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
263
264 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
265 { performBench(&state, &V1_0::IVibrator::perform); });
266
267 using VibratorEffectsBench_V1_1 =
268 VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
269
270 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
271 { performBench(&state, &V1_1::IVibrator::perform_1_1); });
272
273 using VibratorEffectsBench_V1_2 =
274 VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
275
276 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
277 { performBench(&state, &V1_2::IVibrator::perform_1_2); });
278
279 class VibratorBench_V1_3 : public VibratorBench<V1_3::IVibrator> {
280 public:
TearDown(State & state)281 void TearDown(State& state) override {
282 VibratorBench::TearDown(state);
283 if (mVibrator) {
284 mVibrator->setExternalControl(false);
285 }
286 }
287 };
288
289 BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
290 for (auto _ : state) {
291 mVibrator->supportsExternalControl();
292 }
293 });
294
295 BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
296 if (!mVibrator->supportsExternalControl()) {
297 state.SkipWithMessage("external control unavailable");
298 return;
299 }
300
301 for (auto _ : state) {
302 // Test
303 if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
304 return;
305 }
306
307 // Cleanup
308 state.PauseTiming();
309 if (shouldSkipWithError(state, mVibrator->setExternalControl(false))) {
310 return;
311 }
312 state.ResumeTiming();
313 }
314 });
315
316 BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
317 if (!mVibrator->supportsExternalControl()) {
318 state.SkipWithMessage("external control unavailable");
319 return;
320 }
321
322 if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
323 return;
324 }
325
326 for (auto _ : state) {
327 mVibrator->supportsAmplitudeControl();
328 }
329 });
330
331 BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
332 uint8_t amplitude = UINT8_MAX;
333
334 if (!mVibrator->supportsExternalControl()) {
335 state.SkipWithMessage("external control unavailable");
336 return;
337 }
338
339 if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
340 return;
341 }
342
343 if (!mVibrator->supportsAmplitudeControl()) {
344 state.SkipWithMessage("amplitude control unavailable");
345 return;
346 }
347
348 for (auto _ : state) {
349 if (shouldSkipWithError(state, mVibrator->setAmplitude(amplitude))) {
350 return;
351 }
352 }
353 });
354
355 using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
356
357 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
358 { performBench(&state, &V1_3::IVibrator::perform_1_3); });
359
360 class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
361 public:
SetUp(State & state)362 void SetUp(State& state) override {
363 BaseBench::SetUp(state);
364 auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default";
365 this->mVibrator = Aidl::IVibrator::fromBinder(
366 ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
367 }
368
TearDown(State & state)369 void TearDown(State& state) override {
370 BaseBench::TearDown(state);
371 if (mVibrator) {
372 mVibrator->setExternalControl(false);
373 }
374 }
375
376 protected:
hasCapabilities(int32_t capabilities)377 int32_t hasCapabilities(int32_t capabilities) {
378 int32_t deviceCapabilities = 0;
379 this->mVibrator->getCapabilities(&deviceCapabilities);
380 return (deviceCapabilities & capabilities) == capabilities;
381 }
382
shouldSkipWithError(State & state,const ndk::ScopedAStatus && status)383 bool shouldSkipWithError(State& state, const ndk::ScopedAStatus&& status) {
384 if (!status.isOk()) {
385 state.SkipWithError(status.getMessage());
386 return true;
387 }
388 return false;
389 }
390
waitForComplete(std::future<void> & callbackFuture)391 void waitForComplete(std::future<void>& callbackFuture) {
392 // Wait until the HAL has finished processing previous vibration before starting a new one,
393 // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest
394 // HAL implementations are waiting on previous vibration cleanup and might be significantly
395 // slower, so make sure we measure vibrations on a clean slate.
396 if (callbackFuture.valid()) {
397 callbackFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT);
398 }
399 }
400
SlowBenchConfig(Benchmark * b)401 static void SlowBenchConfig(Benchmark* b) { b->Iterations(VIBRATION_ITERATIONS); }
402 };
403
404 class SlowVibratorBench_Aidl : public VibratorBench_Aidl {
405 public:
DefaultConfig(Benchmark * b)406 static void DefaultConfig(Benchmark* b) {
407 VibratorBench_Aidl::DefaultConfig(b);
408 SlowBenchConfig(b);
409 }
410 };
411
412 class HalCallback : public Aidl::BnVibratorCallback {
413 public:
414 HalCallback() = default;
415 ~HalCallback() = default;
416
onComplete()417 ndk::ScopedAStatus onComplete() override {
418 mPromise.set_value();
419 return ndk::ScopedAStatus::ok();
420 }
421
getFuture()422 std::future<void> getFuture() { return mPromise.get_future(); }
423
424 private:
425 std::promise<void> mPromise;
426 };
427
428 BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, on, {
429 auto ms = MAX_ON_DURATION_MS;
430
431 for (auto _ : state) {
432 auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
433 ? ndk::SharedRefBase::make<HalCallback>()
434 : nullptr;
435 // Grab the future before callback promise is destroyed by the HAL.
436 auto cbFuture = cb ? cb->getFuture() : std::future<void>();
437
438 // Test
439 if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
440 return;
441 }
442
443 // Cleanup
444 state.PauseTiming();
445 if (shouldSkipWithError(state, mVibrator->off())) {
446 return;
447 }
448 waitForComplete(cbFuture);
449 state.ResumeTiming();
450 }
451 });
452
453 BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, off, {
454 auto ms = MAX_ON_DURATION_MS;
455
456 for (auto _ : state) {
457 auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
458 ? ndk::SharedRefBase::make<HalCallback>()
459 : nullptr;
460 // Grab the future before callback promise is destroyed by the HAL.
461 auto cbFuture = cb ? cb->getFuture() : std::future<void>();
462
463 // Setup
464 state.PauseTiming();
465 if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
466 return;
467 }
468 state.ResumeTiming();
469
470 // Test
471 if (shouldSkipWithError(state, mVibrator->off())) {
472 return;
473 }
474
475 // Cleanup
476 state.PauseTiming();
477 waitForComplete(cbFuture);
478 state.ResumeTiming();
479 }
480 });
481
482 BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
483 int32_t capabilities = 0;
484
485 for (auto _ : state) {
486 if (shouldSkipWithError(state, mVibrator->getCapabilities(&capabilities))) {
487 return;
488 }
489 }
490 });
491
492 BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
493 auto ms = MAX_ON_DURATION_MS;
494 float amplitude = 1.0f;
495
496 if (!hasCapabilities(Aidl::IVibrator::CAP_AMPLITUDE_CONTROL)) {
497 state.SkipWithMessage("amplitude control unavailable");
498 return;
499 }
500
501 auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
502 ? ndk::SharedRefBase::make<HalCallback>()
503 : nullptr;
504 if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
505 return;
506 }
507
508 for (auto _ : state) {
509 if (shouldSkipWithError(state, mVibrator->setAmplitude(amplitude))) {
510 return;
511 }
512 }
513 });
514
515 BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
516 if (!hasCapabilities(Aidl::IVibrator::CAP_EXTERNAL_CONTROL)) {
517 state.SkipWithMessage("external control unavailable");
518 return;
519 }
520
521 for (auto _ : state) {
522 // Test
523 if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
524 return;
525 }
526
527 // Cleanup
528 state.PauseTiming();
529 if (shouldSkipWithError(state, mVibrator->setExternalControl(false))) {
530 return;
531 }
532 state.ResumeTiming();
533 }
534 });
535
536 BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
537 auto externalControl = static_cast<int32_t>(Aidl::IVibrator::CAP_EXTERNAL_CONTROL);
538 auto externalAmplitudeControl =
539 static_cast<int32_t>(Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL);
540 if (!hasCapabilities(externalControl | externalAmplitudeControl)) {
541 state.SkipWithMessage("external amplitude control unavailable");
542 return;
543 }
544
545 if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
546 return;
547 }
548
549 float amplitude = 1.0f;
550 for (auto _ : state) {
551 if (shouldSkipWithError(state, mVibrator->setAmplitude(amplitude))) {
552 return;
553 }
554 }
555 });
556
557 BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedEffects, {
558 std::vector<Aidl::Effect> supportedEffects;
559
560 for (auto _ : state) {
561 if (shouldSkipWithError(state, mVibrator->getSupportedEffects(&supportedEffects))) {
562 return;
563 }
564 }
565 });
566
567 BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedAlwaysOnEffects, {
568 if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
569 state.SkipWithMessage("always on control unavailable");
570 return;
571 }
572
573 std::vector<Aidl::Effect> supportedEffects;
574
575 for (auto _ : state) {
576 if (shouldSkipWithError(state, mVibrator->getSupportedAlwaysOnEffects(&supportedEffects))) {
577 return;
578 }
579 }
580 });
581
582 BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
583 std::vector<Aidl::CompositePrimitive> supportedPrimitives;
584
585 for (auto _ : state) {
586 if (shouldSkipWithError(state, mVibrator->getSupportedPrimitives(&supportedPrimitives))) {
587 return;
588 }
589 }
590 });
591
592 class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {
593 public:
DefaultArgs(Benchmark * b)594 static void DefaultArgs(Benchmark* b) {
595 b->ArgNames({"Effect", "Strength"});
596 for (const auto& effect : enum_range<Aidl::Effect>()) {
597 for (const auto& strength : enum_range<Aidl::EffectStrength>()) {
598 b->Args({static_cast<long>(effect), static_cast<long>(strength)});
599 }
600 }
601 }
602
603 protected:
getEffect(const State & state) const604 auto getEffect(const State& state) const {
605 return static_cast<Aidl::Effect>(this->getOtherArg(state, 0));
606 }
607
getStrength(const State & state) const608 auto getStrength(const State& state) const {
609 return static_cast<Aidl::EffectStrength>(this->getOtherArg(state, 1));
610 }
611
isEffectSupported(const Aidl::Effect & effect)612 bool isEffectSupported(const Aidl::Effect& effect) {
613 std::vector<Aidl::Effect> supported;
614 mVibrator->getSupportedEffects(&supported);
615 return std::find(supported.begin(), supported.end(), effect) != supported.end();
616 }
617
isAlwaysOnEffectSupported(const Aidl::Effect & effect)618 bool isAlwaysOnEffectSupported(const Aidl::Effect& effect) {
619 std::vector<Aidl::Effect> supported;
620 mVibrator->getSupportedAlwaysOnEffects(&supported);
621 return std::find(supported.begin(), supported.end(), effect) != supported.end();
622 }
623 };
624
625 class SlowVibratorEffectsBench_Aidl : public VibratorEffectsBench_Aidl {
626 public:
DefaultConfig(Benchmark * b)627 static void DefaultConfig(Benchmark* b) {
628 VibratorEffectsBench_Aidl::DefaultConfig(b);
629 SlowBenchConfig(b);
630 }
631 };
632
633 BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
634 if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
635 state.SkipWithMessage("always on control unavailable");
636 return;
637 }
638
639 int32_t id = 1;
640 auto effect = getEffect(state);
641 auto strength = getStrength(state);
642
643 if (!isAlwaysOnEffectSupported(effect)) {
644 state.SkipWithMessage("always on effect unsupported");
645 return;
646 }
647
648 for (auto _ : state) {
649 // Test
650 if (shouldSkipWithError(state, mVibrator->alwaysOnEnable(id, effect, strength))) {
651 return;
652 }
653
654 // Cleanup
655 state.PauseTiming();
656 if (shouldSkipWithError(state, mVibrator->alwaysOnDisable(id))) {
657 return;
658 }
659 state.ResumeTiming();
660 }
661 });
662
663 BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
664 if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
665 state.SkipWithMessage("always on control unavailable");
666 return;
667 }
668
669 int32_t id = 1;
670 auto effect = getEffect(state);
671 auto strength = getStrength(state);
672
673 if (!isAlwaysOnEffectSupported(effect)) {
674 state.SkipWithMessage("always on effect unsupported");
675 return;
676 }
677
678 for (auto _ : state) {
679 // Setup
680 state.PauseTiming();
681 if (shouldSkipWithError(state, mVibrator->alwaysOnEnable(id, effect, strength))) {
682 return;
683 }
684 state.ResumeTiming();
685
686 // Test
687 if (shouldSkipWithError(state, mVibrator->alwaysOnDisable(id))) {
688 return;
689 }
690 }
691 });
692
693 BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, {
694 auto effect = getEffect(state);
695 auto strength = getStrength(state);
696
697 if (!isEffectSupported(effect)) {
698 state.SkipWithMessage("effect unsupported");
699 return;
700 }
701
702 int32_t lengthMs = 0;
703
704 for (auto _ : state) {
705 auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK)
706 ? ndk::SharedRefBase::make<HalCallback>()
707 : nullptr;
708 // Grab the future before callback promise is destroyed by the HAL.
709 auto cbFuture = cb ? cb->getFuture() : std::future<void>();
710
711 // Test
712 if (shouldSkipWithError(state, mVibrator->perform(effect, strength, cb, &lengthMs))) {
713 return;
714 }
715
716 // Cleanup
717 state.PauseTiming();
718 if (shouldSkipWithError(state, mVibrator->off())) {
719 return;
720 }
721 waitForComplete(cbFuture);
722 state.ResumeTiming();
723 }
724 });
725
726 class VibratorPrimitivesBench_Aidl : public VibratorBench_Aidl {
727 public:
DefaultArgs(Benchmark * b)728 static void DefaultArgs(Benchmark* b) {
729 b->ArgNames({"Primitive"});
730 for (const auto& primitive : enum_range<Aidl::CompositePrimitive>()) {
731 b->Args({static_cast<long>(primitive)});
732 }
733 }
734
735 protected:
getPrimitive(const State & state) const736 auto getPrimitive(const State& state) const {
737 return static_cast<Aidl::CompositePrimitive>(this->getOtherArg(state, 0));
738 }
739
isPrimitiveSupported(const Aidl::CompositePrimitive & primitive)740 bool isPrimitiveSupported(const Aidl::CompositePrimitive& primitive) {
741 std::vector<Aidl::CompositePrimitive> supported;
742 mVibrator->getSupportedPrimitives(&supported);
743 return std::find(supported.begin(), supported.end(), primitive) != supported.end();
744 }
745 };
746
747 class SlowVibratorPrimitivesBench_Aidl : public VibratorPrimitivesBench_Aidl {
748 public:
DefaultConfig(Benchmark * b)749 static void DefaultConfig(Benchmark* b) {
750 VibratorPrimitivesBench_Aidl::DefaultConfig(b);
751 SlowBenchConfig(b);
752 }
753 };
754
755 BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionDelayMax, {
756 int32_t ms = 0;
757
758 for (auto _ : state) {
759 if (shouldSkipWithError(state, mVibrator->getCompositionDelayMax(&ms))) {
760 return;
761 }
762 }
763 });
764
765 BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
766 int32_t size = 0;
767
768 for (auto _ : state) {
769 if (shouldSkipWithError(state, mVibrator->getCompositionSizeMax(&size))) {
770 return;
771 }
772 }
773 });
774
775 BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
776 if (!hasCapabilities(Aidl::IVibrator::CAP_COMPOSE_EFFECTS)) {
777 state.SkipWithMessage("compose effects unavailable");
778 return;
779 }
780
781 auto primitive = getPrimitive(state);
782 int32_t ms = 0;
783
784 if (!isPrimitiveSupported(primitive)) {
785 state.SkipWithMessage("primitive unsupported");
786 return;
787 }
788
789 for (auto _ : state) {
790 if (shouldSkipWithError(state, mVibrator->getPrimitiveDuration(primitive, &ms))) {
791 return;
792 }
793 }
794 });
795
796 BENCHMARK_WRAPPER(SlowVibratorPrimitivesBench_Aidl, compose, {
797 if (!hasCapabilities(Aidl::IVibrator::CAP_COMPOSE_EFFECTS)) {
798 state.SkipWithMessage("compose effects unavailable");
799 return;
800 }
801
802 Aidl::CompositeEffect effect;
803 effect.primitive = getPrimitive(state);
804 effect.scale = 1.0f;
805 effect.delayMs = 0;
806
807 if (effect.primitive == Aidl::CompositePrimitive::NOOP) {
808 state.SkipWithMessage("skipping primitive NOOP");
809 return;
810 }
811 if (!isPrimitiveSupported(effect.primitive)) {
812 state.SkipWithMessage("primitive unsupported");
813 return;
814 }
815
816 std::vector<Aidl::CompositeEffect> effects;
817 effects.push_back(effect);
818
819 for (auto _ : state) {
820 auto cb = ndk::SharedRefBase::make<HalCallback>();
821 // Grab the future before callback promise is moved and destroyed by the HAL.
822 auto cbFuture = cb->getFuture();
823
824 // Test
825 if (shouldSkipWithError(state, mVibrator->compose(effects, cb))) {
826 return;
827 }
828
829 // Cleanup
830 state.PauseTiming();
831 if (shouldSkipWithError(state, mVibrator->off())) {
832 return;
833 }
834 waitForComplete(cbFuture);
835 state.ResumeTiming();
836 }
837 });
838
839 BENCHMARK_MAIN();
840