From 3d2d323628b5804e14f5f3c636af0d025d6f10f9 Mon Sep 17 00:00:00 2001 From: zhangwenhao Date: Sun, 6 Mar 2022 15:18:01 +0800 Subject: [PATCH 1/2] fix lambda function copy captured variable many times --- libgo/common/syntax_helper.h | 13 ++++++++++--- libgo/netio/unix/hook.cpp | 12 ++++++------ libgo/routine_sync/channel.h | 1 + libgo/scheduler/scheduler.cpp | 4 ++-- libgo/scheduler/scheduler.h | 2 +- libgo/task/task.cpp | 6 ++---- libgo/task/task.h | 2 +- 7 files changed, 23 insertions(+), 17 deletions(-) diff --git a/libgo/common/syntax_helper.h b/libgo/common/syntax_helper.h index 39047629..1ca62a8d 100644 --- a/libgo/common/syntax_helper.h +++ b/libgo/common/syntax_helper.h @@ -45,12 +45,19 @@ struct __go opt_.lineno_ = lineno; } - template - ALWAYS_INLINE void operator-(Function const& f) + template ()())> + ALWAYS_INLINE void operator-(F &&f) { if (!scheduler_) scheduler_ = Processer::GetCurrentScheduler(); if (!scheduler_) scheduler_ = &Scheduler::getInstance(); - scheduler_->CreateTask(f, opt_); + scheduler_->CreateTask(std::forward(f), opt_); + } + + ALWAYS_INLINE void operator-(TaskF &f) + { + if (!scheduler_) scheduler_ = Processer::GetCurrentScheduler(); + if (!scheduler_) scheduler_ = &Scheduler::getInstance(); + scheduler_->CreateTask(std::forward(f), opt_); } ALWAYS_INLINE __go& operator-(__go_option const& opt) diff --git a/libgo/netio/unix/hook.cpp b/libgo/netio/unix/hook.cpp index 3a3cf7a5..d0ae4eff 100644 --- a/libgo/netio/unix/hook.cpp +++ b/libgo/netio/unix/hook.cpp @@ -516,8 +516,8 @@ struct hostent* gethostbyname(const char* name) int & host_errno = CLS(int); int ret = -1; - while (ret = gethostbyname_r(name, host, &buf[0], - buf.size(), &result, &host_errno) == ERANGE && + while ((ret = gethostbyname_r(name, host, &buf[0], + buf.size(), &result, &host_errno)) == ERANGE && host_errno == NETDB_INTERNAL ) { if (buf.size() < 1024) @@ -568,8 +568,8 @@ struct hostent* gethostbyname2(const char* name, int af) int & host_errno = CLS(int); int ret = -1; - while (ret = gethostbyname2_r(name, af, host, &buf[0], - buf.size(), &result, &host_errno) == ERANGE && + while ((ret = gethostbyname2_r(name, af, host, &buf[0], + buf.size(), &result, &host_errno)) == ERANGE && host_errno == NETDB_INTERNAL ) { if (buf.size() < 1024) @@ -618,8 +618,8 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) int & host_errno = CLS(int); int ret = -1; - while (ret = gethostbyaddr_r(addr, len, type, - host, &buf[0], buf.size(), &result, &host_errno) == ERANGE && + while ((ret = gethostbyaddr_r(addr, len, type, + host, &buf[0], buf.size(), &result, &host_errno)) == ERANGE && host_errno == NETDB_INTERNAL ) { if (buf.size() < 1024) diff --git a/libgo/routine_sync/channel.h b/libgo/routine_sync/channel.h index 313ab397..f12a83cd 100644 --- a/libgo/routine_sync/channel.h +++ b/libgo/routine_sync/channel.h @@ -433,6 +433,7 @@ class ChannelImpl : public ChannelImplWithSignal std::size_t cap_; }; +using std::nullptr_t; // 仅计数 template < typename QueueT diff --git a/libgo/scheduler/scheduler.cpp b/libgo/scheduler/scheduler.cpp index 1a40df39..b39a220c 100644 --- a/libgo/scheduler/scheduler.cpp +++ b/libgo/scheduler/scheduler.cpp @@ -71,9 +71,9 @@ Scheduler::~Scheduler() Stop(); } -void Scheduler::CreateTask(TaskF const& fn, TaskOpt const& opt) +void Scheduler::CreateTask(TaskF &&fn, TaskOpt const& opt) { - Task* tk = new Task(fn, opt.stack_size_ ? opt.stack_size_ : CoroutineOptions::getInstance().stack_size); + Task* tk = new Task(std::forward(fn), opt.stack_size_ ? opt.stack_size_ : CoroutineOptions::getInstance().stack_size); // printf("new tk = %p impl = %p\n", tk, tk->impl_); tk->SetDeleter(Deleter(&Scheduler::DeleteTask, this)); tk->id_ = ++GetTaskIdFactory(); diff --git a/libgo/scheduler/scheduler.h b/libgo/scheduler/scheduler.h index 576ae448..5eecadb6 100644 --- a/libgo/scheduler/scheduler.h +++ b/libgo/scheduler/scheduler.h @@ -31,7 +31,7 @@ class Scheduler static Scheduler* Create(); // 创建一个协程 - void CreateTask(TaskF const& fn, TaskOpt const& opt); + void CreateTask(TaskF &&fn, TaskOpt const& opt); // 当前是否处于协程中 bool IsCoroutine(); diff --git a/libgo/task/task.cpp b/libgo/task/task.cpp index 001ae595..e986da1c 100644 --- a/libgo/task/task.cpp +++ b/libgo/task/task.cpp @@ -83,8 +83,8 @@ void FCONTEXT_CALL Task::StaticRun(intptr_t vp) tk->Run(); } -Task::Task(TaskF const& fn, std::size_t stack_size) - : ctx_(&Task::StaticRun, (intptr_t)this, stack_size), fn_(fn) +Task::Task(TaskF fn, std::size_t stack_size) + : ctx_(&Task::StaticRun, (intptr_t)this, stack_size), fn_(std::move(fn)) { // DebugPrint(dbg_task, "task(%s) construct. this=%p", DebugInfo(), this); #if USE_ROUTINE_SYNC @@ -106,8 +106,6 @@ Task::~Task() const char* Task::DebugInfo() { - if (reinterpret_cast(this) == nullptr) return "nil"; - return TaskDebugInfo(this); } diff --git a/libgo/task/task.h b/libgo/task/task.h index 15f68cab..f516eae4 100644 --- a/libgo/task/task.h +++ b/libgo/task/task.h @@ -40,7 +40,7 @@ struct Task atomic_t suspendId_ {0}; - Task(TaskF const& fn, std::size_t stack_size); + Task(TaskF fn, std::size_t stack_size); ~Task(); ALWAYS_INLINE void SwapIn() From edb60f48491de04ab9f8cc05bba5c8f1bfd52846 Mon Sep 17 00:00:00 2001 From: zhangwenhao Date: Sun, 6 Mar 2022 15:30:05 +0800 Subject: [PATCH 2/2] add benchmark case --- test/bench/capture.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/bench/capture.cpp diff --git a/test/bench/capture.cpp b/test/bench/capture.cpp new file mode 100644 index 00000000..0bf0b3c9 --- /dev/null +++ b/test/bench/capture.cpp @@ -0,0 +1,67 @@ + +#include "coroutine.h" +#include +#include +#include + +struct C { + C() { std::cout << __PRETTY_FUNCTION__ << '\n'; } + + C(const C &) { std::cout << __PRETTY_FUNCTION__ << '\n'; } + C(const C &&) { std::cout << __PRETTY_FUNCTION__ << '\n'; } + C &operator=(const C &) { + std::cout << __PRETTY_FUNCTION__ << '\n'; + return *this; + } + C &operator=(const C &&) { + std::cout << __PRETTY_FUNCTION__ << '\n'; + return *this; + } + ~C() { std::cout << __PRETTY_FUNCTION__ << '\n'; } + int i = 100; +}; + +static void BenchCreateEmpty(benchmark::State &state) { + for (auto _ : state) { + std::vector vi(state.range(0)); + go[]{ + + }; + benchmark::DoNotOptimize(vi.size()); + } +} + +BENCHMARK(BenchCreateEmpty)->Range(1, 8192); + +static void BenchCreateCopy(benchmark::State &state) { + for (auto _ : state) { + std::vector vi(state.range(0)); + go[vi](){ + + }; + } +} + +BENCHMARK(BenchCreateCopy)->Range(1, 8192); +static void BenchCreateMove(benchmark::State &state) { + for (auto _ : state) { + std::vector vi(state.range(0)); + go[vi = std::move(vi)](){ + + }; + } +} + +BENCHMARK(BenchCreateMove)->Range(1, 8192); + +int main(int argc, char **argv) { + C c; + go [c = std::move(c)] {}; + std::thread t([] { co_sched.Start(); }); + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + co_sched.Stop(); + t.join(); + return 0; +} \ No newline at end of file