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