From 31ca7c9f6b4bca727d0a1d599cb7cc2c1a399433 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:46:00 +0800 Subject: [PATCH] feat add fiber switch benchmark --- CMakeLists.txt | 7 ++++ tile/fiber/detail/fiber_benchmark.cc | 45 ++++++++++++++++++++++++++ tile/fiber/detail/scheduler.cc | 16 ++++++++++ tile/fiber/detail/scheduler.h | 1 + tile/fiber/detail/scheduler_test.cc | 2 +- tile/fiber/detail/waitable.cc | 42 ++++++++++++++++++++++++ tile/fiber/detail/waitable.h | 48 ++++++++++++++++++++++++++++ 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tile/fiber/detail/fiber_benchmark.cc create mode 100644 tile/fiber/detail/waitable.cc create mode 100644 tile/fiber/detail/waitable.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c79940..3ab08e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,9 @@ option(TILE_WITH_OPENSSL "Build with openssl" OFF) option(TILE_BUILD_SHARED "Build shared library" ON) option(TILE_BUILD_STATIC "Build static library" ON) +# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "time") +# set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "time") + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(TILE_BUILD_TESTS ON) set(TILE_BUILD_BENCHMARKS ON) @@ -207,6 +210,9 @@ endif() add_library(tile OBJECT ${TILE_SRCS}) set_target_properties(tile PROPERTIES VERSION ${PROJECT_VERSION} +target_precompile_headers(tile PUBLIC inja/inja.h) +target_precompile_headers(tile PUBLIC inja/string_view.h) +target_precompile_headers(tile PUBLIC json/nlohann/json.hpp) SOVERSION "${tile_VERSION_MAJRO}") # target_sources(tile PRIVATE ${TILE_SRCS}) target_include_directories( @@ -358,6 +364,7 @@ if(TILE_BUILD_BENCHMARKS) target_sources(tile_bm_all PRIVATE ${benchmark_file}) endmacro() +tile_add_bm(fiber_detail_fiber_benchmark "tile/fiber/detail/fiber_benchmark.cc") tile_add_bm(base_casting_benchmark "tile/base/casting_benchmark.cc") tile_add_bm(base_thread_mutex_benchmark "tile/base/thread/mutex_benchmark.cc") tile_add_bm(base_encoding_benchmark "tile/base/encoding_benchmark.cc") diff --git a/tile/fiber/detail/fiber_benchmark.cc b/tile/fiber/detail/fiber_benchmark.cc new file mode 100644 index 0000000..1b053a2 --- /dev/null +++ b/tile/fiber/detail/fiber_benchmark.cc @@ -0,0 +1,45 @@ +#include "tile/base/random.h" +#include "tile/fiber/detail/fiber.h" + +#include "benchmark/benchmark.h" +namespace tile { +namespace fiber { +namespace detail { + +void Benchmark_FiberSwitch(benchmark::State &state) { + constexpr int kFiberCount = 10000; + std::unique_ptr master; + std::unique_ptr worker[kFiberCount]; + + int cnt = 0; + + master = Fiber::Create([&]() { + while (state.KeepRunning()) { + ++cnt; + worker[Random(kFiberCount - 1)]->Resume(); + } + + cnt = -1; + for (int i = 0; i != kFiberCount; ++i) { + worker[i]->Resume(); + } + }); + + for (int i = 0; i != kFiberCount; ++i) { + worker[i] = Fiber::Create([&, i]() { + while (cnt != -1) { + master->Resume(); + } + }); + } + + SetUpMasterFiber(master.get()); + SetUpCurrentFiber(nullptr); + + master->Resume(); +} + +BENCHMARK(Benchmark_FiberSwitch); +} // namespace detail +} // namespace fiber +} // namespace tile diff --git a/tile/fiber/detail/scheduler.cc b/tile/fiber/detail/scheduler.cc index b1a8dac..7d4c719 100644 --- a/tile/fiber/detail/scheduler.cc +++ b/tile/fiber/detail/scheduler.cc @@ -20,9 +20,25 @@ void Scheduler::SwitchTo(Fiber *self, Fiber *to) { void Scheduler::Yield(Fiber *self) { auto master = GetMasterFiber(); + TILE_CHECK(self, "self fiber is nullptr."); + TILE_CHECK(master, "Master fiber is not set."); master->state_ = FiberState::Runnable; + self->state_ = FiberState::Running; SwitchTo(self, master); } + +void Scheduler::Halt(Fiber *self) { + TILE_CHECK_EQ(self, GetCurrentFiber(), "Fiber is not current fiber."); + TILE_CHECK(self->state() == FiberState::Running, "Fiber is not running."); + + auto master = GetMasterFiber(); + self->state_ = FiberState::Waiting; + + master->Resume(); + + TILE_CHECK_EQ(self, GetCurrentFiber()); +} + } // namespace detail } // namespace fiber } // namespace tile diff --git a/tile/fiber/detail/scheduler.h b/tile/fiber/detail/scheduler.h index d889ddb..594c695 100644 --- a/tile/fiber/detail/scheduler.h +++ b/tile/fiber/detail/scheduler.h @@ -15,6 +15,7 @@ public: void SwitchTo(Fiber *self, Fiber *to); void Yield(Fiber *self); + void Halt(Fiber *self); }; } // namespace detail } // namespace fiber diff --git a/tile/fiber/detail/scheduler_test.cc b/tile/fiber/detail/scheduler_test.cc index ef128d5..84a0a1f 100644 --- a/tile/fiber/detail/scheduler_test.cc +++ b/tile/fiber/detail/scheduler_test.cc @@ -11,7 +11,7 @@ namespace detail { TEST(Fiber, Resume) { constexpr int kFiberCount = 1000; - constexpr int kSwitchCount = 100000; + constexpr int kSwitchCount = 1000 * 1000; std::unique_ptr master; std::unique_ptr worker[kFiberCount]; diff --git a/tile/fiber/detail/waitable.cc b/tile/fiber/detail/waitable.cc new file mode 100644 index 0000000..eba155e --- /dev/null +++ b/tile/fiber/detail/waitable.cc @@ -0,0 +1,42 @@ +#include "tile/fiber/detail/waitable.h" +#include "tile/base/thread/scoped_lock.h" + +namespace tile { +namespace fiber { +namespace detail { +WaitList::WaitList() {} +WaitList::~WaitList() {} + +bool WaitList::AddWaiter(WaitListNode *node) { + ScopedLock _(lock_); + TILE_CHECK(node->waiter); + + waiters_.push_back(node); + return true; +} + +Fiber *WaitList::WakeOne() { + ScopedLock _(lock_); + while (true) { + if (waiters_.empty()) { + return nullptr; + } + + WaitListNode *waiter = waiters_.front(); + waiters_.pop_front(); + if (!waiter) { + return nullptr; + } + + if (waiter->satisfied.exchange(true, std::memory_order_relaxed)) { + continue; + ; + } + + return waiter->waiter; + } +} + +} // namespace detail +} // namespace fiber +} // namespace tile diff --git a/tile/fiber/detail/waitable.h b/tile/fiber/detail/waitable.h new file mode 100644 index 0000000..2bb04cd --- /dev/null +++ b/tile/fiber/detail/waitable.h @@ -0,0 +1,48 @@ +#ifndef TILE_FIBER_DETAIL_WAITABLE_H +#define TILE_FIBER_DETAIL_WAITABLE_H + +#pragma once + +#include "tile/base/internal/singly_linked_list.h" +#include "tile/base/thread/spinlock.h" + +#include + +namespace tile { +namespace fiber { +namespace detail { + +class Fiber; +class Scheduler; + +struct WaitListNode { + Fiber *waiter = nullptr; + tile::internal::SinglyLinkedListEntry chain; + std::atomic satisfied{false}; +}; + +class WaitList { +public: + WaitList(); + ~WaitList(); + + bool AddWaiter(WaitListNode *node); + // Remove the waiter from the list. + // return true if the waiter is removed, otherwise return nullptr. + Fiber *WakeOne(); + + WaitList(const WaitList &) = delete; + WaitList &operator=(const WaitList &) = delete; + +private: + Spinlock lock_; + std::list waiters_; + // tile::internal::SinglyLinkedList + // waiters_; +}; + +} // namespace detail +} // namespace fiber +} // namespace tile + +#endif // TILE_FIBER_DETAIL_WAITABLE_H