1 /* 2 * Copyright (C) 2020 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 #define LOG_TAG "PowerHalControllerBenchmarks" 18 19 #include <benchmark/benchmark.h> 20 #include <vibratorservice/VibratorHalController.h> 21 22 using ::android::enum_range; 23 using ::android::hardware::vibrator::CompositeEffect; 24 using ::android::hardware::vibrator::CompositePrimitive; 25 using ::android::hardware::vibrator::Effect; 26 using ::android::hardware::vibrator::EffectStrength; 27 using ::benchmark::Counter; 28 using ::benchmark::Fixture; 29 using ::benchmark::kMicrosecond; 30 using ::benchmark::State; 31 using ::benchmark::internal::Benchmark; 32 33 using namespace android; 34 using namespace std::chrono_literals; 35 36 class VibratorBench : public Fixture { 37 public: SetUp(State &)38 void SetUp(State& /*state*/) override { mController.init(); } 39 TearDown(State & state)40 void TearDown(State& state) override { turnVibratorOff(state); } 41 DefaultConfig(Benchmark * b)42 static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); } 43 DefaultArgs(Benchmark *)44 static void DefaultArgs(Benchmark* /*b*/) { 45 // none 46 } 47 48 protected: 49 vibrator::HalController mController; 50 getOtherArg(const State & state,std::size_t index) const51 auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); } 52 hasCapabilities(vibrator::Capabilities && query,State & state)53 bool hasCapabilities(vibrator::Capabilities&& query, State& state) { 54 auto result = mController.getInfo().capabilities; 55 if (result.isFailed()) { 56 state.SkipWithError(result.errorMessage()); 57 return false; 58 } 59 if (!result.isOk()) { 60 return false; 61 } 62 return (result.value() & query) == query; 63 } 64 turnVibratorOff(State & state)65 void turnVibratorOff(State& state) { 66 checkHalResult(halCall<void>(mController, [](auto hal) { return hal->off(); }), state); 67 } 68 69 template <class R> checkHalResult(const vibrator::HalResult<R> & result,State & state)70 bool checkHalResult(const vibrator::HalResult<R>& result, State& state) { 71 if (result.isFailed()) { 72 state.SkipWithError(result.errorMessage()); 73 return false; 74 } 75 return true; 76 } 77 78 template <class R> halCall(vibrator::HalController & controller,const vibrator::HalFunction<vibrator::HalResult<R>> & halFn)79 vibrator::HalResult<R> halCall(vibrator::HalController& controller, 80 const vibrator::HalFunction<vibrator::HalResult<R>>& halFn) { 81 return controller.doWithRetry<R>(halFn, "benchmark"); 82 } 83 }; 84 85 #define BENCHMARK_WRAPPER(fixt, test, code) \ 86 BENCHMARK_DEFINE_F(fixt, test) \ 87 /* NOLINTNEXTLINE */ \ 88 (State& state){code} BENCHMARK_REGISTER_F(fixt, test) \ 89 ->Apply(fixt::DefaultConfig) \ 90 ->Apply(fixt::DefaultArgs) 91 92 BENCHMARK_WRAPPER(VibratorBench, init, { 93 for (auto _ : state) { 94 state.PauseTiming(); 95 vibrator::HalController controller; 96 state.ResumeTiming(); 97 controller.init(); 98 } 99 }); 100 101 BENCHMARK_WRAPPER(VibratorBench, initCached, { 102 for (auto _ : state) { 103 mController.init(); 104 } 105 }); 106 107 BENCHMARK_WRAPPER(VibratorBench, ping, { 108 for (auto _ : state) { 109 state.ResumeTiming(); __anon866670c60202(auto hal) 110 auto ret = halCall<void>(mController, [](auto hal) { return hal->ping(); }); 111 state.PauseTiming(); 112 checkHalResult(ret, state); 113 } 114 }); 115 116 BENCHMARK_WRAPPER(VibratorBench, tryReconnect, { 117 for (auto _ : state) { 118 mController.tryReconnect(); 119 } 120 }); 121 122 BENCHMARK_WRAPPER(VibratorBench, on, { 123 auto duration = 60s; __anon866670c60302() 124 auto callback = []() {}; 125 126 for (auto _ : state) { 127 state.ResumeTiming(); 128 auto ret = __anon866670c60402(auto hal) 129 halCall<void>(mController, [&](auto hal) { return hal->on(duration, callback); }); 130 state.PauseTiming(); 131 if (checkHalResult(ret, state)) { 132 turnVibratorOff(state); 133 } 134 } 135 }); 136 137 BENCHMARK_WRAPPER(VibratorBench, off, { 138 auto duration = 60s; __anon866670c60502() 139 auto callback = []() {}; 140 141 for (auto _ : state) { 142 state.PauseTiming(); 143 auto ret = __anon866670c60602(auto hal) 144 halCall<void>(mController, [&](auto hal) { return hal->on(duration, callback); }); 145 if (!checkHalResult(ret, state)) { 146 continue; 147 } 148 state.ResumeTiming(); 149 turnVibratorOff(state); 150 } 151 }); 152 153 BENCHMARK_WRAPPER(VibratorBench, setAmplitude, { 154 if (!hasCapabilities(vibrator::Capabilities::AMPLITUDE_CONTROL, state)) { 155 return; 156 } 157 158 auto duration = 60s; __anon866670c60702() 159 auto callback = []() {}; 160 auto amplitude = 1.0f; 161 162 for (auto _ : state) { 163 state.PauseTiming(); 164 vibrator::HalController controller; 165 controller.init(); 166 auto result = __anon866670c60802(auto hal) 167 halCall<void>(controller, [&](auto hal) { return hal->on(duration, callback); }); 168 if (!checkHalResult(result, state)) { 169 continue; 170 } 171 state.ResumeTiming(); 172 auto ret = __anon866670c60902(auto hal) 173 halCall<void>(controller, [&](auto hal) { return hal->setAmplitude(amplitude); }); 174 state.PauseTiming(); 175 if (checkHalResult(ret, state)) { 176 turnVibratorOff(state); 177 } 178 } 179 }); 180 181 BENCHMARK_WRAPPER(VibratorBench, setAmplitudeCached, { 182 if (!hasCapabilities(vibrator::Capabilities::AMPLITUDE_CONTROL, state)) { 183 return; 184 } 185 186 auto duration = 6000s; __anon866670c60a02() 187 auto callback = []() {}; 188 auto amplitude = 1.0f; 189 190 auto onResult = __anon866670c60b02(auto hal) 191 halCall<void>(mController, [&](auto hal) { return hal->on(duration, callback); }); 192 checkHalResult(onResult, state); 193 194 for (auto _ : state) { 195 auto ret = __anon866670c60c02(auto hal) 196 halCall<void>(mController, [&](auto hal) { return hal->setAmplitude(amplitude); }); 197 checkHalResult(ret, state); 198 } 199 }); 200 201 BENCHMARK_WRAPPER(VibratorBench, setExternalControl, { 202 if (!hasCapabilities(vibrator::Capabilities::EXTERNAL_CONTROL, state)) { 203 return; 204 } 205 206 for (auto _ : state) { 207 state.PauseTiming(); 208 vibrator::HalController controller; 209 controller.init(); 210 state.ResumeTiming(); 211 auto ret = __anon866670c60d02(auto hal) 212 halCall<void>(controller, [](auto hal) { return hal->setExternalControl(true); }); 213 state.PauseTiming(); 214 if (checkHalResult(ret, state)) { 215 auto result = halCall<void>(controller, __anon866670c60e02(auto hal) 216 [](auto hal) { return hal->setExternalControl(false); }); 217 checkHalResult(result, state); 218 } 219 } 220 }); 221 222 BENCHMARK_WRAPPER(VibratorBench, setExternalControlCached, { 223 if (!hasCapabilities(vibrator::Capabilities::EXTERNAL_CONTROL, state)) { 224 return; 225 } 226 227 for (auto _ : state) { 228 state.ResumeTiming(); 229 auto result = __anon866670c60f02(auto hal) 230 halCall<void>(mController, [](auto hal) { return hal->setExternalControl(true); }); 231 state.PauseTiming(); 232 if (checkHalResult(result, state)) { 233 auto ret = halCall<void>(mController, __anon866670c61002(auto hal) 234 [](auto hal) { return hal->setExternalControl(false); }); 235 checkHalResult(ret, state); 236 } 237 } 238 }); 239 240 BENCHMARK_WRAPPER(VibratorBench, setExternalAmplitudeCached, { 241 if (!hasCapabilities(vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL, state)) { 242 return; 243 } 244 245 auto amplitude = 1.0f; 246 247 auto onResult = __anon866670c61102(auto hal) 248 halCall<void>(mController, [](auto hal) { return hal->setExternalControl(true); }); 249 checkHalResult(onResult, state); 250 251 for (auto _ : state) { 252 auto ret = __anon866670c61202(auto hal) 253 halCall<void>(mController, [&](auto hal) { return hal->setAmplitude(amplitude); }); 254 checkHalResult(ret, state); 255 } 256 257 auto offResult = __anon866670c61302(auto hal) 258 halCall<void>(mController, [](auto hal) { return hal->setExternalControl(false); }); 259 checkHalResult(offResult, state); 260 }); 261 262 BENCHMARK_WRAPPER(VibratorBench, getInfo, { 263 for (auto _ : state) { 264 state.PauseTiming(); 265 vibrator::HalController controller; 266 controller.init(); 267 state.ResumeTiming(); 268 auto result = controller.getInfo(); 269 checkHalResult(result.capabilities, state); 270 checkHalResult(result.supportedEffects, state); 271 checkHalResult(result.supportedPrimitives, state); 272 checkHalResult(result.primitiveDurations, state); 273 checkHalResult(result.resonantFrequency, state); 274 checkHalResult(result.qFactor, state); 275 } 276 }); 277 278 BENCHMARK_WRAPPER(VibratorBench, getInfoCached, { 279 // First call to cache values. 280 mController.getInfo(); 281 282 for (auto _ : state) { 283 auto result = mController.getInfo(); 284 checkHalResult(result.capabilities, state); 285 checkHalResult(result.supportedEffects, state); 286 checkHalResult(result.supportedPrimitives, state); 287 checkHalResult(result.primitiveDurations, state); 288 checkHalResult(result.resonantFrequency, state); 289 checkHalResult(result.qFactor, state); 290 } 291 }); 292 293 class VibratorEffectsBench : public VibratorBench { 294 public: DefaultArgs(Benchmark * b)295 static void DefaultArgs(Benchmark* b) { 296 vibrator::HalController controller; 297 auto effectsResult = controller.getInfo().supportedEffects; 298 if (!effectsResult.isOk()) { 299 return; 300 } 301 302 std::vector<Effect> supported = effectsResult.value(); 303 b->ArgNames({"Effect", "Strength"}); 304 305 if (supported.empty()) { 306 b->Args({static_cast<long>(-1), static_cast<long>(-1)}); 307 return; 308 } 309 310 for (const auto& effect : enum_range<Effect>()) { 311 if (std::find(supported.begin(), supported.end(), effect) == supported.end()) { 312 continue; 313 } 314 for (const auto& strength : enum_range<EffectStrength>()) { 315 b->Args({static_cast<long>(effect), static_cast<long>(strength)}); 316 } 317 } 318 } 319 320 protected: hasArgs(const State & state) const321 bool hasArgs(const State& state) const { return this->getOtherArg(state, 0) >= 0; } 322 getEffect(const State & state) const323 auto getEffect(const State& state) const { 324 return static_cast<Effect>(this->getOtherArg(state, 0)); 325 } 326 getStrength(const State & state) const327 auto getStrength(const State& state) const { 328 return static_cast<EffectStrength>(this->getOtherArg(state, 1)); 329 } 330 }; 331 332 BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnEnable, { 333 if (!hasCapabilities(vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) { 334 return; 335 } 336 if (!hasArgs(state)) { 337 return; 338 } 339 340 int32_t id = 1; 341 auto effect = getEffect(state); 342 auto strength = getStrength(state); 343 344 for (auto _ : state) { 345 state.ResumeTiming(); __anon866670c61402(auto hal) 346 auto ret = halCall<void>(mController, [&](auto hal) { 347 return hal->alwaysOnEnable(id, effect, strength); 348 }); 349 state.PauseTiming(); 350 if (checkHalResult(ret, state)) { 351 auto disableResult = __anon866670c61502(auto hal) 352 halCall<void>(mController, [&](auto hal) { return hal->alwaysOnDisable(id); }); 353 checkHalResult(disableResult, state); 354 } 355 } 356 }); 357 358 BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnDisable, { 359 if (!hasCapabilities(vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) { 360 return; 361 } 362 if (!hasArgs(state)) { 363 return; 364 } 365 366 int32_t id = 1; 367 auto effect = getEffect(state); 368 auto strength = getStrength(state); 369 370 for (auto _ : state) { 371 state.PauseTiming(); __anon866670c61602(auto hal) 372 auto enableResult = halCall<void>(mController, [&](auto hal) { 373 return hal->alwaysOnEnable(id, effect, strength); 374 }); 375 if (!checkHalResult(enableResult, state)) { 376 continue; 377 } 378 state.ResumeTiming(); 379 auto disableResult = __anon866670c61702(auto hal) 380 halCall<void>(mController, [&](auto hal) { return hal->alwaysOnDisable(id); }); 381 checkHalResult(disableResult, state); 382 } 383 }); 384 385 BENCHMARK_WRAPPER(VibratorEffectsBench, performEffect, { 386 if (!hasArgs(state)) { 387 return; 388 } 389 390 auto effect = getEffect(state); 391 auto strength = getStrength(state); __anon866670c61802() 392 auto callback = []() {}; 393 394 for (auto _ : state) { 395 state.ResumeTiming(); __anon866670c61902(auto hal) 396 auto ret = halCall<std::chrono::milliseconds>(mController, [&](auto hal) { 397 return hal->performEffect(effect, strength, callback); 398 }); 399 state.PauseTiming(); 400 if (checkHalResult(ret, state)) { 401 turnVibratorOff(state); 402 } 403 } 404 }); 405 406 class VibratorPrimitivesBench : public VibratorBench { 407 public: DefaultArgs(Benchmark * b)408 static void DefaultArgs(Benchmark* b) { 409 vibrator::HalController controller; 410 auto primitivesResult = controller.getInfo().supportedPrimitives; 411 if (!primitivesResult.isOk()) { 412 return; 413 } 414 415 std::vector<CompositePrimitive> supported = primitivesResult.value(); 416 b->ArgNames({"Primitive"}); 417 418 if (supported.empty()) { 419 b->Args({static_cast<long>(-1)}); 420 return; 421 } 422 423 for (const auto& primitive : enum_range<CompositePrimitive>()) { 424 if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) { 425 continue; 426 } 427 if (primitive == CompositePrimitive::NOOP) { 428 continue; 429 } 430 b->Args({static_cast<long>(primitive)}); 431 } 432 } 433 434 protected: hasArgs(const State & state) const435 bool hasArgs(const State& state) const { return this->getOtherArg(state, 0) >= 0; } 436 getPrimitive(const State & state) const437 auto getPrimitive(const State& state) const { 438 return static_cast<CompositePrimitive>(this->getOtherArg(state, 0)); 439 } 440 }; 441 442 BENCHMARK_WRAPPER(VibratorPrimitivesBench, performComposedEffect, { 443 if (!hasCapabilities(vibrator::Capabilities::COMPOSE_EFFECTS, state)) { 444 return; 445 } 446 if (!hasArgs(state)) { 447 return; 448 } 449 450 CompositeEffect effect; 451 effect.primitive = getPrimitive(state); 452 effect.scale = 1.0f; 453 effect.delayMs = static_cast<int32_t>(0); 454 455 std::vector<CompositeEffect> effects; 456 effects.push_back(effect); __anon866670c61a02() 457 auto callback = []() {}; 458 459 for (auto _ : state) { 460 state.ResumeTiming(); __anon866670c61b02(auto hal) 461 auto ret = halCall<std::chrono::milliseconds>(mController, [&](auto hal) { 462 return hal->performComposedEffect(effects, callback); 463 }); 464 state.PauseTiming(); 465 if (checkHalResult(ret, state)) { 466 turnVibratorOff(state); 467 } 468 } 469 }); 470 471 BENCHMARK_MAIN();