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