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 
21 using ::android::sp;
22 using ::android::hardware::hidl_enum_range;
23 using ::android::hardware::Return;
24 using ::android::hardware::details::hidl_enum_values;
25 using ::benchmark::Counter;
26 using ::benchmark::Fixture;
27 using ::benchmark::kMicrosecond;
28 using ::benchmark::State;
29 using ::benchmark::internal::Benchmark;
30 using ::std::chrono::duration;
31 using ::std::chrono::duration_cast;
32 using ::std::chrono::high_resolution_clock;
33 
34 namespace V1_0 = ::android::hardware::vibrator::V1_0;
35 namespace V1_1 = ::android::hardware::vibrator::V1_1;
36 namespace V1_2 = ::android::hardware::vibrator::V1_2;
37 namespace V1_3 = ::android::hardware::vibrator::V1_3;
38 
39 template <typename I>
40 class VibratorBench : public Fixture {
41   public:
SetUp(State &)42     void SetUp(State & /*state*/) override { mVibrator = I::getService(); }
43 
TearDown(State &)44     void TearDown(State & /*state*/) override {
45         if (!mVibrator) {
46             return;
47         }
48         mVibrator->off();
49     }
50 
DefaultConfig(Benchmark * b)51     static void DefaultConfig(Benchmark *b) { b->Unit(kMicrosecond); }
52 
DefaultArgs(Benchmark *)53     static void DefaultArgs(Benchmark * /*b*/) {
54         // none
55     }
56 
57   protected:
getOtherArg(const State & state,std::size_t index) const58     auto getOtherArg(const State &state, std::size_t index) const {
59         return state.range(index + 0);
60     }
61 
62   protected:
63     sp<I> mVibrator;
64 };
65 
66 enum class EmptyEnum : uint32_t;
67 template <>
68 inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
69 
70 template <typename T, typename U>
difference(const hidl_enum_range<T> & t,const hidl_enum_range<U> & u)71 std::set<T> difference(const hidl_enum_range<T> &t, const hidl_enum_range<U> &u) {
72     class Compare {
73       public:
74         bool operator()(const T &a, const U &b) { return a < static_cast<T>(b); }
75         bool operator()(const U &a, const T &b) { return static_cast<T>(a) < b; }
76     };
77     std::set<T> ret;
78 
79     std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
80                         std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
81 
82     return ret;
83 }
84 
85 template <typename I, typename E1, typename E2 = EmptyEnum>
86 class VibratorEffectsBench : public VibratorBench<I> {
87   public:
88     using Effect = E1;
89     using EffectStrength = V1_0::EffectStrength;
90     using Status = V1_0::Status;
91 
92   public:
DefaultArgs(Benchmark * b)93     static void DefaultArgs(Benchmark *b) {
94         b->ArgNames({"Effect", "Strength"});
95         for (const auto &effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
96             for (const auto &strength : hidl_enum_range<EffectStrength>()) {
97                 b->Args({static_cast<long>(effect), static_cast<long>(strength)});
98             }
99         }
100     }
101 
performBench(State * state,Return<void> (I::* performApi)(Effect,EffectStrength,typename I::perform_cb))102     void performBench(State *state, Return<void> (I::*performApi)(Effect, EffectStrength,
103                                                                   typename I::perform_cb)) {
104         auto effect = getEffect(*state);
105         auto strength = getStrength(*state);
106         bool supported = true;
107 
108         (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
109             if (status == Status::UNSUPPORTED_OPERATION) {
110                 supported = false;
111             }
112         });
113 
114         if (!supported) {
115             return;
116         }
117 
118         for (auto _ : *state) {
119             state->ResumeTiming();
120             (*this->mVibrator.*performApi)(effect, strength,
121                                            [](Status /*status*/, uint32_t /*lengthMs*/) {});
122             state->PauseTiming();
123             this->mVibrator->off();
124         }
125     }
126 
127   protected:
getEffect(const State & state) const128     auto getEffect(const State &state) const {
129         return static_cast<Effect>(this->getOtherArg(state, 0));
130     }
131 
getStrength(const State & state) const132     auto getStrength(const State &state) const {
133         return static_cast<EffectStrength>(this->getOtherArg(state, 1));
134     }
135 };
136 
137 #define BENCHMARK_WRAPPER(fixt, test, code) \
138     BENCHMARK_DEFINE_F(fixt, test)          \
139     /* NOLINTNEXTLINE */                    \
140     (State & state) {                       \
141         if (!mVibrator) {                   \
142             return;                         \
143         }                                   \
144                                             \
145         code                                \
146     }                                       \
147     BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
148 
149 using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
150 
151 BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
152     uint32_t ms = UINT32_MAX;
153 
154     for (auto _ : state) {
155         state.ResumeTiming();
156         mVibrator->on(ms);
157         state.PauseTiming();
158         mVibrator->off();
159     }
160 });
161 
162 BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
163     uint32_t ms = UINT32_MAX;
164 
165     for (auto _ : state) {
166         state.PauseTiming();
167         mVibrator->on(ms);
168         state.ResumeTiming();
169         mVibrator->off();
170     }
171 });
172 
173 BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
174     for (auto _ : state) {
175         mVibrator->supportsAmplitudeControl();
176     }
177 });
178 
179 BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
180     uint8_t amplitude = UINT8_MAX;
181 
182     if (!mVibrator->supportsAmplitudeControl()) {
183         return;
184     }
185 
186     mVibrator->on(UINT32_MAX);
187 
188     for (auto _ : state) {
189         mVibrator->setAmplitude(amplitude);
190     }
191 
192     mVibrator->off();
193 });
194 
195 using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
196 
197 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
198                   { performBench(&state, &V1_0::IVibrator::perform); });
199 
200 using VibratorEffectsBench_V1_1 =
201     VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
202 
203 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
204                   { performBench(&state, &V1_1::IVibrator::perform_1_1); });
205 
206 using VibratorEffectsBench_V1_2 =
207     VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
208 
209 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
210                   { performBench(&state, &V1_2::IVibrator::perform_1_2); });
211 
212 using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
213 
214 BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
215     for (auto _ : state) {
216         mVibrator->supportsExternalControl();
217     }
218 });
219 
220 BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
221     bool enable = true;
222 
223     if (!mVibrator->supportsExternalControl()) {
224         return;
225     }
226 
227     for (auto _ : state) {
228         state.ResumeTiming();
229         mVibrator->setExternalControl(enable);
230         state.PauseTiming();
231         mVibrator->setExternalControl(false);
232     }
233 });
234 
235 BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
236     if (!mVibrator->supportsExternalControl()) {
237         return;
238     }
239 
240     mVibrator->setExternalControl(true);
241 
242     for (auto _ : state) {
243         mVibrator->supportsAmplitudeControl();
244     }
245 
246     mVibrator->setExternalControl(false);
247 });
248 
249 BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
250     uint8_t amplitude = UINT8_MAX;
251 
252     if (!mVibrator->supportsExternalControl()) {
253         return;
254     }
255 
256     mVibrator->setExternalControl(true);
257 
258     if (!mVibrator->supportsAmplitudeControl()) {
259         return;
260     }
261 
262     for (auto _ : state) {
263         mVibrator->setAmplitude(amplitude);
264     }
265 
266     mVibrator->setExternalControl(false);
267 });
268 
269 using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
270 
271 BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
272                   { performBench(&state, &V1_3::IVibrator::perform_1_3); });
273 
274 BENCHMARK_MAIN();
275