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