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