From 8c819fb4d18ab68415021c34599784e1463e2333 Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Fri, 28 Sep 2018 23:11:16 +0200 Subject: [PATCH 1/2] Initial commit of contrib separation & Trampoline for discussion --- CMakeLists.txt | 1 + include/ftl/atomic_counter.h | 17 +++++ include/ftl/contrib/trampoline.h | 113 +++++++++++++++++++++++++++++++ source/CMakeLists.txt | 32 +++++++++ source/atomic_counter.cpp | 1 - source/contrib.cpp | 12 ++++ tests/CMakeLists.txt | 22 ++++++ tests/contrib/trampoline.cpp | 89 ++++++++++++++++++++++++ 8 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 include/ftl/contrib/trampoline.h create mode 100644 source/contrib.cpp create mode 100644 tests/contrib/trampoline.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 74adfd91..349fb1b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ option(FTL_BUILD_TESTS "Build FiberTaskingLib tests" ON) option(FTL_BUILD_BENCHMARKS "Build FiberTaskingLib benchmarks" ON) option(FTL_VALGRIND "Link and test with Valgrind" OFF) option(FTL_FIBER_STACK_GUARD_PAGES "Add guard pages around the fiber stacks" OFF) +option(FTL_BUILD_CONTRIB_TESTS "Should contrib tests be built? (requires C++17)" OFF) # Include Valgrind if (FTL_VALGRIND) diff --git a/include/ftl/atomic_counter.h b/include/ftl/atomic_counter.h index c14799d9..68f5be47 100644 --- a/include/ftl/atomic_counter.h +++ b/include/ftl/atomic_counter.h @@ -35,7 +35,14 @@ namespace ftl { class TaskScheduler; +struct Task; +#ifdef FTL_CONTRIB_CHANGES +struct BoundTrampolineBase { + virtual ~BoundTrampolineBase() = default; + virtual operator ftl::Task() & = 0; +}; +#endif /** * AtomicCounter is a wrapper over a C++11 atomic_uint * In FiberTaskingLib, AtomicCounter is used to create dependencies between Tasks, and @@ -97,6 +104,16 @@ class AtomicCounter { */ friend class TaskScheduler; + /**/ + +#ifdef FTL_CONTRIB_CHANGES +private: + std::mutex m_boundTrampolinesLock; + std::vector> m_boundTrampolines; +public: + void addTask(std::unique_ptr bound_trampoline); +#endif + public: /** * A wrapper over std::atomic_uint::load() diff --git a/include/ftl/contrib/trampoline.h b/include/ftl/contrib/trampoline.h new file mode 100644 index 00000000..71577b5c --- /dev/null +++ b/include/ftl/contrib/trampoline.h @@ -0,0 +1,113 @@ +/** + * FiberTaskingLib - A tasking library that uses fibers for efficient task switching + * + * This library was created as a proof of concept of the ideas presented by + * Christian Gyrling in his 2015 GDC Talk 'Parallelizing the Naughty Dog Engine Using Fibers' + * + * http://gdcvault.com/play/1022186/Parallelizing-the-Naughty-Dog-Engine + * + * FiberTaskingLib is the legal property of Adrian Astley + * Copyright Adrian Astley 2015 - 2018 + * + * 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. + */ + +#pragma once + +#include "../atomic_counter.h" +#include +#include +#include + + +namespace ftl { + struct TrampolineBase { + TrampolineBase(void* arg = nullptr) : arg(arg) {} + void* arg; + + virtual ~TrampolineBase() = default; + }; + + template struct BoundTrampoline; + + template + struct Trampoline : TrampolineBase { + Trampoline(F&& f, void* userdata = nullptr) : TrampolineBase(userdata), handler(std::move(f)) {} + F handler; + + template + auto bind(Args&&... args) { + return std::unique_ptr>(new BoundTrampoline(*this, std::forward_as_tuple(args...))); + } + + virtual ~Trampoline() = default; + }; + + namespace detail { + template + struct return_value_t { + typename T::type return_value; + operator typename T::type() { return return_value; } + + }; + + template + using return_type_of_lambda = typename std::invoke_result; + + template + struct has_type { + private: + template + static typename T1::type test(int); + template + static void test(...); + public: + enum { value = !std::is_void(0))>::value }; + }; + + template + constexpr bool is_lambda_void_return = !has_type>::value; + + struct empty {}; + } + + template + struct BoundTrampoline : BoundTrampolineBase, std::conditional_t < detail::is_lambda_void_return, detail::empty, detail::return_value_t> > { + Trampoline tramp; + std::tuple args; + static constexpr bool is_void_return = detail::is_lambda_void_return; + + BoundTrampoline(Trampoline func, std::tuple&& args) : tramp(func), args(std::move(args)) {} + + // call fiber + auto call() { + return std::apply(tramp.handler, args); + } + + // call task + static void gencall(ftl::TaskScheduler* ts, void * arg) { + auto& t = *static_cast*>(arg); + if constexpr (!is_void_return) + t.return_value = t.call(); + else + t.call(); + } + + virtual operator ftl::Task() & override { + return ftl::Task{ &gencall, static_cast(this) }; + } + + virtual ~BoundTrampoline() = default; + }; + +} // End of namespace ftl diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 0a90ea79..15f35261 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -64,6 +64,11 @@ if ((FTL_ARCH STREQUAL "x86_64") OR (FTL_ARCH STREQUAL "i386")) add_definitions(-DFTL_STRONG_MEMORY_MODEL=1) endif() +if (FTL_CONTRIB_CHANGES) + add_definitions(-DFTL_CONTRIB_CHANGES=1) +endif() + + SetSourceGroup(NAME Core PREFIX FTL @@ -85,15 +90,42 @@ SetSourceGroup(NAME Util ../include/ftl/ftl_valgrind.h ) +SetSourceGroup(NAME Contrib + PREFIX FTL + SOURCE_FILES ../include/ftl/contrib/trampoline.h + contrib.cpp +) + # Link all the sources into one set(FIBER_TASKING_LIB_SRC ${FTL_CORE} ${FTL_UTIL} ) +set(FIBER_TASKING_LIB_CONTRIB_SRC + ${FTL_CONTRIB} +) + add_library(ftl STATIC ${FIBER_TASKING_LIB_SRC}) target_link_libraries(ftl boost_context ${CMAKE_THREAD_LIBS_INIT}) target_include_directories(ftl PUBLIC ../include) +# Contrib static library + +add_library(ftl-contrib STATIC ${FIBER_TASKING_LIB_SRC} ${FIBER_TASKING_LIB_CONTRIB_SRC}) +target_link_libraries(ftl-contrib boost_context ${CMAKE_THREAD_LIBS_INIT}) +target_include_directories(ftl-contrib PUBLIC ../include) +target_compile_definitions(ftl-contrib PUBLIC -DFTL_CONTRIB_CHANGES=1) +set_target_properties(ftl-contrib PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED YES +) + +# before 3.10, CMake does not understand MSVC version flags +if(MSVC AND ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.10) + target_compile_options(ftl-contrib PUBLIC "/std:c++17") +endif() + # Remove the prefix set_target_properties(ftl PROPERTIES PREFIX "") +set_target_properties(ftl-contrib PROPERTIES PREFIX "") \ No newline at end of file diff --git a/source/atomic_counter.cpp b/source/atomic_counter.cpp index 747449eb..003aeb7b 100644 --- a/source/atomic_counter.cpp +++ b/source/atomic_counter.cpp @@ -152,5 +152,4 @@ void AtomicCounter::CheckWaitingFibers(uint value) { } } - } // End of namespace ftl diff --git a/source/contrib.cpp b/source/contrib.cpp new file mode 100644 index 00000000..6ebaddc1 --- /dev/null +++ b/source/contrib.cpp @@ -0,0 +1,12 @@ +#include "ftl/atomic_counter.h" +#include "ftl/task_scheduler.h" + +namespace ftl { + + void AtomicCounter::addTask(std::unique_ptr bound_trampoline) { + std::lock_guard lock(m_boundTrampolinesLock); + m_boundTrampolines.emplace_back(std::move(bound_trampoline)); + m_taskScheduler->AddTask(*m_boundTrampolines.back(), this); + } + +} //namespace ftl \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c1a409a2..ff95457e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -56,3 +56,25 @@ add_executable(ftl-test ${FIBER_TASKING_LIB_TESTS_SRC}) target_link_libraries(ftl-test gtest gtest_main ftl) GTEST_ADD_TESTS(ftl-test "" ${FIBER_TASKING_LIB_TESTS_SRC}) + +if(FTL_BUILD_CONTRIB_TESTS) + SetSourceGroup(NAME "Trampoline" + PREFIX FTL_TEST_CONTRIB + SOURCE_FILES contrib/trampoline.cpp + ) + + # Link all the sources into one + set(FIBER_TASKING_LIB_TESTS_CONTRIB_SRC + ${FTL_TEST_CONTRIB_TRAMPOLINE} + ) + + add_executable(ftl-contrib-test ${FIBER_TASKING_LIB_TESTS_CONTRIB_SRC}) + target_link_libraries(ftl-contrib-test gtest gtest_main ftl-contrib) + + GTEST_ADD_TESTS(ftl-contrib-test "" ${FIBER_TASKING_LIB_TESTS_CONTRIB_SRC}) + + set_target_properties(ftl-contrib-test PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED YES + ) +endif() \ No newline at end of file diff --git a/tests/contrib/trampoline.cpp b/tests/contrib/trampoline.cpp new file mode 100644 index 00000000..44359fd0 --- /dev/null +++ b/tests/contrib/trampoline.cpp @@ -0,0 +1,89 @@ +/** + * FiberTaskingLib - A tasking library that uses fibers for efficient task switching + * + * This library was created as a proof of concept of the ideas presented by + * Christian Gyrling in his 2015 GDC Talk 'Parallelizing the Naughty Dog Engine Using Fibers' + * + * http://gdcvault.com/play/1022186/Parallelizing-the-Naughty-Dog-Engine + * + * FiberTaskingLib is the legal property of Adrian Astley + * Copyright Adrian Astley 2015 - 2018 + * + * 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 "ftl/atomic_counter.h" +#include "ftl/task_scheduler.h" + +#include + +#include "ftl/contrib/trampoline.h" + +struct Foo {}; + +/* + Showcases Trampoline functionality + + Requires C++17 + + Features: + - automatic type safe interface and lambdas-as-tasks + - error if mismatched type/count of arguments (if a bit cryptic) + - no need to repeat types + - supports returning values from tasks + + Two usages showcased here: one with automatic memory management, and one with manual-ish memory management + + Downsides: + - C++17 + - version A requires intrusive changes to AtomicCounter + + Missing for A: + - Multiple task addition support + - Task return value retrieval + + Glossary: + - Trampoline: wrapper around a lambda / function + - BoundTrampoline: Trampoline + arguments + possible return value +*/ + +void TrampolineMainTask(ftl::TaskScheduler *taskScheduler, void *arg) { + Foo f; + int a = 3, b = 4, d = 6; + + ftl::AtomicCounter counter(taskScheduler); + // Version A + // Trampoline lifetime is automatically managed by the counter + counter.addTask( + ftl::Trampoline([](int& a, const int& b, const Foo& f, const int d) { a++; }) + .bind(a, b, f, d) + ); + + taskScheduler->WaitForCounter(&counter, 0); + // values are correctly captured and const is respected + std::cout << a << '\n'; + + // Version B + // Trampoline lifetime is managed by the user + auto bt2 = ftl::Trampoline([](int& a, const int& b, const Foo& f, const int d) {return a+1; }).bind(a, b, f, d); + // automatic conversion to ftl::Task + taskScheduler->AddTask(*bt2, &counter); + taskScheduler->WaitForCounter(&counter, 0); + // showcases returning values + std::cout << *bt2 << '\n'; +} + +TEST(ContribTests, Trampoline) { + ftl::TaskScheduler taskScheduler; + taskScheduler.Run(400, TrampolineMainTask); +} From 68557145e78ebe3eec1fb75eb73ea5f30b742da4 Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Sat, 29 Sep 2018 11:15:04 +0200 Subject: [PATCH 2/2] Remove the contrib static library; Replace C++17 features with C+11 machinery; Remove value return support; Remove machinery from AtomicCounter; Tie BoundTrampoline lifetime to Task duration --- CMakeLists.txt | 2 +- include/ftl/atomic_counter.h | 17 ----- include/ftl/contrib/trampoline.h | 117 +++++++++++++++++-------------- source/CMakeLists.txt | 27 +------ source/contrib.cpp | 12 ---- tests/CMakeLists.txt | 22 +++--- tests/contrib/trampoline.cpp | 32 +-------- 7 files changed, 79 insertions(+), 150 deletions(-) delete mode 100644 source/contrib.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 349fb1b6..9874a6c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,10 +27,10 @@ project(FiberTaskingLib) # Options option(FTL_BUILD_TESTS "Build FiberTaskingLib tests" ON) +option(FTL_BUILD_CONTRIB_TESTS "Should FiberTaskingLib contrib tests be built?" ON) option(FTL_BUILD_BENCHMARKS "Build FiberTaskingLib benchmarks" ON) option(FTL_VALGRIND "Link and test with Valgrind" OFF) option(FTL_FIBER_STACK_GUARD_PAGES "Add guard pages around the fiber stacks" OFF) -option(FTL_BUILD_CONTRIB_TESTS "Should contrib tests be built? (requires C++17)" OFF) # Include Valgrind if (FTL_VALGRIND) diff --git a/include/ftl/atomic_counter.h b/include/ftl/atomic_counter.h index 68f5be47..c14799d9 100644 --- a/include/ftl/atomic_counter.h +++ b/include/ftl/atomic_counter.h @@ -35,14 +35,7 @@ namespace ftl { class TaskScheduler; -struct Task; -#ifdef FTL_CONTRIB_CHANGES -struct BoundTrampolineBase { - virtual ~BoundTrampolineBase() = default; - virtual operator ftl::Task() & = 0; -}; -#endif /** * AtomicCounter is a wrapper over a C++11 atomic_uint * In FiberTaskingLib, AtomicCounter is used to create dependencies between Tasks, and @@ -104,16 +97,6 @@ class AtomicCounter { */ friend class TaskScheduler; - /**/ - -#ifdef FTL_CONTRIB_CHANGES -private: - std::mutex m_boundTrampolinesLock; - std::vector> m_boundTrampolines; -public: - void addTask(std::unique_ptr bound_trampoline); -#endif - public: /** * A wrapper over std::atomic_uint::load() diff --git a/include/ftl/contrib/trampoline.h b/include/ftl/contrib/trampoline.h index 71577b5c..df10f22b 100644 --- a/include/ftl/contrib/trampoline.h +++ b/include/ftl/contrib/trampoline.h @@ -24,90 +24,105 @@ #pragma once -#include "../atomic_counter.h" +#include "ftl/task.h" + #include #include -#include - +#include namespace ftl { - struct TrampolineBase { - TrampolineBase(void* arg = nullptr) : arg(arg) {} - void* arg; - - virtual ~TrampolineBase() = default; - }; + class TaskScheduler; template struct BoundTrampoline; template - struct Trampoline : TrampolineBase { - Trampoline(F&& f, void* userdata = nullptr) : TrampolineBase(userdata), handler(std::move(f)) {} + struct Trampoline { + Trampoline(F&& f) : handler(std::move(f)) {} F handler; template - auto bind(Args&&... args) { - return std::unique_ptr>(new BoundTrampoline(*this, std::forward_as_tuple(args...))); + BoundTrampoline* bind(Args&&... args) { + return new BoundTrampoline(*this, std::forward_as_tuple(args...)); } - - virtual ~Trampoline() = default; }; - namespace detail { - template - struct return_value_t { - typename T::type return_value; - operator typename T::type() { return return_value; } + template + Trampoline make_trampoline(F&& f) { + Trampoline t(std::forward(f)); + return t; + } + /* + C++11 machinery to power std::apply + */ + namespace detail { + // based on http://stackoverflow.com/a/17426611/410767 by Xeo + template + struct index_sequence { + using type = index_sequence; + using value_type = size_t; + static constexpr std::size_t size() noexcept { return sizeof...(Ints); } }; - template - using return_type_of_lambda = typename std::invoke_result; - - template - struct has_type { - private: - template - static typename T1::type test(int); - template - static void test(...); - public: - enum { value = !std::is_void(0))>::value }; - }; + // -------------------------------------------------------------- - template - constexpr bool is_lambda_void_return = !has_type>::value; + template + struct _merge_and_renumber; - struct empty {}; - } + template + struct _merge_and_renumber, index_sequence> + : index_sequence {}; + + // -------------------------------------------------------------- + + template + struct make_index_sequence + : _merge_and_renumber::type, + typename make_index_sequence::type> {}; + + template<> struct make_index_sequence<0> : index_sequence<> {}; + template<> struct make_index_sequence<1> : index_sequence<0> {}; + + + template + auto invoke(F f, Args&&... args) -> decltype(std::ref(f)(std::forward(args)...)) { + return std::ref(f)(std::forward(args)...); + } + + template + auto apply_impl(F&& f, Tuple&& t, detail::index_sequence) -> decltype(std::ref(f)(std::get(std::forward(t))...)) { + return invoke(std::forward(f), std::get(std::forward(t))...); + } + + } // namespace detail template - struct BoundTrampoline : BoundTrampolineBase, std::conditional_t < detail::is_lambda_void_return, detail::empty, detail::return_value_t> > { + struct BoundTrampoline { Trampoline tramp; std::tuple args; - static constexpr bool is_void_return = detail::is_lambda_void_return; + friend struct Trampoline; + private: BoundTrampoline(Trampoline func, std::tuple&& args) : tramp(func), args(std::move(args)) {} + public: + BoundTrampoline(const BoundTrampoline&) = delete; + BoundTrampoline& operator=(const BoundTrampoline&) = delete; - // call fiber - auto call() { - return std::apply(tramp.handler, args); - } + BoundTrampoline(BoundTrampoline&&) = default; + BoundTrampoline& operator=(BoundTrampoline&&) = default; // call task static void gencall(ftl::TaskScheduler* ts, void * arg) { - auto& t = *static_cast*>(arg); - if constexpr (!is_void_return) - t.return_value = t.call(); - else - t.call(); + auto t = static_cast*>(arg); + detail::apply_impl(t->tramp.handler, t->args,detail::make_index_sequence::type>::value>{}); + delete t; } - virtual operator ftl::Task() & override { - return ftl::Task{ &gencall, static_cast(this) }; + operator Task() { + return Task{ &gencall, static_cast(this) }; } - virtual ~BoundTrampoline() = default; + ~BoundTrampoline() = default; }; } // End of namespace ftl diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 15f35261..3486d5e8 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -64,11 +64,6 @@ if ((FTL_ARCH STREQUAL "x86_64") OR (FTL_ARCH STREQUAL "i386")) add_definitions(-DFTL_STRONG_MEMORY_MODEL=1) endif() -if (FTL_CONTRIB_CHANGES) - add_definitions(-DFTL_CONTRIB_CHANGES=1) -endif() - - SetSourceGroup(NAME Core PREFIX FTL @@ -93,7 +88,6 @@ SetSourceGroup(NAME Util SetSourceGroup(NAME Contrib PREFIX FTL SOURCE_FILES ../include/ftl/contrib/trampoline.h - contrib.cpp ) # Link all the sources into one @@ -106,26 +100,9 @@ set(FIBER_TASKING_LIB_CONTRIB_SRC ${FTL_CONTRIB} ) -add_library(ftl STATIC ${FIBER_TASKING_LIB_SRC}) +add_library(ftl STATIC ${FIBER_TASKING_LIB_SRC} ${FIBER_TASKING_LIB_CONTRIB_SRC}) target_link_libraries(ftl boost_context ${CMAKE_THREAD_LIBS_INIT}) target_include_directories(ftl PUBLIC ../include) -# Contrib static library - -add_library(ftl-contrib STATIC ${FIBER_TASKING_LIB_SRC} ${FIBER_TASKING_LIB_CONTRIB_SRC}) -target_link_libraries(ftl-contrib boost_context ${CMAKE_THREAD_LIBS_INIT}) -target_include_directories(ftl-contrib PUBLIC ../include) -target_compile_definitions(ftl-contrib PUBLIC -DFTL_CONTRIB_CHANGES=1) -set_target_properties(ftl-contrib PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED YES -) - -# before 3.10, CMake does not understand MSVC version flags -if(MSVC AND ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.10) - target_compile_options(ftl-contrib PUBLIC "/std:c++17") -endif() - # Remove the prefix -set_target_properties(ftl PROPERTIES PREFIX "") -set_target_properties(ftl-contrib PROPERTIES PREFIX "") \ No newline at end of file +set_target_properties(ftl PROPERTIES PREFIX "") \ No newline at end of file diff --git a/source/contrib.cpp b/source/contrib.cpp deleted file mode 100644 index 6ebaddc1..00000000 --- a/source/contrib.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "ftl/atomic_counter.h" -#include "ftl/task_scheduler.h" - -namespace ftl { - - void AtomicCounter::addTask(std::unique_ptr bound_trampoline) { - std::lock_guard lock(m_boundTrampolinesLock); - m_boundTrampolines.emplace_back(std::move(bound_trampoline)); - m_taskScheduler->AddTask(*m_boundTrampolines.back(), this); - } - -} //namespace ftl \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ff95457e..9d47d297 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -51,12 +51,6 @@ set(FIBER_TASKING_LIB_TESTS_SRC ${FTL_TEST_TRIANGLE_NUMBER} ) - -add_executable(ftl-test ${FIBER_TASKING_LIB_TESTS_SRC}) -target_link_libraries(ftl-test gtest gtest_main ftl) - -GTEST_ADD_TESTS(ftl-test "" ${FIBER_TASKING_LIB_TESTS_SRC}) - if(FTL_BUILD_CONTRIB_TESTS) SetSourceGroup(NAME "Trampoline" PREFIX FTL_TEST_CONTRIB @@ -68,13 +62,13 @@ if(FTL_BUILD_CONTRIB_TESTS) ${FTL_TEST_CONTRIB_TRAMPOLINE} ) - add_executable(ftl-contrib-test ${FIBER_TASKING_LIB_TESTS_CONTRIB_SRC}) - target_link_libraries(ftl-contrib-test gtest gtest_main ftl-contrib) + set(FIBER_TASKING_LIB_TESTS_SRC + ${FIBER_TASKING_LIB_TESTS_SRC} + ${FIBER_TASKING_LIB_TESTS_CONTRIB_SRC} + ) +endif() - GTEST_ADD_TESTS(ftl-contrib-test "" ${FIBER_TASKING_LIB_TESTS_CONTRIB_SRC}) +add_executable(ftl-test ${FIBER_TASKING_LIB_TESTS_SRC}) +target_link_libraries(ftl-test gtest gtest_main ftl) - set_target_properties(ftl-contrib-test PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED YES - ) -endif() \ No newline at end of file +GTEST_ADD_TESTS(ftl-test "" ${FIBER_TASKING_LIB_TESTS_SRC}) \ No newline at end of file diff --git a/tests/contrib/trampoline.cpp b/tests/contrib/trampoline.cpp index 44359fd0..950e29c3 100644 --- a/tests/contrib/trampoline.cpp +++ b/tests/contrib/trampoline.cpp @@ -34,27 +34,14 @@ struct Foo {}; /* Showcases Trampoline functionality - Requires C++17 - Features: - automatic type safe interface and lambdas-as-tasks - error if mismatched type/count of arguments (if a bit cryptic) - no need to repeat types - - supports returning values from tasks - - Two usages showcased here: one with automatic memory management, and one with manual-ish memory management - - Downsides: - - C++17 - - version A requires intrusive changes to AtomicCounter - - Missing for A: - - Multiple task addition support - - Task return value retrieval Glossary: - Trampoline: wrapper around a lambda / function - - BoundTrampoline: Trampoline + arguments + possible return value + - BoundTrampoline: Trampoline + arguments */ void TrampolineMainTask(ftl::TaskScheduler *taskScheduler, void *arg) { @@ -62,25 +49,10 @@ void TrampolineMainTask(ftl::TaskScheduler *taskScheduler, void *arg) { int a = 3, b = 4, d = 6; ftl::AtomicCounter counter(taskScheduler); - // Version A - // Trampoline lifetime is automatically managed by the counter - counter.addTask( - ftl::Trampoline([](int& a, const int& b, const Foo& f, const int d) { a++; }) - .bind(a, b, f, d) - ); - + taskScheduler->AddTask(*ftl::make_trampoline([](int& a, const int& b, const Foo& f, const int d) { a++; }).bind(a, b, f, d), &counter); taskScheduler->WaitForCounter(&counter, 0); // values are correctly captured and const is respected std::cout << a << '\n'; - - // Version B - // Trampoline lifetime is managed by the user - auto bt2 = ftl::Trampoline([](int& a, const int& b, const Foo& f, const int d) {return a+1; }).bind(a, b, f, d); - // automatic conversion to ftl::Task - taskScheduler->AddTask(*bt2, &counter); - taskScheduler->WaitForCounter(&counter, 0); - // showcases returning values - std::cout << *bt2 << '\n'; } TEST(ContribTests, Trampoline) {