/* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "abstract_message_loop.h" #include "common/message_loop_thread.h" #include "osi/include/fixed_queue.h" #include "osi/include/thread.h" using bluetooth::common::MessageLoopThread; #define NUM_MESSAGES_TO_SEND 100000 volatile static int g_counter = 0; static std::unique_ptr> g_counter_promise = nullptr; void callback_batch(fixed_queue_t* queue, void* data) { if (queue != nullptr) { fixed_queue_dequeue(queue); } g_counter++; if (g_counter >= NUM_MESSAGES_TO_SEND) { g_counter_promise->set_value(); } } class PerformanceTest : public testing::Test { protected: void SetUp() override { set_up_promise_ = std::make_unique>(); g_counter = 0; bt_msg_queue_ = fixed_queue_new(SIZE_MAX); } void TearDown() override { fixed_queue_free(bt_msg_queue_, nullptr); bt_msg_queue_ = nullptr; set_up_promise_.reset(nullptr); g_counter_promise.reset(nullptr); } fixed_queue_t* bt_msg_queue_ = nullptr; std::unique_ptr> set_up_promise_ = nullptr; }; class MessageLoopPerformanceTest : public PerformanceTest { public: static void RunThread(void* context) { auto test = static_cast(context); test->RunMessageLoop(); } static void* RunPThread(void* context) { auto test = static_cast(context); test->RunMessageLoop(); return nullptr; } void RunMessageLoop() { message_loop_ = new btbase::AbstractMessageLoop(); run_loop_ = new base::RunLoop(); message_loop_->task_runner()->PostTask( FROM_HERE, base::Bind(&std::promise::set_value, base::Unretained(set_up_promise_.get()))); run_loop_->Run(); delete message_loop_; message_loop_ = nullptr; delete run_loop_; run_loop_ = nullptr; } protected: btbase::AbstractMessageLoop* message_loop_ = nullptr; base::RunLoop* run_loop_ = nullptr; }; class OsiThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest { protected: void SetUp() override { MessageLoopPerformanceTest::SetUp(); std::future set_up_future = set_up_promise_->get_future(); thread_ = thread_new("OsiThreadMessageLoopPerformanceTest thread"); thread_post(thread_, &MessageLoopPerformanceTest::RunThread, this); set_up_future.wait(); } void TearDown() override { message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitWhenIdleClosure()); thread_free(thread_); thread_ = nullptr; MessageLoopPerformanceTest::TearDown(); } thread_t* thread_ = nullptr; }; TEST_F(OsiThreadMessageLoopPerformanceTest, message_loop_speed_test) { g_counter = 0; g_counter_promise = std::make_unique>(); std::future counter_future = g_counter_promise->get_future(); std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter); message_loop_->task_runner()->PostTask( FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr)); } counter_future.wait(); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); std::chrono::milliseconds duration = std::chrono::duration_cast(end_time - start_time); LOG(INFO) << "OsiThreadMessageLoopPerformanceTest, " << duration.count() << " ms, " << NUM_MESSAGES_TO_SEND << " messages"; } class StlThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest { protected: void SetUp() override { MessageLoopPerformanceTest::SetUp(); std::future set_up_future = set_up_promise_->get_future(); thread_ = new std::thread(&MessageLoopPerformanceTest::RunThread, this); set_up_future.wait(); } void TearDown() override { message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitWhenIdleClosure()); thread_->join(); delete thread_; thread_ = nullptr; MessageLoopPerformanceTest::TearDown(); } std::thread* thread_ = nullptr; }; TEST_F(StlThreadMessageLoopPerformanceTest, stl_thread_speed_test) { g_counter = 0; g_counter_promise = std::make_unique>(); std::future counter_future = g_counter_promise->get_future(); std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter); message_loop_->task_runner()->PostTask( FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr)); } counter_future.wait(); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); std::chrono::milliseconds duration = std::chrono::duration_cast(end_time - start_time); LOG(INFO) << "StlThreadMessageLoopPerformanceTest, " << duration.count() << " ms, " << NUM_MESSAGES_TO_SEND << " messages"; } class PosixThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest { protected: void SetUp() override { MessageLoopPerformanceTest::SetUp(); std::future set_up_future = set_up_promise_->get_future(); pthread_create(&thread_, nullptr, &MessageLoopPerformanceTest::RunPThread, (void*)this); set_up_future.wait(); } void TearDown() override { message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitWhenIdleClosure()); pthread_join(thread_, nullptr); MessageLoopPerformanceTest::TearDown(); } pthread_t thread_ = -1; }; TEST_F(PosixThreadMessageLoopPerformanceTest, stl_thread_speed_test) { g_counter = 0; g_counter_promise = std::make_unique>(); std::future counter_future = g_counter_promise->get_future(); std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter); message_loop_->task_runner()->PostTask( FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr)); } counter_future.wait(); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); std::chrono::milliseconds duration = std::chrono::duration_cast(end_time - start_time); LOG(INFO) << "PosixThreadMessageLoopPerformanceTest, " << duration.count() << " ms, " << NUM_MESSAGES_TO_SEND << " messages"; } class ReactorPerformanceTest : public PerformanceTest { protected: void SetUp() override { PerformanceTest::SetUp(); thread_ = thread_new("ReactorPerformanceTest thread"); } void TearDown() override { thread_free(thread_); thread_ = nullptr; PerformanceTest::TearDown(); } thread_t* thread_ = nullptr; }; TEST_F(ReactorPerformanceTest, reactor_thread_speed_test) { g_counter = 0; g_counter_promise = std::make_unique>(); std::future counter_future = g_counter_promise->get_future(); fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_), callback_batch, nullptr); std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter); } counter_future.wait(); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); std::chrono::milliseconds duration = std::chrono::duration_cast(end_time - start_time); fixed_queue_unregister_dequeue(bt_msg_queue_); LOG(INFO) << "ReactorPerformanceTest, " << duration.count() << " ms, " << NUM_MESSAGES_TO_SEND << " messages"; } class WorkerThreadPerformanceTest : public PerformanceTest { protected: void SetUp() override { PerformanceTest::SetUp(); std::future set_up_future = set_up_promise_->get_future(); worker_thread_ = new MessageLoopThread("WorkerThreadPerformanceTest thread"); worker_thread_->StartUp(); worker_thread_->DoInThread( FROM_HERE, base::Bind(&std::promise::set_value, base::Unretained(set_up_promise_.get()))); set_up_future.wait(); } void TearDown() override { worker_thread_->ShutDown(); delete worker_thread_; worker_thread_ = nullptr; PerformanceTest::TearDown(); } MessageLoopThread* worker_thread_ = nullptr; }; TEST_F(WorkerThreadPerformanceTest, worker_thread_speed_test) { g_counter = 0; g_counter_promise = std::make_unique>(); std::future counter_future = g_counter_promise->get_future(); std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter); worker_thread_->DoInThread( FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr)); } counter_future.wait(); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); std::chrono::milliseconds duration = std::chrono::duration_cast(end_time - start_time); LOG(INFO) << "WorkerThreadPerformanceTest, " << duration.count() << " ms, " << NUM_MESSAGES_TO_SEND << " messages"; } class LibChromeThreadPerformanceTest : public PerformanceTest { protected: void SetUp() override { PerformanceTest::SetUp(); std::future set_up_future = set_up_promise_->get_future(); thread_ = new base::Thread("LibChromeThreadPerformanceTest thread"); thread_->Start(); thread_->task_runner()->PostTask( FROM_HERE, base::Bind(&std::promise::set_value, base::Unretained(set_up_promise_.get()))); set_up_future.wait(); } void TearDown() override { thread_->Stop(); delete thread_; thread_ = nullptr; PerformanceTest::TearDown(); } base::Thread* thread_ = nullptr; }; TEST_F(LibChromeThreadPerformanceTest, worker_thread_speed_test) { g_counter = 0; g_counter_promise = std::make_unique>(); std::future counter_future = g_counter_promise->get_future(); std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) { fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter); thread_->task_runner()->PostTask( FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr)); } counter_future.wait(); std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); std::chrono::milliseconds duration = std::chrono::duration_cast(end_time - start_time); LOG(INFO) << "LibChromeThreadPerformanceTest, " << duration.count() << " ms, " << NUM_MESSAGES_TO_SEND << " messages"; }