xref: /aosp_15_r20/hardware/interfaces/vibrator/bench/benchmark.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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