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