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