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