• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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