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 // TODO(b/369381361) Enfore -Wmissing-prototypes
34 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
35
36 using ::benchmark::State;
37 using bluetooth::common::MessageLoopThread;
38
39 #define NUM_MESSAGES_TO_SEND 100000
40
41 static std::atomic<int> g_counter = 0;
42 static std::unique_ptr<std::promise<void>> g_counter_promise = nullptr;
43
pthread_callback_batch(void * context)44 void pthread_callback_batch(void* context) {
45 auto queue = static_cast<fixed_queue_t*>(context);
46 bluetooth::log::assert_that(queue != nullptr, "assert failed: queue != nullptr");
47 fixed_queue_dequeue(queue);
48 g_counter++;
49 if (g_counter >= NUM_MESSAGES_TO_SEND) {
50 g_counter_promise->set_value();
51 }
52 }
53
callback_sequential(void *)54 void callback_sequential(void* /* context */) { g_counter_promise->set_value(); }
55
callback_sequential_queue(fixed_queue_t * queue,void *)56 void callback_sequential_queue(fixed_queue_t* queue, void* /* context */) {
57 bluetooth::log::assert_that(queue != nullptr, "assert failed: queue != nullptr");
58 fixed_queue_dequeue(queue);
59 g_counter_promise->set_value();
60 }
61
callback_batch(fixed_queue_t * queue,void *)62 void callback_batch(fixed_queue_t* queue, void* /* data */) {
63 bluetooth::log::assert_that(queue != nullptr, "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(FROM_HERE,
105 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, run_loop_->QuitWhenIdleClosure());
131 thread_free(thread_);
132 thread_ = nullptr;
133 BM_MessageLoop::TearDown(st);
134 }
135
136 thread_t* thread_ = nullptr;
137 };
138
BENCHMARK_F(BM_MessageLoopOsiThread,batch_enque_dequeue)139 BENCHMARK_F(BM_MessageLoopOsiThread, batch_enque_dequeue)(State& state) {
140 for (auto _ : state) {
141 g_counter = 0;
142 g_counter_promise = std::make_unique<std::promise<void>>();
143 std::future<void> counter_future = g_counter_promise->get_future();
144 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
145 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
146 message_loop_->task_runner()->PostTask(
147 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
148 }
149 counter_future.wait();
150 }
151 }
152
BENCHMARK_F(BM_MessageLoopOsiThread,sequential_execution)153 BENCHMARK_F(BM_MessageLoopOsiThread, sequential_execution)(State& state) {
154 for (auto _ : state) {
155 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
156 g_counter_promise = std::make_unique<std::promise<void>>();
157 std::future<void> counter_future = g_counter_promise->get_future();
158 message_loop_->task_runner()->PostTask(FROM_HERE,
159 base::BindOnce(&callback_sequential, nullptr));
160 counter_future.wait();
161 }
162 }
163 }
164
165 class BM_MessageLoopStlThread : public BM_MessageLoop {
166 protected:
SetUp(State & st)167 void SetUp(State& st) override {
168 BM_MessageLoop::SetUp(st);
169 std::future<void> set_up_future = set_up_promise_->get_future();
170 thread_ = new std::thread(&BM_MessageLoop::RunThread, this);
171 set_up_future.wait();
172 }
173
TearDown(State & st)174 void TearDown(State& st) override {
175 message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitWhenIdleClosure());
176 thread_->join();
177 delete thread_;
178 thread_ = nullptr;
179 BM_MessageLoop::TearDown(st);
180 }
181
182 std::thread* thread_ = nullptr;
183 };
184
BENCHMARK_F(BM_MessageLoopStlThread,batch_enque_dequeue)185 BENCHMARK_F(BM_MessageLoopStlThread, batch_enque_dequeue)(State& state) {
186 for (auto _ : state) {
187 g_counter = 0;
188 g_counter_promise = std::make_unique<std::promise<void>>();
189 std::future<void> counter_future = g_counter_promise->get_future();
190 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
191 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
192 message_loop_->task_runner()->PostTask(
193 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
194 }
195 counter_future.wait();
196 }
197 }
198
BENCHMARK_F(BM_MessageLoopStlThread,sequential_execution)199 BENCHMARK_F(BM_MessageLoopStlThread, sequential_execution)(State& state) {
200 for (auto _ : state) {
201 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
202 g_counter_promise = std::make_unique<std::promise<void>>();
203 std::future<void> counter_future = g_counter_promise->get_future();
204 message_loop_->task_runner()->PostTask(FROM_HERE,
205 base::BindOnce(&callback_sequential, nullptr));
206 counter_future.wait();
207 }
208 }
209 }
210
211 class BM_MessageLoopPosixThread : public BM_MessageLoop {
212 protected:
SetUp(State & st)213 void SetUp(State& st) override {
214 BM_MessageLoop::SetUp(st);
215 std::future<void> set_up_future = set_up_promise_->get_future();
216 pthread_create(&thread_, nullptr, &BM_MessageLoop::RunPThread, (void*)this);
217 set_up_future.wait();
218 }
219
TearDown(State & st)220 void TearDown(State& st) override {
221 message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitWhenIdleClosure());
222 pthread_join(thread_, nullptr);
223 BM_MessageLoop::TearDown(st);
224 }
225
226 pthread_t thread_ = -1;
227 };
228
BENCHMARK_F(BM_MessageLoopPosixThread,batch_enque_dequeue)229 BENCHMARK_F(BM_MessageLoopPosixThread, batch_enque_dequeue)(State& state) {
230 for (auto _ : state) {
231 g_counter = 0;
232 g_counter_promise = std::make_unique<std::promise<void>>();
233 std::future<void> counter_future = g_counter_promise->get_future();
234 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
235 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
236 message_loop_->task_runner()->PostTask(
237 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
238 }
239 counter_future.wait();
240 }
241 }
242
BENCHMARK_F(BM_MessageLoopPosixThread,sequential_execution)243 BENCHMARK_F(BM_MessageLoopPosixThread, sequential_execution)(State& state) {
244 for (auto _ : state) {
245 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
246 g_counter_promise = std::make_unique<std::promise<void>>();
247 std::future<void> counter_future = g_counter_promise->get_future();
248 message_loop_->task_runner()->PostTask(FROM_HERE,
249 base::BindOnce(&callback_sequential, nullptr));
250 counter_future.wait();
251 }
252 }
253 }
254
255 class BM_OsiReactorThread : public BM_ThreadPerformance {
256 protected:
SetUp(State & st)257 void SetUp(State& st) override {
258 BM_ThreadPerformance::SetUp(st);
259 thread_ = thread_new("BM_OsiReactorThread thread");
260 }
261
TearDown(State & st)262 void TearDown(State& st) override {
263 thread_free(thread_);
264 thread_ = nullptr;
265 BM_ThreadPerformance::TearDown(st);
266 }
267
268 thread_t* thread_ = nullptr;
269 };
270
BENCHMARK_F(BM_OsiReactorThread,batch_enque_dequeue_using_thread_post)271 BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_thread_post)
272 (State& state) {
273 for (auto _ : state) {
274 g_counter = 0;
275 g_counter_promise = std::make_unique<std::promise<void>>();
276 std::future<void> counter_future = g_counter_promise->get_future();
277 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
278 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
279 thread_post(thread_, pthread_callback_batch, bt_msg_queue_);
280 }
281 counter_future.wait();
282 }
283 }
284
BENCHMARK_F(BM_OsiReactorThread,sequential_execution_using_thread_post)285 BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_thread_post)
286 (State& state) {
287 for (auto _ : state) {
288 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
289 g_counter_promise = std::make_unique<std::promise<void>>();
290 std::future<void> counter_future = g_counter_promise->get_future();
291 thread_post(thread_, callback_sequential, nullptr);
292 counter_future.wait();
293 }
294 }
295 }
296
BENCHMARK_F(BM_OsiReactorThread,batch_enque_dequeue_using_reactor)297 BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_reactor)
298 (State& state) {
299 fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_), callback_batch, nullptr);
300 for (auto _ : state) {
301 g_counter = 0;
302 g_counter_promise = std::make_unique<std::promise<void>>();
303 std::future<void> counter_future = g_counter_promise->get_future();
304 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
305 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
306 }
307 counter_future.wait();
308 }
309 }
310
BENCHMARK_F(BM_OsiReactorThread,sequential_execution_using_reactor)311 BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_reactor)
312 (State& state) {
313 fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
314 callback_sequential_queue, nullptr);
315 for (auto _ : state) {
316 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
317 g_counter_promise = std::make_unique<std::promise<void>>();
318 std::future<void> counter_future = g_counter_promise->get_future();
319 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
320 counter_future.wait();
321 }
322 }
323 }
324
325 class BM_MessageLooopThread : public BM_ThreadPerformance {
326 protected:
SetUp(State & st)327 void SetUp(State& st) override {
328 BM_ThreadPerformance::SetUp(st);
329 std::future<void> set_up_future = set_up_promise_->get_future();
330 message_loop_thread_ = new MessageLoopThread("BM_MessageLooopThread thread");
331 message_loop_thread_->StartUp();
332 message_loop_thread_->DoInThread(FROM_HERE,
333 base::BindOnce(&std::promise<void>::set_value,
334 base::Unretained(set_up_promise_.get())));
335 set_up_future.wait();
336 }
337
TearDown(State & st)338 void TearDown(State& st) override {
339 message_loop_thread_->ShutDown();
340 delete message_loop_thread_;
341 message_loop_thread_ = nullptr;
342 BM_ThreadPerformance::TearDown(st);
343 }
344
345 MessageLoopThread* message_loop_thread_ = nullptr;
346 };
347
BENCHMARK_F(BM_MessageLooopThread,batch_enque_dequeue)348 BENCHMARK_F(BM_MessageLooopThread, batch_enque_dequeue)(State& state) {
349 for (auto _ : state) {
350 g_counter = 0;
351 g_counter_promise = std::make_unique<std::promise<void>>();
352 std::future<void> counter_future = g_counter_promise->get_future();
353 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
354 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
355 message_loop_thread_->DoInThread(FROM_HERE,
356 base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
357 }
358 counter_future.wait();
359 }
360 }
361
BENCHMARK_F(BM_MessageLooopThread,sequential_execution)362 BENCHMARK_F(BM_MessageLooopThread, sequential_execution)(State& state) {
363 for (auto _ : state) {
364 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
365 g_counter_promise = std::make_unique<std::promise<void>>();
366 std::future<void> counter_future = g_counter_promise->get_future();
367 message_loop_thread_->DoInThread(FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
368 counter_future.wait();
369 }
370 }
371 }
372
373 class BM_LibChromeThread : public BM_ThreadPerformance {
374 protected:
SetUp(State & st)375 void SetUp(State& st) override {
376 BM_ThreadPerformance::SetUp(st);
377 std::future<void> set_up_future = set_up_promise_->get_future();
378 thread_ = new base::Thread("BM_LibChromeThread thread");
379 thread_->Start();
380 thread_->task_runner()->PostTask(FROM_HERE,
381 base::BindOnce(&std::promise<void>::set_value,
382 base::Unretained(set_up_promise_.get())));
383 set_up_future.wait();
384 }
385
TearDown(State & st)386 void TearDown(State& st) override {
387 thread_->Stop();
388 delete thread_;
389 thread_ = nullptr;
390 BM_ThreadPerformance::TearDown(st);
391 }
392
393 base::Thread* thread_ = nullptr;
394 };
395
BENCHMARK_F(BM_LibChromeThread,batch_enque_dequeue)396 BENCHMARK_F(BM_LibChromeThread, batch_enque_dequeue)(State& state) {
397 for (auto _ : state) {
398 g_counter = 0;
399 g_counter_promise = std::make_unique<std::promise<void>>();
400 std::future<void> counter_future = g_counter_promise->get_future();
401 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
402 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
403 thread_->task_runner()->PostTask(FROM_HERE,
404 base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
405 }
406 counter_future.wait();
407 }
408 }
409
BENCHMARK_F(BM_LibChromeThread,sequential_execution)410 BENCHMARK_F(BM_LibChromeThread, sequential_execution)(State& state) {
411 for (auto _ : state) {
412 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
413 g_counter_promise = std::make_unique<std::promise<void>>();
414 std::future<void> counter_future = g_counter_promise->get_future();
415 thread_->task_runner()->PostTask(FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
416 counter_future.wait();
417 }
418 }
419 }
420
main(int argc,char ** argv)421 int main(int argc, char** argv) {
422 ::benchmark::Initialize(&argc, argv);
423 if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
424 return 1;
425 }
426 ::benchmark::RunSpecifiedBenchmarks();
427 }
428