From 92da43ff23c2f99b9875f98db4903faea3601802 Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Tue, 2 Apr 2019 11:10:22 +0200 Subject: [PATCH] Rename tbb_task to fork_join_task. --- app/playground/main.cpp | 4 ++-- lib/pls/CMakeLists.txt | 5 +++-- lib/pls/include/pls/algorithms/invoke_parallel.h | 16 ++++++++++++++++ lib/pls/include/pls/internal/scheduling/fork_join_task.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pls/include/pls/internal/scheduling/tbb_task.h | 102 ------------------------------------------------------------------------------------------------------ lib/pls/include/pls/pls.h | 6 +++--- lib/pls/src/algorithms/invoke_parallel.cpp | 1 + lib/pls/src/internal/scheduling/fork_join_task.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pls/src/internal/scheduling/tbb_task.cpp | 96 ------------------------------------------------------------------------------------------------ test/scheduling_tests.cpp | 14 +++++++------- 10 files changed, 230 insertions(+), 212 deletions(-) create mode 100644 lib/pls/include/pls/algorithms/invoke_parallel.h create mode 100644 lib/pls/include/pls/internal/scheduling/fork_join_task.h delete mode 100644 lib/pls/include/pls/internal/scheduling/tbb_task.h create mode 100644 lib/pls/src/algorithms/invoke_parallel.cpp create mode 100644 lib/pls/src/internal/scheduling/fork_join_task.cpp delete mode 100644 lib/pls/src/internal/scheduling/tbb_task.cpp diff --git a/app/playground/main.cpp b/app/playground/main.cpp index 5d417c7..4d585cd 100644 --- a/app/playground/main.cpp +++ b/app/playground/main.cpp @@ -12,7 +12,7 @@ using namespace pls; // Example for static memory allocation (no malloc or free required) static static_scheduler_memory<8, 2 << 12> my_scheduler_memory; -class fib: public tbb_sub_task { +class fib: public fork_join_sub_task { static constexpr int CUTOFF = 20; int num_; @@ -64,7 +64,7 @@ int main() { int result; fib fib_sub_task{45, &result}; - tbb_task tbb_task{&fib_sub_task, task_id{1}}; + fork_join_task tbb_task{&fib_sub_task, task_id{1}}; scheduler::execute_task(tbb_task); std::cout << "Result: " << result << std::endl; diff --git a/lib/pls/CMakeLists.txt b/lib/pls/CMakeLists.txt index bad2b80..ff6fe7e 100644 --- a/lib/pls/CMakeLists.txt +++ b/lib/pls/CMakeLists.txt @@ -12,8 +12,9 @@ add_library(pls STATIC src/internal/base/aligned_stack.cpp include/pls/internal/base/aligned_stack.h include/pls/internal/base/system_details.h src/internal/scheduling/run_on_n_threads_task.cpp include/pls/internal/scheduling/run_on_n_threads_task.h - src/internal/scheduling/tbb_task.cpp include/pls/internal/scheduling/tbb_task.h - src/internal/base/deque.cpp include/pls/internal/base/deque.h) + src/internal/scheduling/fork_join_task.cpp include/pls/internal/scheduling/fork_join_task.h + src/internal/base/deque.cpp include/pls/internal/base/deque.h + src/algorithms/invoke_parallel.cpp include/pls/algorithms/invoke_parallel.h) # Add everything in `./include` to be in the include path of this project target_include_directories(pls diff --git a/lib/pls/include/pls/algorithms/invoke_parallel.h b/lib/pls/include/pls/algorithms/invoke_parallel.h new file mode 100644 index 0000000..3809034 --- /dev/null +++ b/lib/pls/include/pls/algorithms/invoke_parallel.h @@ -0,0 +1,16 @@ + +#ifndef PLS_PARALLEL_INVOKE_H +#define PLS_PARALLEL_INVOKE_H + +namespace pls { + namespace algorithm { +// template +// void invoke_parallel(Function1 function1, Function2 function2) { +// if (already_this_invoke_parallel_instance) { +// +// } +// } + } +} + +#endif //PLS_PARALLEL_INVOKE_H diff --git a/lib/pls/include/pls/internal/scheduling/fork_join_task.h b/lib/pls/include/pls/internal/scheduling/fork_join_task.h new file mode 100644 index 0000000..eb08fcd --- /dev/null +++ b/lib/pls/include/pls/internal/scheduling/fork_join_task.h @@ -0,0 +1,102 @@ + +#ifndef PLS_TBB_LIKE_TASK_H +#define PLS_TBB_LIKE_TASK_H + +#include "pls/internal/base/aligned_stack.h" +#include "pls/internal/base/deque.h" + +#include "abstract_task.h" +#include "thread_state.h" + +namespace pls { + namespace internal { + namespace scheduling { + class fork_join_task; + class fork_join_sub_task: public base::deque_item { + friend class fork_join_task; + + // Coordinate finishing of sub_tasks + std::atomic_uint32_t ref_count_; + fork_join_sub_task* parent_; + + // Access to TBB scheduling environment + fork_join_task* tbb_task_; + + // Stack Management (reset stack pointer after wait_for_all() calls) + base::aligned_stack::state stack_state_; + protected: + explicit fork_join_sub_task(); + fork_join_sub_task(const fork_join_sub_task& other); + + virtual void execute_internal() = 0; + // SubClass Implementations: + // Do Work + // |-- Spawn Sub Task (new subtask; spawn(subtask);) + // |-- Spawn Sub task + // Do Work + // |-- Wait For All + // Do Work + // |-- Spawn Sub Task + + template + void spawn_child(const T& sub_task); + void wait_for_all(); + private: + void spawn_child_internal(fork_join_sub_task* sub_task); + void execute(); + + public: + virtual void test() { + std::cout << "Test" << std::endl; + } + }; + + class fork_join_task: public abstract_task { + friend class fork_join_sub_task; + + fork_join_sub_task* root_task_; + base::aligned_stack* my_stack_; + + // Double-Ended Queue management + base::deque deque_; + + // Steal Management + fork_join_sub_task* last_stolen_; + + fork_join_sub_task* get_local_sub_task(); + fork_join_sub_task* get_stolen_sub_task(); + + bool internal_stealing(abstract_task* other_task) override; + bool split_task(base::spin_lock* /*lock*/) override; + + public: + explicit fork_join_task(fork_join_sub_task* root_task, const abstract_task::id& id): + abstract_task{0, id}, + root_task_{root_task}, + my_stack_{nullptr}, + deque_{}, + last_stolen_{nullptr} {}; + + void execute() override { + // Bind this instance to our OS thread + my_stack_ = base::this_thread::state()->task_stack_; + root_task_->tbb_task_ = this; + root_task_->stack_state_ = my_stack_->save_state(); + + // Execute it on our OS thread until its finished + root_task_->execute(); + } + }; + + template + void fork_join_sub_task::spawn_child(const T& task) { + static_assert(std::is_base_of::value, "Only pass fork_join_sub_task subclasses!"); + + T* new_task = tbb_task_->my_stack_->push(task); + spawn_child_internal(new_task); + } + } + } +} + +#endif //PLS_TBB_LIKE_TASK_H diff --git a/lib/pls/include/pls/internal/scheduling/tbb_task.h b/lib/pls/include/pls/internal/scheduling/tbb_task.h deleted file mode 100644 index d3284b6..0000000 --- a/lib/pls/include/pls/internal/scheduling/tbb_task.h +++ /dev/null @@ -1,102 +0,0 @@ - -#ifndef PLS_TBB_LIKE_TASK_H -#define PLS_TBB_LIKE_TASK_H - -#include "pls/internal/base/aligned_stack.h" -#include "pls/internal/base/deque.h" - -#include "abstract_task.h" -#include "thread_state.h" - -namespace pls { - namespace internal { - namespace scheduling { - class tbb_task; - class tbb_sub_task: public base::deque_item { - friend class tbb_task; - - // Coordinate finishing of sub_tasks - std::atomic_uint32_t ref_count_; - tbb_sub_task* parent_; - - // Access to TBB scheduling environment - tbb_task* tbb_task_; - - // Stack Management (reset stack pointer after wait_for_all() calls) - base::aligned_stack::state stack_state_; - protected: - explicit tbb_sub_task(); - tbb_sub_task(const tbb_sub_task& other); - - virtual void execute_internal() = 0; - // SubClass Implementations: - // Do Work - // |-- Spawn Sub Task (new subtask; spawn(subtask);) - // |-- Spawn Sub task - // Do Work - // |-- Wait For All - // Do Work - // |-- Spawn Sub Task - - template - void spawn_child(const T& sub_task); - void wait_for_all(); - private: - void spawn_child_internal(tbb_sub_task* sub_task); - void execute(); - - public: - virtual void test() { - std::cout << "Test" << std::endl; - } - }; - - class tbb_task: public abstract_task { - friend class tbb_sub_task; - - tbb_sub_task* root_task_; - base::aligned_stack* my_stack_; - - // Double-Ended Queue management - base::deque deque_; - - // Steal Management - tbb_sub_task* last_stolen_; - - tbb_sub_task* get_local_sub_task(); - tbb_sub_task* get_stolen_sub_task(); - - bool internal_stealing(abstract_task* other_task) override; - bool split_task(base::spin_lock* /*lock*/) override; - - public: - explicit tbb_task(tbb_sub_task* root_task, const abstract_task::id& id): - abstract_task{0, id}, - root_task_{root_task}, - my_stack_{nullptr}, - deque_{}, - last_stolen_{nullptr} {}; - - void execute() override { - // Bind this instance to our OS thread - my_stack_ = base::this_thread::state()->task_stack_; - root_task_->tbb_task_ = this; - root_task_->stack_state_ = my_stack_->save_state(); - - // Execute it on our OS thread until its finished - root_task_->execute(); - } - }; - - template - void tbb_sub_task::spawn_child(const T& task) { - static_assert(std::is_base_of::value, "Only pass tbb_sub_task subclasses!"); - - T* new_task = tbb_task_->my_stack_->push(task); - spawn_child_internal(new_task); - } - } - } -} - -#endif //PLS_TBB_LIKE_TASK_H diff --git a/lib/pls/include/pls/pls.h b/lib/pls/include/pls/pls.h index 7b81a9c..6b7f81b 100644 --- a/lib/pls/include/pls/pls.h +++ b/lib/pls/include/pls/pls.h @@ -2,7 +2,7 @@ #define PLS_LIBRARY_H #include "pls/internal/scheduling/scheduler.h" -#include "pls/internal/scheduling/tbb_task.h" +#include "pls/internal/scheduling/fork_join_task.h" #include "pls/internal/scheduling/abstract_task.h" namespace pls { @@ -10,8 +10,8 @@ namespace pls { using internal::scheduling::static_scheduler_memory; using task_id = internal::scheduling::abstract_task::id; - using internal::scheduling::tbb_sub_task; - using internal::scheduling::tbb_task; + using internal::scheduling::fork_join_sub_task; + using internal::scheduling::fork_join_task; } #endif diff --git a/lib/pls/src/algorithms/invoke_parallel.cpp b/lib/pls/src/algorithms/invoke_parallel.cpp new file mode 100644 index 0000000..598d59f --- /dev/null +++ b/lib/pls/src/algorithms/invoke_parallel.cpp @@ -0,0 +1 @@ +#include "pls/algorithms/invoke_parallel.h" diff --git a/lib/pls/src/internal/scheduling/fork_join_task.cpp b/lib/pls/src/internal/scheduling/fork_join_task.cpp new file mode 100644 index 0000000..cf16d53 --- /dev/null +++ b/lib/pls/src/internal/scheduling/fork_join_task.cpp @@ -0,0 +1,96 @@ +#include "pls/internal/scheduling/scheduler.h" +#include "pls/internal/scheduling/fork_join_task.h" + +namespace pls { + namespace internal { + namespace scheduling { + fork_join_sub_task::fork_join_sub_task(): + base::deque_item{}, + ref_count_{0}, + parent_{nullptr}, + tbb_task_{nullptr}, + stack_state_{nullptr} {} + + fork_join_sub_task::fork_join_sub_task(const fork_join_sub_task& other): base::deque_item(other) { + // Do Nothing, will be inited after this anyways + } + + void fork_join_sub_task::execute() { + execute_internal(); + wait_for_all(); + + if (parent_ != nullptr) { + parent_->ref_count_--; + } + } + + void fork_join_sub_task::spawn_child_internal(fork_join_sub_task* sub_task) { + // Keep our refcount up to date + ref_count_++; + + // Assign forced values + sub_task->parent_ = this; + sub_task->tbb_task_ = tbb_task_; + sub_task->stack_state_ = tbb_task_->my_stack_->save_state(); + + tbb_task_->deque_.push_tail(sub_task); + } + + void fork_join_sub_task::wait_for_all() { + while (ref_count_ > 0) { + fork_join_sub_task* local_task = tbb_task_->get_local_sub_task(); + if (local_task != nullptr) { + local_task->execute(); + } else { + // Try to steal work. + // External steal will be executed implicitly if success + if (tbb_task_->steal_work()) { + tbb_task_->last_stolen_->execute(); + } + } + } + tbb_task_->my_stack_->reset_state(stack_state_); + } + + fork_join_sub_task* fork_join_task::get_local_sub_task() { + return deque_.pop_tail(); + } + + fork_join_sub_task* fork_join_task::get_stolen_sub_task() { + return deque_.pop_head(); + } + + bool fork_join_task::internal_stealing(abstract_task* other_task) { + auto cast_other_task = reinterpret_cast(other_task); + + auto stolen_sub_task = cast_other_task->get_stolen_sub_task(); + if (stolen_sub_task == nullptr) { + return false; + } else { + // Make sub-task belong to our fork_join_task instance + stolen_sub_task->tbb_task_ = this; + stolen_sub_task->stack_state_ = my_stack_->save_state(); + // We will execute this next without explicitly moving it onto our stack storage + last_stolen_ = stolen_sub_task; + + return true; + } + } + + bool fork_join_task::split_task(base::spin_lock* lock) { + fork_join_sub_task* stolen_sub_task = get_stolen_sub_task(); + if (stolen_sub_task == nullptr) { + return false; + } + fork_join_task task{stolen_sub_task, this->unique_id()}; + + // In success case, unlock. + // TODO: this locking is complicated and error prone. + lock->unlock(); + + scheduler::execute_task(task, depth()); + return true; + } + } + } +} diff --git a/lib/pls/src/internal/scheduling/tbb_task.cpp b/lib/pls/src/internal/scheduling/tbb_task.cpp deleted file mode 100644 index 2a6024d..0000000 --- a/lib/pls/src/internal/scheduling/tbb_task.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "pls/internal/scheduling/scheduler.h" -#include "pls/internal/scheduling/tbb_task.h" - -namespace pls { - namespace internal { - namespace scheduling { - tbb_sub_task::tbb_sub_task(): - base::deque_item{}, - ref_count_{0}, - parent_{nullptr}, - tbb_task_{nullptr}, - stack_state_{nullptr} {} - - tbb_sub_task::tbb_sub_task(const tbb_sub_task& other): base::deque_item(other) { - // Do Nothing, will be inited after this anyways - } - - void tbb_sub_task::execute() { - execute_internal(); - wait_for_all(); - - if (parent_ != nullptr) { - parent_->ref_count_--; - } - } - - void tbb_sub_task::spawn_child_internal(tbb_sub_task* sub_task) { - // Keep our refcount up to date - ref_count_++; - - // Assign forced values - sub_task->parent_ = this; - sub_task->tbb_task_ = tbb_task_; - sub_task->stack_state_ = tbb_task_->my_stack_->save_state(); - - tbb_task_->deque_.push_tail(sub_task); - } - - void tbb_sub_task::wait_for_all() { - while (ref_count_ > 0) { - tbb_sub_task* local_task = tbb_task_->get_local_sub_task(); - if (local_task != nullptr) { - local_task->execute(); - } else { - // Try to steal work. - // External steal will be executed implicitly if success - if (tbb_task_->steal_work()) { - tbb_task_->last_stolen_->execute(); - } - } - } - tbb_task_->my_stack_->reset_state(stack_state_); - } - - tbb_sub_task* tbb_task::get_local_sub_task() { - return deque_.pop_tail(); - } - - tbb_sub_task* tbb_task::get_stolen_sub_task() { - return deque_.pop_head(); - } - - bool tbb_task::internal_stealing(abstract_task* other_task) { - auto cast_other_task = reinterpret_cast(other_task); - - auto stolen_sub_task = cast_other_task->get_stolen_sub_task(); - if (stolen_sub_task == nullptr) { - return false; - } else { - // Make sub-task belong to our tbb_task instance - stolen_sub_task->tbb_task_ = this; - stolen_sub_task->stack_state_ = my_stack_->save_state(); - // We will execute this next without explicitly moving it onto our stack storage - last_stolen_ = stolen_sub_task; - - return true; - } - } - - bool tbb_task::split_task(base::spin_lock* lock) { - tbb_sub_task* stolen_sub_task = get_stolen_sub_task(); - if (stolen_sub_task == nullptr) { - return false; - } - tbb_task task{stolen_sub_task, this->unique_id()}; - - // In success case, unlock. - // TODO: this locking is complicated and error prone. - lock->unlock(); - - scheduler::execute_task(task, depth()); - return true; - } - } - } -} diff --git a/test/scheduling_tests.cpp b/test/scheduling_tests.cpp index 47ff5e2..50f208e 100644 --- a/test/scheduling_tests.cpp +++ b/test/scheduling_tests.cpp @@ -4,7 +4,7 @@ using namespace pls; -class once_sub_task: public tbb_sub_task { +class once_sub_task: public fork_join_sub_task { std::atomic* counter_; int children_; @@ -18,12 +18,12 @@ protected: public: explicit once_sub_task(std::atomic* counter, int children): - tbb_sub_task(), + fork_join_sub_task(), counter_{counter}, children_{children} {} }; -class force_steal_sub_task: public tbb_sub_task { +class force_steal_sub_task: public fork_join_sub_task { std::atomic* parent_counter_; std::atomic* overall_counter_; @@ -42,12 +42,12 @@ protected: public: explicit force_steal_sub_task(std::atomic* parent_counter, std::atomic* overall_counter): - tbb_sub_task(), + fork_join_sub_task(), parent_counter_{parent_counter}, overall_counter_{overall_counter} {} }; -TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/tbb_task.h]") { +TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_task.h]") { static static_scheduler_memory<8, 2 << 12> my_scheduler_memory; SECTION("tasks are executed exactly once") { @@ -58,7 +58,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/tbb_task.h] my_scheduler.perform_work([&] (){ once_sub_task sub_task{&counter, start_counter}; - tbb_task task{&sub_task}; + fork_join_task task{&sub_task}; scheduler::execute_task(task); }); @@ -71,7 +71,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/tbb_task.h] my_scheduler.perform_work([&] (){ std::atomic dummy_parent{1}, overall_counter{8}; force_steal_sub_task sub_task{&dummy_parent, &overall_counter}; - tbb_task task{&sub_task}; + fork_join_task task{&sub_task}; scheduler::execute_task(task); }); my_scheduler.terminate(true); -- libgit2 0.26.0