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 <bluetooth/log.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include <unistd.h>
24
25 #include <chrono>
26 #include <future>
27 #include <thread>
28
29 #include "abstract_message_loop.h"
30 #include "common/message_loop_thread.h"
31 #include "osi/include/fixed_queue.h"
32 #include "osi/include/thread.h"
33
34 using bluetooth::common::MessageLoopThread;
35 using namespace bluetooth;
36
37 #define NUM_MESSAGES_TO_SEND 100000
38
39 static int g_counter = 0;
40 static std::unique_ptr<std::promise<void>> g_counter_promise = nullptr;
41
callback_batch(fixed_queue_t * queue,void * data)42 void callback_batch(fixed_queue_t* queue, void* data) {
43 if (queue != nullptr) {
44 fixed_queue_dequeue(queue);
45 }
46 g_counter++;
47 if (g_counter >= NUM_MESSAGES_TO_SEND) {
48 g_counter_promise->set_value();
49 }
50 }
51
52 class PerformanceTest : public testing::Test {
53 protected:
SetUp()54 void SetUp() override {
55 set_up_promise_ = std::make_unique<std::promise<void>>();
56 g_counter = 0;
57 bt_msg_queue_ = fixed_queue_new(SIZE_MAX);
58 }
TearDown()59 void TearDown() override {
60 fixed_queue_free(bt_msg_queue_, nullptr);
61 bt_msg_queue_ = nullptr;
62 set_up_promise_.reset(nullptr);
63 g_counter_promise.reset(nullptr);
64 }
65 fixed_queue_t* bt_msg_queue_ = nullptr;
66 std::unique_ptr<std::promise<void>> set_up_promise_ = nullptr;
67 };
68
69 class MessageLoopPerformanceTest : public PerformanceTest {
70 public:
RunThread(void * context)71 static void RunThread(void* context) {
72 auto test = static_cast<MessageLoopPerformanceTest*>(context);
73 test->RunMessageLoop();
74 }
RunPThread(void * context)75 static void* RunPThread(void* context) {
76 auto test = static_cast<MessageLoopPerformanceTest*>(context);
77 test->RunMessageLoop();
78 return nullptr;
79 }
RunMessageLoop()80 void RunMessageLoop() {
81 message_loop_ = new btbase::AbstractMessageLoop();
82 run_loop_ = new base::RunLoop();
83 message_loop_->task_runner()->PostTask(
84 FROM_HERE, base::Bind(&std::promise<void>::set_value,
85 base::Unretained(set_up_promise_.get())));
86 run_loop_->Run();
87 delete message_loop_;
88 message_loop_ = nullptr;
89 delete run_loop_;
90 run_loop_ = nullptr;
91 }
92
93 protected:
94 btbase::AbstractMessageLoop* message_loop_ = nullptr;
95 base::RunLoop* run_loop_ = nullptr;
96 };
97
98 class OsiThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest {
99 protected:
SetUp()100 void SetUp() override {
101 MessageLoopPerformanceTest::SetUp();
102 std::future<void> set_up_future = set_up_promise_->get_future();
103 thread_ = thread_new("OsiThreadMessageLoopPerformanceTest thread");
104 thread_post(thread_, &MessageLoopPerformanceTest::RunThread, this);
105 set_up_future.wait();
106 }
107
TearDown()108 void TearDown() override {
109 message_loop_->task_runner()->PostTask(FROM_HERE,
110 run_loop_->QuitWhenIdleClosure());
111 thread_free(thread_);
112 thread_ = nullptr;
113 MessageLoopPerformanceTest::TearDown();
114 }
115
116 thread_t* thread_ = nullptr;
117 };
118
TEST_F(OsiThreadMessageLoopPerformanceTest,message_loop_speed_test)119 TEST_F(OsiThreadMessageLoopPerformanceTest, message_loop_speed_test) {
120 g_counter = 0;
121 g_counter_promise = std::make_unique<std::promise<void>>();
122 std::future<void> counter_future = g_counter_promise->get_future();
123 std::chrono::steady_clock::time_point start_time =
124 std::chrono::steady_clock::now();
125
126 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
127 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
128 message_loop_->task_runner()->PostTask(
129 FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
130 }
131 counter_future.wait();
132
133 std::chrono::steady_clock::time_point end_time =
134 std::chrono::steady_clock::now();
135 std::chrono::milliseconds duration =
136 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
137 start_time);
138
139 log::info("OsiThreadMessageLoopPerformanceTest, {} ms, {} messages",
140 duration.count(), NUM_MESSAGES_TO_SEND);
141 }
142
143 class StlThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest {
144 protected:
SetUp()145 void SetUp() override {
146 MessageLoopPerformanceTest::SetUp();
147 std::future<void> set_up_future = set_up_promise_->get_future();
148 thread_ = new std::thread(&MessageLoopPerformanceTest::RunThread, this);
149 set_up_future.wait();
150 }
151
TearDown()152 void TearDown() override {
153 message_loop_->task_runner()->PostTask(FROM_HERE,
154 run_loop_->QuitWhenIdleClosure());
155 thread_->join();
156 delete thread_;
157 thread_ = nullptr;
158 MessageLoopPerformanceTest::TearDown();
159 }
160
161 std::thread* thread_ = nullptr;
162 };
163
TEST_F(StlThreadMessageLoopPerformanceTest,stl_thread_speed_test)164 TEST_F(StlThreadMessageLoopPerformanceTest, stl_thread_speed_test) {
165 g_counter = 0;
166 g_counter_promise = std::make_unique<std::promise<void>>();
167 std::future<void> counter_future = g_counter_promise->get_future();
168 std::chrono::steady_clock::time_point start_time =
169 std::chrono::steady_clock::now();
170
171 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
172 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
173 message_loop_->task_runner()->PostTask(
174 FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
175 }
176 counter_future.wait();
177
178 std::chrono::steady_clock::time_point end_time =
179 std::chrono::steady_clock::now();
180 std::chrono::milliseconds duration =
181 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
182 start_time);
183
184 log::info("StlThreadMessageLoopPerformanceTest, {} ms, {} messages",
185 duration.count(), NUM_MESSAGES_TO_SEND);
186 }
187
188 class PosixThreadMessageLoopPerformanceTest
189 : public MessageLoopPerformanceTest {
190 protected:
SetUp()191 void SetUp() override {
192 MessageLoopPerformanceTest::SetUp();
193 std::future<void> set_up_future = set_up_promise_->get_future();
194 pthread_create(&thread_, nullptr, &MessageLoopPerformanceTest::RunPThread,
195 (void*)this);
196 set_up_future.wait();
197 }
198
TearDown()199 void TearDown() override {
200 message_loop_->task_runner()->PostTask(FROM_HERE,
201 run_loop_->QuitWhenIdleClosure());
202 pthread_join(thread_, nullptr);
203 MessageLoopPerformanceTest::TearDown();
204 }
205
206 pthread_t thread_ = -1;
207 };
208
TEST_F(PosixThreadMessageLoopPerformanceTest,stl_thread_speed_test)209 TEST_F(PosixThreadMessageLoopPerformanceTest, stl_thread_speed_test) {
210 g_counter = 0;
211 g_counter_promise = std::make_unique<std::promise<void>>();
212 std::future<void> counter_future = g_counter_promise->get_future();
213
214 std::chrono::steady_clock::time_point start_time =
215 std::chrono::steady_clock::now();
216
217 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
218 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
219 message_loop_->task_runner()->PostTask(
220 FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
221 }
222 counter_future.wait();
223
224 std::chrono::steady_clock::time_point end_time =
225 std::chrono::steady_clock::now();
226 std::chrono::milliseconds duration =
227 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
228 start_time);
229
230 log::info("PosixThreadMessageLoopPerformanceTest, {} ms, {} messages",
231 duration.count(), NUM_MESSAGES_TO_SEND);
232 }
233
234 class ReactorPerformanceTest : public PerformanceTest {
235 protected:
SetUp()236 void SetUp() override {
237 PerformanceTest::SetUp();
238 thread_ = thread_new("ReactorPerformanceTest thread");
239 }
240
TearDown()241 void TearDown() override {
242 thread_free(thread_);
243 thread_ = nullptr;
244 PerformanceTest::TearDown();
245 }
246
247 thread_t* thread_ = nullptr;
248 };
249
TEST_F(ReactorPerformanceTest,reactor_thread_speed_test)250 TEST_F(ReactorPerformanceTest, reactor_thread_speed_test) {
251 g_counter = 0;
252 g_counter_promise = std::make_unique<std::promise<void>>();
253 std::future<void> counter_future = g_counter_promise->get_future();
254 fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
255 callback_batch, nullptr);
256
257 std::chrono::steady_clock::time_point start_time =
258 std::chrono::steady_clock::now();
259
260 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
261 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
262 }
263 counter_future.wait();
264
265 std::chrono::steady_clock::time_point end_time =
266 std::chrono::steady_clock::now();
267 std::chrono::milliseconds duration =
268 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
269 start_time);
270 fixed_queue_unregister_dequeue(bt_msg_queue_);
271
272 log::info("ReactorPerformanceTest, {} ms, {} messages", duration.count(),
273 NUM_MESSAGES_TO_SEND);
274 }
275
276 class WorkerThreadPerformanceTest : public PerformanceTest {
277 protected:
SetUp()278 void SetUp() override {
279 PerformanceTest::SetUp();
280 std::future<void> set_up_future = set_up_promise_->get_future();
281 worker_thread_ =
282 new MessageLoopThread("WorkerThreadPerformanceTest thread");
283 worker_thread_->StartUp();
284 worker_thread_->DoInThread(
285 FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
286 base::Unretained(set_up_promise_.get())));
287 set_up_future.wait();
288 }
289
TearDown()290 void TearDown() override {
291 worker_thread_->ShutDown();
292 delete worker_thread_;
293 worker_thread_ = nullptr;
294 PerformanceTest::TearDown();
295 }
296
297 MessageLoopThread* worker_thread_ = nullptr;
298 };
299
TEST_F(WorkerThreadPerformanceTest,worker_thread_speed_test)300 TEST_F(WorkerThreadPerformanceTest, worker_thread_speed_test) {
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
305 std::chrono::steady_clock::time_point start_time =
306 std::chrono::steady_clock::now();
307
308 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
309 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
310 worker_thread_->DoInThread(
311 FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
312 }
313 counter_future.wait();
314
315 std::chrono::steady_clock::time_point end_time =
316 std::chrono::steady_clock::now();
317 std::chrono::milliseconds duration =
318 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
319 start_time);
320
321 log::info("WorkerThreadPerformanceTest, {} ms, {} messages", duration.count(),
322 NUM_MESSAGES_TO_SEND);
323 }
324
325 class LibChromeThreadPerformanceTest : public PerformanceTest {
326 protected:
SetUp()327 void SetUp() override {
328 PerformanceTest::SetUp();
329 std::future<void> set_up_future = set_up_promise_->get_future();
330 thread_ = new base::Thread("LibChromeThreadPerformanceTest thread");
331 thread_->Start();
332 thread_->task_runner()->PostTask(
333 FROM_HERE, base::Bind(&std::promise<void>::set_value,
334 base::Unretained(set_up_promise_.get())));
335 set_up_future.wait();
336 }
337
TearDown()338 void TearDown() override {
339 thread_->Stop();
340 delete thread_;
341 thread_ = nullptr;
342 PerformanceTest::TearDown();
343 }
344
345 base::Thread* thread_ = nullptr;
346 };
347
TEST_F(LibChromeThreadPerformanceTest,worker_thread_speed_test)348 TEST_F(LibChromeThreadPerformanceTest, worker_thread_speed_test) {
349 g_counter = 0;
350 g_counter_promise = std::make_unique<std::promise<void>>();
351 std::future<void> counter_future = g_counter_promise->get_future();
352
353 std::chrono::steady_clock::time_point start_time =
354 std::chrono::steady_clock::now();
355
356 for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
357 fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
358 thread_->task_runner()->PostTask(
359 FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
360 }
361 counter_future.wait();
362
363 std::chrono::steady_clock::time_point end_time =
364 std::chrono::steady_clock::now();
365 std::chrono::milliseconds duration =
366 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
367 start_time);
368
369 log::info("LibChromeThreadPerformanceTest, {} ms, {} messages",
370 duration.count(), NUM_MESSAGES_TO_SEND);
371 }
372