1 /* * Copyright (C) 2019 The Android Open Source Project *
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  *      http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 #include "benchmark/benchmark.h"
16 
17 #include <android-base/file.h>
18 #include <android-base/properties.h>
19 #include <cutils/fs.h>
20 
21 #include "Hardware.h"
22 #include "Vibrator.h"
23 
24 namespace aidl {
25 namespace android {
26 namespace hardware {
27 namespace vibrator {
28 
29 using ::android::base::SetProperty;
30 
31 class VibratorBench : public benchmark::Fixture {
32   private:
33     static constexpr const char *FILE_NAMES[]{
34             "device/autocal",
35             "device/ol_lra_period",
36             "activate",
37             "duration",
38             "state",
39             "device/rtp_input",
40             "device/mode",
41             "device/set_sequencer",
42             "device/scale",
43             "device/ctrl_loop",
44             "device/lp_trigger_effect",
45             "device/lp_trigger_scale",
46             "device/lra_wave_shape",
47             "device/od_clamp",
48     };
49     static constexpr char PROPERTY_PREFIX[] = "test.vibrator.hal.";
50 
51   public:
SetUp(::benchmark::State & state)52     void SetUp(::benchmark::State &state) override {
53         auto prefix = std::filesystem::path(mFilesDir.path) / "";
54 
55         setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
56 
57         for (auto n : FILE_NAMES) {
58             const auto name = std::filesystem::path(n);
59             const auto path = std::filesystem::path(mFilesDir.path) / name;
60 
61             fs_mkdirs(path.c_str(), S_IRWXU);
62             symlink("/dev/null", path.c_str());
63         }
64 
65         setenv("PROPERTY_PREFIX", PROPERTY_PREFIX, true);
66 
67         SetProperty(std::string() + PROPERTY_PREFIX + "config.dynamic", getDynamicConfig(state));
68 
69         mVibrator = ndk::SharedRefBase::make<Vibrator>(HwApi::Create(), std::make_unique<HwCal>());
70     }
71 
DefaultConfig(benchmark::internal::Benchmark * b)72     static void DefaultConfig(benchmark::internal::Benchmark *b) {
73         b->Unit(benchmark::kMicrosecond);
74     }
75 
DefaultArgs(benchmark::internal::Benchmark * b)76     static void DefaultArgs(benchmark::internal::Benchmark *b) {
77         b->ArgNames({"DynamicConfig"});
78         b->Args({false});
79         b->Args({true});
80     }
81 
82   protected:
getDynamicConfig(const::benchmark::State & state) const83     std::string getDynamicConfig(const ::benchmark::State &state) const {
84         return std::to_string(state.range(0));
85     }
86 
getOtherArg(const::benchmark::State & state,std::size_t index) const87     auto getOtherArg(const ::benchmark::State &state, std::size_t index) const {
88         return state.range(index + 1);
89     }
90 
91   protected:
92     TemporaryDir mFilesDir;
93     std::shared_ptr<IVibrator> mVibrator;
94 };
95 
96 #define BENCHMARK_WRAPPER(fixt, test, code)                           \
97     BENCHMARK_DEFINE_F(fixt, test)                                    \
98     /* NOLINTNEXTLINE */                                              \
99     (benchmark::State & state){code} BENCHMARK_REGISTER_F(fixt, test) \
100             ->Apply(fixt::DefaultConfig)                              \
101             ->Apply(fixt::DefaultArgs)
102 
103 BENCHMARK_WRAPPER(VibratorBench, on, {
104     uint32_t duration = std::rand() ?: 1;
105 
106     for (auto _ : state) {
107         mVibrator->on(duration, nullptr);
108     }
109 });
110 
111 BENCHMARK_WRAPPER(VibratorBench, off, {
112     for (auto _ : state) {
113         mVibrator->off();
114     }
115 });
116 
117 BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
118     uint8_t amplitude = std::rand() ?: 1;
119 
120     for (auto _ : state) {
121         mVibrator->setAmplitude(amplitude);
122     }
123 });
124 
125 BENCHMARK_WRAPPER(VibratorBench, setExternalControl_enable, {
126     for (auto _ : state) {
127         mVibrator->setExternalControl(true);
128     }
129 });
130 
131 BENCHMARK_WRAPPER(VibratorBench, setExternalControl_disable, {
132     for (auto _ : state) {
133         mVibrator->setExternalControl(false);
134     }
135 });
136 
137 BENCHMARK_WRAPPER(VibratorBench, getCapabilities, {
138     int32_t capabilities;
139 
140     for (auto _ : state) {
141         mVibrator->getCapabilities(&capabilities);
142     }
143 });
144 
145 class VibratorEffectsBench : public VibratorBench {
146   public:
DefaultArgs(benchmark::internal::Benchmark * b)147     static void DefaultArgs(benchmark::internal::Benchmark *b) {
148         b->ArgNames({"DynamicConfig", "Effect", "Strength"});
149         for (const auto &dynamic : {false, true}) {
150             for (const auto &effect : ndk::enum_range<Effect>()) {
151                 for (const auto &strength : ndk::enum_range<EffectStrength>()) {
152                     b->Args({dynamic, static_cast<long>(effect), static_cast<long>(strength)});
153                 }
154             }
155         }
156     }
157 
158   protected:
getEffect(const::benchmark::State & state) const159     auto getEffect(const ::benchmark::State &state) const {
160         return static_cast<Effect>(getOtherArg(state, 0));
161     }
162 
getStrength(const::benchmark::State & state) const163     auto getStrength(const ::benchmark::State &state) const {
164         return static_cast<EffectStrength>(getOtherArg(state, 1));
165     }
166 };
167 
168 BENCHMARK_WRAPPER(VibratorEffectsBench, perform, {
169     Effect effect = getEffect(state);
170     EffectStrength strength = getStrength(state);
171     int32_t lengthMs;
172 
173     ndk::ScopedAStatus status = mVibrator->perform(effect, strength, nullptr, &lengthMs);
174 
175     if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
176         return;
177     }
178 
179     for (auto _ : state) {
180         mVibrator->perform(effect, strength, nullptr, &lengthMs);
181     }
182 });
183 
184 }  // namespace vibrator
185 }  // namespace hardware
186 }  // namespace android
187 }  // namespace aidl
188 
189 BENCHMARK_MAIN();
190