1 /*
2 * Copyright 2018 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 <base/bind.h>
18 #include <base/run_loop.h>
19 #include <base/threading/thread.h>
20 #include <benchmark/benchmark.h>
21 #include <future>
22
23 #include "common/message_loop_thread.h"
24 #include "common/once_timer.h"
25 #include "common/repeating_timer.h"
26 #include "common/time_util.h"
27 #include "osi/include/alarm.h"
28
29 using ::benchmark::State;
30 using bluetooth::common::MessageLoopThread;
31 using bluetooth::common::OnceTimer;
32 using bluetooth::common::RepeatingTimer;
33 using bluetooth::common::time_get_os_boottime_us;
34
get_main_thread()35 bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
36
37 namespace {
38 std::unordered_map<int, int> g_map;
39 std::shared_ptr<std::promise<void>> g_promise;
40 uint64_t g_start_time;
41 int g_scheduled_tasks;
42 int g_task_length;
43 int g_task_interval;
44 int g_task_counter;
45
TimerFire(void *)46 void TimerFire(void*) { g_promise->set_value(); }
47
AlarmSleepAndCountDelayedTime(void *)48 void AlarmSleepAndCountDelayedTime(void*) {
49 auto end_time_us = time_get_os_boottime_us();
50 auto time_after_start_ms = (end_time_us - g_start_time) / 1000;
51 g_task_counter++;
52 g_map[time_after_start_ms - g_task_counter * g_task_interval]++;
53 std::this_thread::sleep_for(std::chrono::milliseconds(g_task_length));
54 if (g_task_counter >= g_scheduled_tasks) {
55 g_promise->set_value();
56 }
57 }
58
59 } // namespace
60
61 class BM_OsiAlarmTimer : public ::benchmark::Fixture {
62 protected:
SetUp(State & st)63 void SetUp(State& st) override {
64 ::benchmark::Fixture::SetUp(st);
65 alarm_ = alarm_new("osi_alarm_timer_test");
66 g_promise = std::make_shared<std::promise<void>>();
67 }
68
TearDown(State & st)69 void TearDown(State& st) override {
70 g_promise = nullptr;
71 alarm_free(alarm_);
72 ::benchmark::Fixture::TearDown(st);
73 }
74
75 alarm_t* alarm_ = nullptr;
76 };
77
BENCHMARK_DEFINE_F(BM_OsiAlarmTimer,timer_performance_ms)78 BENCHMARK_DEFINE_F(BM_OsiAlarmTimer, timer_performance_ms)(State& state) {
79 auto milliseconds = static_cast<int>(state.range(0));
80 for (auto _ : state) {
81 auto start_time_point = time_get_os_boottime_us();
82 alarm_set(alarm_, milliseconds, &TimerFire, nullptr);
83 g_promise->get_future().get();
84 auto end_time_point = time_get_os_boottime_us();
85 auto duration = end_time_point - start_time_point;
86 state.SetIterationTime(duration * 1e-6);
87 }
88 };
89
90 BENCHMARK_REGISTER_F(BM_OsiAlarmTimer, timer_performance_ms)
91 ->Arg(1)
92 ->Arg(5)
93 ->Arg(10)
94 ->Arg(20)
95 ->Arg(100)
96 ->Arg(1000)
97 ->Arg(2000)
98 ->Iterations(1)
99 ->UseManualTime();
100
101 class BM_AlarmTaskTimer : public ::benchmark::Fixture {
102 protected:
SetUp(State & st)103 void SetUp(State& st) override {
104 ::benchmark::Fixture::SetUp(st);
105 message_loop_thread_ = new MessageLoopThread("timer_benchmark");
106 message_loop_thread_->StartUp();
107 message_loop_thread_->EnableRealTimeScheduling();
108 once_timer_ = new OnceTimer();
109 repeating_timer_ = new RepeatingTimer();
110 g_promise = std::make_shared<std::promise<void>>();
111 }
112
TearDown(State & st)113 void TearDown(State& st) override {
114 g_promise = nullptr;
115 delete once_timer_;
116 once_timer_ = nullptr;
117 delete repeating_timer_;
118 repeating_timer_ = nullptr;
119 message_loop_thread_->ShutDown();
120 delete message_loop_thread_;
121 message_loop_thread_ = nullptr;
122 ::benchmark::Fixture::TearDown(st);
123 }
124
125 MessageLoopThread* message_loop_thread_;
126 OnceTimer* once_timer_;
127 RepeatingTimer* repeating_timer_;
128 };
129
BENCHMARK_DEFINE_F(BM_AlarmTaskTimer,timer_performance_ms)130 BENCHMARK_DEFINE_F(BM_AlarmTaskTimer, timer_performance_ms)(State& state) {
131 auto milliseconds = static_cast<int>(state.range(0));
132 for (auto _ : state) {
133 auto start_time_point = time_get_os_boottime_us();
134 once_timer_->Schedule(message_loop_thread_->GetWeakPtr(), FROM_HERE,
135 base::BindOnce(&TimerFire, nullptr),
136 #if BASE_VER < 931007
137 base::TimeDelta::FromMilliseconds(milliseconds));
138 #else
139 base::Milliseconds(milliseconds));
140 #endif
141 g_promise->get_future().get();
142 once_timer_->Cancel();
143 auto end_time_point = time_get_os_boottime_us();
144 auto duration = end_time_point - start_time_point;
145 state.SetIterationTime(duration * 1e-6);
146 }
147 };
148
149 BENCHMARK_REGISTER_F(BM_AlarmTaskTimer, timer_performance_ms)
150 ->Arg(1)
151 ->Arg(5)
152 ->Arg(10)
153 ->Arg(20)
154 ->Arg(100)
155 ->Arg(1000)
156 ->Arg(2000)
157 ->Iterations(1)
158 ->UseManualTime();
159
160 class BM_OsiPeriodicAlarmTimer : public ::benchmark::Fixture {
161 protected:
SetUp(State & st)162 void SetUp(State& st) override {
163 ::benchmark::Fixture::SetUp(st);
164 alarm_ = alarm_new_periodic("osi_alarm_timer_test");
165 g_map.clear();
166 g_promise = std::make_shared<std::promise<void>>();
167 g_scheduled_tasks = 0;
168 g_task_length = 0;
169 g_task_interval = 0;
170 g_task_counter = 0;
171 }
172
TearDown(State & st)173 void TearDown(State& st) override {
174 g_promise = nullptr;
175 alarm_free(alarm_);
176 ::benchmark::Fixture::TearDown(st);
177 }
178
179 alarm_t* alarm_ = nullptr;
180 };
181
BENCHMARK_DEFINE_F(BM_OsiPeriodicAlarmTimer,periodic_accuracy)182 BENCHMARK_DEFINE_F(BM_OsiPeriodicAlarmTimer, periodic_accuracy)(State& state) {
183 for (auto _ : state) {
184 g_scheduled_tasks = state.range(0);
185 g_task_length = state.range(1);
186 g_task_interval = state.range(2);
187 g_start_time = time_get_os_boottime_us();
188 alarm_set(alarm_, g_task_interval, &AlarmSleepAndCountDelayedTime, nullptr);
189 g_promise->get_future().get();
190 alarm_cancel(alarm_);
191 }
192 for (const auto& delay : g_map) {
193 state.counters[std::to_string(delay.first)] = delay.second;
194 }
195 };
196
197 BENCHMARK_REGISTER_F(BM_OsiPeriodicAlarmTimer, periodic_accuracy)
198 ->Args({2000, 1, 5})
199 ->Args({2000, 3, 5})
200 ->Args({2000, 1, 7})
201 ->Args({2000, 3, 7})
202 ->Args({2000, 1, 20})
203 ->Args({2000, 5, 20})
204 ->Args({2000, 10, 20})
205 ->Args({2000, 15, 20})
206 ->Iterations(1)
207 ->UseRealTime();
208
209 class BM_AlarmTaskPeriodicTimer : public ::benchmark::Fixture {
210 protected:
SetUp(State & st)211 void SetUp(State& st) override {
212 ::benchmark::Fixture::SetUp(st);
213 message_loop_thread_ = new MessageLoopThread("timer_benchmark");
214 message_loop_thread_->StartUp();
215 message_loop_thread_->EnableRealTimeScheduling();
216 once_timer_ = new OnceTimer();
217 repeating_timer_ = new RepeatingTimer();
218 g_map.clear();
219 g_promise = std::make_shared<std::promise<void>>();
220 g_scheduled_tasks = 0;
221 g_task_length = 0;
222 g_task_interval = 0;
223 g_task_counter = 0;
224 }
225
TearDown(State & st)226 void TearDown(State& st) override {
227 g_promise = nullptr;
228 delete once_timer_;
229 once_timer_ = nullptr;
230 delete repeating_timer_;
231 repeating_timer_ = nullptr;
232 message_loop_thread_->ShutDown();
233 delete message_loop_thread_;
234 message_loop_thread_ = nullptr;
235 ::benchmark::Fixture::TearDown(st);
236 }
237
238 MessageLoopThread* message_loop_thread_;
239 OnceTimer* once_timer_;
240 RepeatingTimer* repeating_timer_;
241 };
242
BENCHMARK_DEFINE_F(BM_AlarmTaskPeriodicTimer,periodic_accuracy)243 BENCHMARK_DEFINE_F(BM_AlarmTaskPeriodicTimer, periodic_accuracy)
244 (State& state) {
245 for (auto _ : state) {
246 g_scheduled_tasks = state.range(0);
247 g_task_length = state.range(1);
248 g_task_interval = state.range(2);
249 g_start_time = time_get_os_boottime_us();
250 repeating_timer_->SchedulePeriodic(
251 message_loop_thread_->GetWeakPtr(), FROM_HERE,
252 base::BindRepeating(&AlarmSleepAndCountDelayedTime, nullptr),
253 #if BASE_VER < 931007
254 base::TimeDelta::FromMilliseconds(g_task_interval));
255 #else
256 base::Milliseconds(g_task_interval));
257 #endif
258 g_promise->get_future().get();
259 repeating_timer_->Cancel();
260 }
261 for (const auto& delay : g_map) {
262 state.counters[std::to_string(delay.first)] = delay.second;
263 }
264 };
265
266 BENCHMARK_REGISTER_F(BM_AlarmTaskPeriodicTimer, periodic_accuracy)
267 ->Args({2000, 1, 5})
268 ->Args({2000, 3, 5})
269 ->Args({2000, 1, 7})
270 ->Args({2000, 3, 7})
271 ->Args({2000, 1, 20})
272 ->Args({2000, 5, 20})
273 ->Args({2000, 10, 20})
274 ->Args({2000, 15, 20})
275 ->Iterations(1)
276 ->UseRealTime();
277
main(int argc,char ** argv)278 int main(int argc, char** argv) {
279 // Disable LOG() output from libchrome
280 logging::LoggingSettings log_settings;
281 log_settings.logging_dest = logging::LoggingDestination::LOG_NONE;
282 CHECK(logging::InitLogging(log_settings)) << "Failed to set up logging";
283 ::benchmark::Initialize(&argc, argv);
284 if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
285 return 1;
286 }
287 ::benchmark::RunSpecifiedBenchmarks();
288 }
289