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