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/functional/bind.h>
18 #include <base/run_loop.h>
19 #include <base/threading/thread.h>
20 #include <benchmark/benchmark.h>
21 #include <bluetooth/log.h>
22
23 #include <atomic>
24 #include <future>
25 #include <memory>
26 #include <thread>
27
28 #include "abstract_message_loop.h"
29 #include "common/message_loop_thread.h"
30 #include "osi/include/fixed_queue.h"
31 #include "osi/include/thread.h"
32
33 using ::benchmark::State;
34 using bluetooth::common::MessageLoopThread;
35
36 #define NUM_MESSAGES_TO_SEND 100000
37
38 static std::atomic<int> g_counter = 0;
39 static std::unique_ptr<std::promise<void>> g_counter_promise = nullptr;
40
pthread_callback_batch(void * context)41 void pthread_callback_batch(void* context) {
42 auto queue = static_cast<fixed_queue_t*>(context);
43 bluetooth::log::assert_that(queue != nullptr,
44 "assert failed: queue != nullptr");
45 fixed_queue_dequeue(queue);
46 g_counter++;
47 if (g_counter >= NUM_MESSAGES_TO_SEND) {
48 g_counter_promise->set_value();
49 }
50 }
51
callback_sequential(void * context)52 void callback_sequential(void* context) { g_counter_promise->set_value(); }
53
callback_sequential_queue(fixed_queue_t * queue,void * context)54 void callback_sequential_queue(fixed_queue_t* queue, void* context) {
55 bluetooth::log::assert_that(queue != nullptr,
56 "assert failed: queue != nullptr");
57 fixed_queue_dequeue(queue);
58 g_counter_promise->set_value();
59 }
60
callback_batch(fixed_queue_t * queue,void * data)61 void callback_batch(fixed_queue_t* queue, void* data) {
62 bluetooth::log::assert_that(queue != nullptr,
63 "assert failed: queue != nullptr");
64 fixed_queue_dequeue(queue);
65 g_counter++;
66 if (g_counter >= NUM_MESSAGES_TO_SEND) {
67 g_counter_promise->set_value();
68 }
69 }
70
71 class BM_ThreadPerformance : public ::benchmark::Fixture {
72 protected:
SetUp(State & st)73 void SetUp(State& st) override {
74 benchmark::Fixture::SetUp(st);
75 set_up_promise_ = std::make_unique<std::promise<void>>();
76 g_counter = 0;
77 bt_msg_queue_ = fixed_queue_new(SIZE_MAX);
78 }
TearDown(State & st)79 void TearDown(State& st) override {
80 fixed_queue_free(bt_msg_queue_, nullptr);
81 bt_msg_queue_ = nullptr;
82 set_up_promise_.reset(nullptr);
83 g_counter_promise.reset(nullptr);
84 benchmark::Fixture::TearDown(st);
85 }
86 fixed_queue_t* bt_msg_queue_ = nullptr;
87 std::unique_ptr<std::promise<void>> set_up_promise_;
88 };
89
90 class BM_MessageLoop : public BM_ThreadPerformance {
91 public:
RunThread(void * context)92 static void RunThread(void* context) {
93 auto test = static_cast<BM_MessageLoop*>(context);
94 test->RunMessageLoop();
95 }
RunPThread(void * context)96 static void* RunPThread(void* context) {
97 auto test = static_cast<BM_MessageLoop*>(context);
98 test->RunMessageLoop();
99 return nullptr;
100 }
RunMessageLoop()101 void RunMessageLoop() {
102 message_loop_ = new btbase::AbstractMessageLoop();
103 run_loop_ = new base::RunLoop();
104 message_loop_->task_runner()->PostTask(
105 FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
106 base::Unretained(set_up_promise_.get())));
107 run_loop_->Run();
108 delete message_loop_;
109 message_loop_ = nullptr;
110 delete run_loop_;
111 run_loop_ = nullptr;
112 }
113
114 protected:
115 btbase::AbstractMessageLoop* message_loop_ = nullptr;
116 base::RunLoop* run_loop_ = nullptr;
117 };
118
119 class BM_MessageLoopOsiThread : public BM_MessageLoop {
120 protected:
SetUp(State & st)121 void SetUp(State& st) override {
122 BM_MessageLoop::SetUp(st);
123 std::future<void> set_up_future = set_up_promise_->get_future();
124 thread_ = thread_new("BM_MessageLoopOnOsiThread thread");
125 thread_post(thread_, &BM_MessageLoop::RunThread, this);
126 set_up_future.wait();
127 }
128
TearDown(State & st)129 void TearDown(State& st) override {
130 message_loop_->task_runner()->PostTask(FROM_HERE,
131 run_loop_->QuitWhenIdleClosure());
132 thread_free(thread_);
133 thread_ = nullptr;
134 BM_MessageLoop::TearDown(st);
135 }
136
137 thread_t* thread_ = nullptr;
138 };
139
BENCHMARK_F(BM_MessageLoopOsiThread,batch_enque_dequeue)140 BENCHMARK_F(BM_MessageLoopOsiThread, batch_enque_dequeue)(State& state) {
141 for (auto _ : state) {
142 g_counter = 0;
143 g_counter_promise = std::make_unique<std::promise<void>>();
144 std::future<void> counter_future = g_counter_promise->get_future();
145 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
146 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
147 message_loop_->task_runner()->PostTask(
148 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
149 }
150 counter_future.wait();
151 }
152 };
153
BENCHMARK_F(BM_MessageLoopOsiThread,sequential_execution)154 BENCHMARK_F(BM_MessageLoopOsiThread, sequential_execution)(State& state) {
155 for (auto _ : state) {
156 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
157 g_counter_promise = std::make_unique<std::promise<void>>();
158 std::future<void> counter_future = g_counter_promise->get_future();
159 message_loop_->task_runner()->PostTask(
160 FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
161 counter_future.wait();
162 }
163 }
164 };
165
166 class BM_MessageLoopStlThread : public BM_MessageLoop {
167 protected:
SetUp(State & st)168 void SetUp(State& st) override {
169 BM_MessageLoop::SetUp(st);
170 std::future<void> set_up_future = set_up_promise_->get_future();
171 thread_ = new std::thread(&BM_MessageLoop::RunThread, this);
172 set_up_future.wait();
173 }
174
TearDown(State & st)175 void TearDown(State& st) override {
176 message_loop_->task_runner()->PostTask(FROM_HERE,
177 run_loop_->QuitWhenIdleClosure());
178 thread_->join();
179 delete thread_;
180 thread_ = nullptr;
181 BM_MessageLoop::TearDown(st);
182 }
183
184 std::thread* thread_ = nullptr;
185 };
186
BENCHMARK_F(BM_MessageLoopStlThread,batch_enque_dequeue)187 BENCHMARK_F(BM_MessageLoopStlThread, batch_enque_dequeue)(State& state) {
188 for (auto _ : state) {
189 g_counter = 0;
190 g_counter_promise = std::make_unique<std::promise<void>>();
191 std::future<void> counter_future = g_counter_promise->get_future();
192 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
193 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
194 message_loop_->task_runner()->PostTask(
195 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
196 }
197 counter_future.wait();
198 }
199 };
200
BENCHMARK_F(BM_MessageLoopStlThread,sequential_execution)201 BENCHMARK_F(BM_MessageLoopStlThread, sequential_execution)(State& state) {
202 for (auto _ : state) {
203 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
204 g_counter_promise = std::make_unique<std::promise<void>>();
205 std::future<void> counter_future = g_counter_promise->get_future();
206 message_loop_->task_runner()->PostTask(
207 FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
208 counter_future.wait();
209 }
210 }
211 };
212
213 class BM_MessageLoopPosixThread : public BM_MessageLoop {
214 protected:
SetUp(State & st)215 void SetUp(State& st) override {
216 BM_MessageLoop::SetUp(st);
217 std::future<void> set_up_future = set_up_promise_->get_future();
218 pthread_create(&thread_, nullptr, &BM_MessageLoop::RunPThread, (void*)this);
219 set_up_future.wait();
220 }
221
TearDown(State & st)222 void TearDown(State& st) override {
223 message_loop_->task_runner()->PostTask(FROM_HERE,
224 run_loop_->QuitWhenIdleClosure());
225 pthread_join(thread_, nullptr);
226 BM_MessageLoop::TearDown(st);
227 }
228
229 pthread_t thread_ = -1;
230 };
231
BENCHMARK_F(BM_MessageLoopPosixThread,batch_enque_dequeue)232 BENCHMARK_F(BM_MessageLoopPosixThread, batch_enque_dequeue)(State& state) {
233 for (auto _ : state) {
234 g_counter = 0;
235 g_counter_promise = std::make_unique<std::promise<void>>();
236 std::future<void> counter_future = g_counter_promise->get_future();
237 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
238 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
239 message_loop_->task_runner()->PostTask(
240 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
241 }
242 counter_future.wait();
243 }
244 };
245
BENCHMARK_F(BM_MessageLoopPosixThread,sequential_execution)246 BENCHMARK_F(BM_MessageLoopPosixThread, sequential_execution)(State& state) {
247 for (auto _ : state) {
248 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
249 g_counter_promise = std::make_unique<std::promise<void>>();
250 std::future<void> counter_future = g_counter_promise->get_future();
251 message_loop_->task_runner()->PostTask(
252 FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
253 counter_future.wait();
254 }
255 }
256 };
257
258 class BM_OsiReactorThread : public BM_ThreadPerformance {
259 protected:
SetUp(State & st)260 void SetUp(State& st) override {
261 BM_ThreadPerformance::SetUp(st);
262 thread_ = thread_new("BM_OsiReactorThread thread");
263 }
264
TearDown(State & st)265 void TearDown(State& st) override {
266 thread_free(thread_);
267 thread_ = nullptr;
268 BM_ThreadPerformance::TearDown(st);
269 }
270
271 thread_t* thread_ = nullptr;
272 };
273
BENCHMARK_F(BM_OsiReactorThread,batch_enque_dequeue_using_thread_post)274 BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_thread_post)
275 (State& state) {
276 for (auto _ : state) {
277 g_counter = 0;
278 g_counter_promise = std::make_unique<std::promise<void>>();
279 std::future<void> counter_future = g_counter_promise->get_future();
280 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
281 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
282 thread_post(thread_, pthread_callback_batch, bt_msg_queue_);
283 }
284 counter_future.wait();
285 }
286 };
287
BENCHMARK_F(BM_OsiReactorThread,sequential_execution_using_thread_post)288 BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_thread_post)
289 (State& state) {
290 for (auto _ : state) {
291 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
292 g_counter_promise = std::make_unique<std::promise<void>>();
293 std::future<void> counter_future = g_counter_promise->get_future();
294 thread_post(thread_, callback_sequential, nullptr);
295 counter_future.wait();
296 }
297 }
298 };
299
BENCHMARK_F(BM_OsiReactorThread,batch_enque_dequeue_using_reactor)300 BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_reactor)
301 (State& state) {
302 fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
303 callback_batch, nullptr);
304 for (auto _ : state) {
305 g_counter = 0;
306 g_counter_promise = std::make_unique<std::promise<void>>();
307 std::future<void> counter_future = g_counter_promise->get_future();
308 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
309 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
310 }
311 counter_future.wait();
312 }
313 };
314
BENCHMARK_F(BM_OsiReactorThread,sequential_execution_using_reactor)315 BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_reactor)
316 (State& state) {
317 fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
318 callback_sequential_queue, nullptr);
319 for (auto _ : state) {
320 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
321 g_counter_promise = std::make_unique<std::promise<void>>();
322 std::future<void> counter_future = g_counter_promise->get_future();
323 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
324 counter_future.wait();
325 }
326 }
327 };
328
329 class BM_MessageLooopThread : public BM_ThreadPerformance {
330 protected:
SetUp(State & st)331 void SetUp(State& st) override {
332 BM_ThreadPerformance::SetUp(st);
333 std::future<void> set_up_future = set_up_promise_->get_future();
334 message_loop_thread_ =
335 new MessageLoopThread("BM_MessageLooopThread thread");
336 message_loop_thread_->StartUp();
337 message_loop_thread_->DoInThread(
338 FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
339 base::Unretained(set_up_promise_.get())));
340 set_up_future.wait();
341 }
342
TearDown(State & st)343 void TearDown(State& st) override {
344 message_loop_thread_->ShutDown();
345 delete message_loop_thread_;
346 message_loop_thread_ = nullptr;
347 BM_ThreadPerformance::TearDown(st);
348 }
349
350 MessageLoopThread* message_loop_thread_ = nullptr;
351 };
352
BENCHMARK_F(BM_MessageLooopThread,batch_enque_dequeue)353 BENCHMARK_F(BM_MessageLooopThread, batch_enque_dequeue)(State& state) {
354 for (auto _ : state) {
355 g_counter = 0;
356 g_counter_promise = std::make_unique<std::promise<void>>();
357 std::future<void> counter_future = g_counter_promise->get_future();
358 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
359 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
360 message_loop_thread_->DoInThread(
361 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
362 }
363 counter_future.wait();
364 }
365 };
366
BENCHMARK_F(BM_MessageLooopThread,sequential_execution)367 BENCHMARK_F(BM_MessageLooopThread, sequential_execution)(State& state) {
368 for (auto _ : state) {
369 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
370 g_counter_promise = std::make_unique<std::promise<void>>();
371 std::future<void> counter_future = g_counter_promise->get_future();
372 message_loop_thread_->DoInThread(
373 FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
374 counter_future.wait();
375 }
376 }
377 };
378
379 class BM_LibChromeThread : public BM_ThreadPerformance {
380 protected:
SetUp(State & st)381 void SetUp(State& st) override {
382 BM_ThreadPerformance::SetUp(st);
383 std::future<void> set_up_future = set_up_promise_->get_future();
384 thread_ = new base::Thread("BM_LibChromeThread thread");
385 thread_->Start();
386 thread_->task_runner()->PostTask(
387 FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
388 base::Unretained(set_up_promise_.get())));
389 set_up_future.wait();
390 }
391
TearDown(State & st)392 void TearDown(State& st) override {
393 thread_->Stop();
394 delete thread_;
395 thread_ = nullptr;
396 BM_ThreadPerformance::TearDown(st);
397 }
398
399 base::Thread* thread_ = nullptr;
400 };
401
BENCHMARK_F(BM_LibChromeThread,batch_enque_dequeue)402 BENCHMARK_F(BM_LibChromeThread, batch_enque_dequeue)(State& state) {
403 for (auto _ : state) {
404 g_counter = 0;
405 g_counter_promise = std::make_unique<std::promise<void>>();
406 std::future<void> counter_future = g_counter_promise->get_future();
407 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
408 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
409 thread_->task_runner()->PostTask(
410 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
411 }
412 counter_future.wait();
413 }
414 };
415
BENCHMARK_F(BM_LibChromeThread,sequential_execution)416 BENCHMARK_F(BM_LibChromeThread, sequential_execution)(State& state) {
417 for (auto _ : state) {
418 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
419 g_counter_promise = std::make_unique<std::promise<void>>();
420 std::future<void> counter_future = g_counter_promise->get_future();
421 thread_->task_runner()->PostTask(
422 FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
423 counter_future.wait();
424 }
425 }
426 };
427
main(int argc,char ** argv)428 int main(int argc, char** argv) {
429 ::benchmark::Initialize(&argc, argv);
430 if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
431 return 1;
432 }
433 ::benchmark::RunSpecifiedBenchmarks();
434 }
435