From e3237abdbc7416fdc21194ed3943c4251da108ed Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Mon, 13 May 2019 13:53:38 +0200 Subject: [PATCH] Add parallel_for based on fork_join tasks. --- CMakeLists.txt | 1 + lib/pls/include/pls/algorithms/parallel_for.h | 15 +++++++++++++++ lib/pls/include/pls/algorithms/parallel_for_impl.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pls/include/pls/internal/scheduling/parallel_iterator_task.h | 35 ++++++++++++++++++++--------------- lib/pls/include/pls/internal/scheduling/parallel_iterator_task_impl.h | 47 +++++++++++++++++++++++------------------------ lib/pls/include/pls/pls.h | 2 ++ 6 files changed, 118 insertions(+), 39 deletions(-) create mode 100644 lib/pls/include/pls/algorithms/parallel_for.h create mode 100644 lib/pls/include/pls/algorithms/parallel_for_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a66e63..bc061e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_subdirectory(app/test_for_new) add_subdirectory(app/invoke_parallel) add_subdirectory(app/benchmark_fft) add_subdirectory(app/benchmark_unbalanced) +add_subdirectory(app/benchmark_matrix) # Add optional tests option(PACKAGE_TESTS "Build the tests" ON) diff --git a/lib/pls/include/pls/algorithms/parallel_for.h b/lib/pls/include/pls/algorithms/parallel_for.h new file mode 100644 index 0000000..4df1104 --- /dev/null +++ b/lib/pls/include/pls/algorithms/parallel_for.h @@ -0,0 +1,15 @@ + +#ifndef PLS_PARALLEL_FOR_H +#define PLS_PARALLEL_FOR_H + +namespace pls { +namespace algorithm { + +template +void parallel_for(RandomIt first, RandomIt last, const Function &function); + +} +} +#include "parallel_for_impl.h" + +#endif //PLS_PARALLEL_FOR_H diff --git a/lib/pls/include/pls/algorithms/parallel_for_impl.h b/lib/pls/include/pls/algorithms/parallel_for_impl.h new file mode 100644 index 0000000..afd7baa --- /dev/null +++ b/lib/pls/include/pls/algorithms/parallel_for_impl.h @@ -0,0 +1,57 @@ + +#ifndef PLS_PARALLEL_FOR_IMPL_H +#define PLS_PARALLEL_FOR_IMPL_H + +#include "pls/internal/scheduling/fork_join_task.h" +#include "pls/internal/scheduling/scheduler.h" +#include "pls/internal/scheduling/scheduler.h" + +#include "pls/internal/helpers/unique_id.h" + +namespace pls { +namespace algorithm { +namespace internal { +template +void parallel_for(RandomIt first, RandomIt last, const Function &function) { + using namespace ::pls::internal::scheduling; + using namespace ::pls::internal::helpers; + using namespace ::pls::internal::base; + constexpr long min_elements = 4; + + long num_elements = std::distance(first, last); + if (num_elements <= min_elements) { + // calculate last elements in loop to avoid overhead + for (auto current = first; current != last; current++) { + function(*current); + } + } else { + // Cut in half recursively + long middle_index = num_elements / 2; + + auto body = [=] { internal::parallel_for(first + middle_index, last, function); }; + fork_join_lambda_by_reference second_half_task(body); + fork_join_sub_task::current()->spawn_child(second_half_task); + + parallel_for(first, first + middle_index, function); + fork_join_sub_task::current()->wait_for_all(); + } +} +} + +template +void parallel_for(RandomIt first, RandomIt last, const Function &function) { + using namespace ::pls::internal::scheduling; + using namespace ::pls::internal::helpers; + using namespace ::pls::internal::base; + static abstract_task::id id = unique_id::create(); + + auto body = [=] { internal::parallel_for(first, last, function); }; + fork_join_lambda_by_reference root_body(body); + fork_join_task root_task{&root_body, id}; + scheduler::execute_task(root_task); +} + +} +} + +#endif //PLS_INVOKE_PARALLEL_IMPL_H diff --git a/lib/pls/include/pls/internal/scheduling/parallel_iterator_task.h b/lib/pls/include/pls/internal/scheduling/parallel_iterator_task.h index c57b1ab..2013110 100644 --- a/lib/pls/include/pls/internal/scheduling/parallel_iterator_task.h +++ b/lib/pls/include/pls/internal/scheduling/parallel_iterator_task.h @@ -5,23 +5,28 @@ #include "abstract_task.h" namespace pls { - namespace internal { - namespace scheduling { - template - class parallel_iterator_task: public abstract_task { - RandomIt first_, last_; - Function function_; +namespace internal { +namespace scheduling { +template +class parallel_iterator_task : public abstract_task { + RandomIt first_, last_; + Function function_; - protected: - bool internal_stealing(abstract_task* other_task) override; - bool split_task(base::spin_lock* /*lock*/) override; + // External stealing + size_t first_index_ava, last_index_ava; + // My internal state + size_t current_index, max_index; - public: - explicit parallel_iterator_task(RandomIt first, RandomIt last, Function function, const abstract_task::id& id); - void execute() override; - }; - } - } + protected: + bool internal_stealing(abstract_task *other_task) override; + bool split_task(base::swmr_spin_lock * /*lock*/) override; + + public: + explicit parallel_iterator_task(RandomIt first, RandomIt last, Function function, const abstract_task::id &id); + void execute() override; +}; +} +} } #include "parallel_iterator_task_impl.h" diff --git a/lib/pls/include/pls/internal/scheduling/parallel_iterator_task_impl.h b/lib/pls/include/pls/internal/scheduling/parallel_iterator_task_impl.h index a0ab2dd..1883cde 100644 --- a/lib/pls/include/pls/internal/scheduling/parallel_iterator_task_impl.h +++ b/lib/pls/include/pls/internal/scheduling/parallel_iterator_task_impl.h @@ -2,34 +2,33 @@ #ifndef PLS_PARALLEL_ITERATOR_TASK_IMPL_H #define PLS_PARALLEL_ITERATOR_TASK_IMPL_H - namespace pls { - namespace internal { - namespace scheduling { - template - parallel_iterator_task::parallel_iterator_task - (RandomIt first, RandomIt last, Function function, const abstract_task::id& id): - abstract_task(0, id), - first_{first}, - last_{last}, - function_{function} {} - - template - void parallel_iterator_task::execute() { +namespace internal { +namespace scheduling { +template +parallel_iterator_task::parallel_iterator_task + (RandomIt first, RandomIt last, Function function, const abstract_task::id &id): + abstract_task(0, id), + first_{first}, + last_{last}, + function_{function} {} + +template +void parallel_iterator_task::execute() { - } +} - template - bool parallel_iterator_task::split_task(base::spin_lock* /*lock*/) { - return false; - } +template +bool parallel_iterator_task::split_task(base::swmr_spin_lock * /*lock*/) { + return false; +} - template - bool parallel_iterator_task::internal_stealing(abstract_task* other_task) { - return false; - } - } - } +template +bool parallel_iterator_task::internal_stealing(abstract_task *other_task) { + return false; +} +} +} } #endif //PLS_PARALLEL_ITERATOR_TASK_IMPL_H diff --git a/lib/pls/include/pls/pls.h b/lib/pls/include/pls/pls.h index b7a218b..0b0e366 100644 --- a/lib/pls/include/pls/pls.h +++ b/lib/pls/include/pls/pls.h @@ -2,6 +2,7 @@ #define PLS_LIBRARY_H #include "pls/algorithms/invoke_parallel.h" +#include "pls/algorithms/parallel_for.h" #include "pls/internal/scheduling/abstract_task.h" #include "pls/internal/scheduling/fork_join_task.h" #include "pls/internal/scheduling/scheduler.h" @@ -23,6 +24,7 @@ using internal::scheduling::fork_join_lambda_by_value; using internal::scheduling::fork_join_task; using algorithm::invoke_parallel; +using algorithm::parallel_for; } -- libgit2 0.26.0