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