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