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