blob: 4c38feda91a3fff3c42fb761466e41da47d03a67 [file] [log] [blame]
/*
* 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 <base/bind.h>
#include <base/logging.h>
#include <base/run_loop.h>
#include <base/threading/thread.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unistd.h>
#include <chrono>
#include <future>
#include <iostream>
#include <thread>
#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<std::promise<void>> 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<std::promise<void>>();
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<std::promise<void>> set_up_promise_ = nullptr;
};
class MessageLoopPerformanceTest : public PerformanceTest {
public:
static void RunThread(void* context) {
auto test = static_cast<MessageLoopPerformanceTest*>(context);
test->RunMessageLoop();
}
static void* RunPThread(void* context) {
auto test = static_cast<MessageLoopPerformanceTest*>(context);
test->RunMessageLoop();
return nullptr;
}
void RunMessageLoop() {
message_loop_ = new base::MessageLoop();
run_loop_ = new base::RunLoop();
message_loop_->task_runner()->PostTask(
FROM_HERE, base::Bind(&std::promise<void>::set_value,
base::Unretained(set_up_promise_.get())));
run_loop_->Run();
delete message_loop_;
message_loop_ = nullptr;
delete run_loop_;
run_loop_ = nullptr;
}
protected:
base::MessageLoop* message_loop_ = nullptr;
base::RunLoop* run_loop_ = nullptr;
};
class OsiThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest {
protected:
void SetUp() override {
MessageLoopPerformanceTest::SetUp();
std::future<void> 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::promise<void>>();
std::future<void> 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<std::chrono::milliseconds>(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<void> 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::promise<void>>();
std::future<void> 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<std::chrono::milliseconds>(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<void> 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::promise<void>>();
std::future<void> 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<std::chrono::milliseconds>(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::promise<void>>();
std::future<void> 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<std::chrono::milliseconds>(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<void> 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<void>::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::promise<void>>();
std::future<void> 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<std::chrono::milliseconds>(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<void> 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<void>::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::promise<void>>();
std::future<void> 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<std::chrono::milliseconds>(end_time -
start_time);
LOG(INFO) << "LibChromeThreadPerformanceTest, " << duration.count() << " ms, "
<< NUM_MESSAGES_TO_SEND << " messages";
}