• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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