434 lines
14 KiB
C++
434 lines
14 KiB
C++
/*
|
|
* 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 <benchmark/benchmark.h>
|
|
#include <future>
|
|
#include <memory>
|
|
#include <thread>
|
|
|
|
#include "abstract_message_loop.h"
|
|
#include "common/message_loop_thread.h"
|
|
#include "osi/include/fixed_queue.h"
|
|
#include "osi/include/thread.h"
|
|
|
|
using ::benchmark::State;
|
|
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 pthread_callback_batch(void* context) {
|
|
auto queue = static_cast<fixed_queue_t*>(context);
|
|
CHECK_NE(queue, nullptr);
|
|
fixed_queue_dequeue(queue);
|
|
g_counter++;
|
|
if (g_counter >= NUM_MESSAGES_TO_SEND) {
|
|
g_counter_promise->set_value();
|
|
}
|
|
}
|
|
|
|
void callback_sequential(void* context) { g_counter_promise->set_value(); }
|
|
|
|
void callback_sequential_queue(fixed_queue_t* queue, void* context) {
|
|
CHECK_NE(queue, nullptr);
|
|
fixed_queue_dequeue(queue);
|
|
g_counter_promise->set_value();
|
|
}
|
|
|
|
void callback_batch(fixed_queue_t* queue, void* data) {
|
|
CHECK_NE(queue, nullptr);
|
|
fixed_queue_dequeue(queue);
|
|
g_counter++;
|
|
if (g_counter >= NUM_MESSAGES_TO_SEND) {
|
|
g_counter_promise->set_value();
|
|
}
|
|
}
|
|
|
|
class BM_ThreadPerformance : public ::benchmark::Fixture {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
benchmark::Fixture::SetUp(st);
|
|
set_up_promise_ = std::make_unique<std::promise<void>>();
|
|
g_counter = 0;
|
|
bt_msg_queue_ = fixed_queue_new(SIZE_MAX);
|
|
}
|
|
void TearDown(State& st) override {
|
|
fixed_queue_free(bt_msg_queue_, nullptr);
|
|
bt_msg_queue_ = nullptr;
|
|
set_up_promise_.reset(nullptr);
|
|
g_counter_promise.reset(nullptr);
|
|
benchmark::Fixture::TearDown(st);
|
|
}
|
|
fixed_queue_t* bt_msg_queue_ = nullptr;
|
|
std::unique_ptr<std::promise<void>> set_up_promise_;
|
|
};
|
|
|
|
class BM_MessageLoop : public BM_ThreadPerformance {
|
|
public:
|
|
static void RunThread(void* context) {
|
|
auto test = static_cast<BM_MessageLoop*>(context);
|
|
test->RunMessageLoop();
|
|
}
|
|
static void* RunPThread(void* context) {
|
|
auto test = static_cast<BM_MessageLoop*>(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::BindOnce(&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:
|
|
btbase::AbstractMessageLoop* message_loop_ = nullptr;
|
|
base::RunLoop* run_loop_ = nullptr;
|
|
};
|
|
|
|
class BM_MessageLoopOsiThread : public BM_MessageLoop {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
BM_MessageLoop::SetUp(st);
|
|
std::future<void> set_up_future = set_up_promise_->get_future();
|
|
thread_ = thread_new("BM_MessageLoopOnOsiThread thread");
|
|
thread_post(thread_, &BM_MessageLoop::RunThread, this);
|
|
set_up_future.wait();
|
|
}
|
|
|
|
void TearDown(State& st) override {
|
|
message_loop_->task_runner()->PostTask(FROM_HERE,
|
|
run_loop_->QuitWhenIdleClosure());
|
|
thread_free(thread_);
|
|
thread_ = nullptr;
|
|
BM_MessageLoop::TearDown(st);
|
|
}
|
|
|
|
thread_t* thread_ = nullptr;
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLoopOsiThread, batch_enque_dequeue)(State& state) {
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
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::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLoopOsiThread, sequential_execution)(State& state) {
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
message_loop_->task_runner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
class BM_MessageLoopStlThread : public BM_MessageLoop {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
BM_MessageLoop::SetUp(st);
|
|
std::future<void> set_up_future = set_up_promise_->get_future();
|
|
thread_ = new std::thread(&BM_MessageLoop::RunThread, this);
|
|
set_up_future.wait();
|
|
}
|
|
|
|
void TearDown(State& st) override {
|
|
message_loop_->task_runner()->PostTask(FROM_HERE,
|
|
run_loop_->QuitWhenIdleClosure());
|
|
thread_->join();
|
|
delete thread_;
|
|
thread_ = nullptr;
|
|
BM_MessageLoop::TearDown(st);
|
|
}
|
|
|
|
std::thread* thread_ = nullptr;
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLoopStlThread, batch_enque_dequeue)(State& state) {
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
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::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLoopStlThread, sequential_execution)(State& state) {
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
message_loop_->task_runner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
class BM_MessageLoopPosixThread : public BM_MessageLoop {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
BM_MessageLoop::SetUp(st);
|
|
std::future<void> set_up_future = set_up_promise_->get_future();
|
|
pthread_create(&thread_, nullptr, &BM_MessageLoop::RunPThread, (void*)this);
|
|
set_up_future.wait();
|
|
}
|
|
|
|
void TearDown(State& st) override {
|
|
message_loop_->task_runner()->PostTask(FROM_HERE,
|
|
run_loop_->QuitWhenIdleClosure());
|
|
pthread_join(thread_, nullptr);
|
|
BM_MessageLoop::TearDown(st);
|
|
}
|
|
|
|
pthread_t thread_ = -1;
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLoopPosixThread, batch_enque_dequeue)(State& state) {
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
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::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLoopPosixThread, sequential_execution)(State& state) {
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
message_loop_->task_runner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
class BM_OsiReactorThread : public BM_ThreadPerformance {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
BM_ThreadPerformance::SetUp(st);
|
|
thread_ = thread_new("BM_OsiReactorThread thread");
|
|
}
|
|
|
|
void TearDown(State& st) override {
|
|
thread_free(thread_);
|
|
thread_ = nullptr;
|
|
BM_ThreadPerformance::TearDown(st);
|
|
}
|
|
|
|
thread_t* thread_ = nullptr;
|
|
};
|
|
|
|
BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_thread_post)
|
|
(State& state) {
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
|
|
thread_post(thread_, pthread_callback_batch, bt_msg_queue_);
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_thread_post)
|
|
(State& state) {
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
thread_post(thread_, callback_sequential, nullptr);
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_reactor)
|
|
(State& state) {
|
|
fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
|
|
callback_batch, nullptr);
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_reactor)
|
|
(State& state) {
|
|
fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
|
|
callback_sequential_queue, nullptr);
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
class BM_MessageLooopThread : public BM_ThreadPerformance {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
BM_ThreadPerformance::SetUp(st);
|
|
std::future<void> set_up_future = set_up_promise_->get_future();
|
|
message_loop_thread_ =
|
|
new MessageLoopThread("BM_MessageLooopThread thread");
|
|
message_loop_thread_->StartUp();
|
|
message_loop_thread_->DoInThread(
|
|
FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
|
|
base::Unretained(set_up_promise_.get())));
|
|
set_up_future.wait();
|
|
}
|
|
|
|
void TearDown(State& st) override {
|
|
message_loop_thread_->ShutDown();
|
|
delete message_loop_thread_;
|
|
message_loop_thread_ = nullptr;
|
|
BM_ThreadPerformance::TearDown(st);
|
|
}
|
|
|
|
MessageLoopThread* message_loop_thread_ = nullptr;
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLooopThread, batch_enque_dequeue)(State& state) {
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
|
|
message_loop_thread_->DoInThread(
|
|
FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_MessageLooopThread, sequential_execution)(State& state) {
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
message_loop_thread_->DoInThread(
|
|
FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
class BM_LibChromeThread : public BM_ThreadPerformance {
|
|
protected:
|
|
void SetUp(State& st) override {
|
|
BM_ThreadPerformance::SetUp(st);
|
|
std::future<void> set_up_future = set_up_promise_->get_future();
|
|
thread_ = new base::Thread("BM_LibChromeThread thread");
|
|
thread_->Start();
|
|
thread_->task_runner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
|
|
base::Unretained(set_up_promise_.get())));
|
|
set_up_future.wait();
|
|
}
|
|
|
|
void TearDown(State& st) override {
|
|
thread_->Stop();
|
|
delete thread_;
|
|
thread_ = nullptr;
|
|
BM_ThreadPerformance::TearDown(st);
|
|
}
|
|
|
|
base::Thread* thread_ = nullptr;
|
|
};
|
|
|
|
BENCHMARK_F(BM_LibChromeThread, batch_enque_dequeue)(State& state) {
|
|
for (auto _ : state) {
|
|
g_counter = 0;
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
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::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
|
|
}
|
|
counter_future.wait();
|
|
}
|
|
};
|
|
|
|
BENCHMARK_F(BM_LibChromeThread, sequential_execution)(State& state) {
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
|
|
g_counter_promise = std::make_unique<std::promise<void>>();
|
|
std::future<void> counter_future = g_counter_promise->get_future();
|
|
thread_->task_runner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
|
|
counter_future.wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
int main(int argc, char** argv) {
|
|
// Disable LOG() output from libchrome
|
|
logging::LoggingSettings log_settings;
|
|
log_settings.logging_dest = logging::LoggingDestination::LOG_NONE;
|
|
CHECK(logging::InitLogging(log_settings)) << "Failed to set up logging";
|
|
::benchmark::Initialize(&argc, argv);
|
|
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
|
|
return 1;
|
|
}
|
|
::benchmark::RunSpecifiedBenchmarks();
|
|
}
|