feat/support_fiber #2
@ -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")
|
||||
|
45
tile/fiber/detail/fiber_benchmark.cc
Normal file
45
tile/fiber/detail/fiber_benchmark.cc
Normal file
@ -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<Fiber> master;
|
||||
std::unique_ptr<Fiber> 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
|
@ -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
|
||||
|
@ -15,6 +15,7 @@ public:
|
||||
|
||||
void SwitchTo(Fiber *self, Fiber *to);
|
||||
void Yield(Fiber *self);
|
||||
void Halt(Fiber *self);
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace fiber
|
||||
|
@ -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<Fiber> master;
|
||||
std::unique_ptr<Fiber> worker[kFiberCount];
|
||||
|
42
tile/fiber/detail/waitable.cc
Normal file
42
tile/fiber/detail/waitable.cc
Normal file
@ -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
|
48
tile/fiber/detail/waitable.h
Normal file
48
tile/fiber/detail/waitable.h
Normal file
@ -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 <list>
|
||||
|
||||
namespace tile {
|
||||
namespace fiber {
|
||||
namespace detail {
|
||||
|
||||
class Fiber;
|
||||
class Scheduler;
|
||||
|
||||
struct WaitListNode {
|
||||
Fiber *waiter = nullptr;
|
||||
tile::internal::SinglyLinkedListEntry chain;
|
||||
std::atomic<bool> 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<WaitListNode *> waiters_;
|
||||
// tile::internal::SinglyLinkedList<WaitListNode, &WaitListNode::chain>
|
||||
// waiters_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace fiber
|
||||
} // namespace tile
|
||||
|
||||
#endif // TILE_FIBER_DETAIL_WAITABLE_H
|
Loading…
x
Reference in New Issue
Block a user