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