From b7f42e2bebacd75d7ce2daded12fdb4e2078b274 Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Fri, 12 Apr 2019 15:04:18 +0200 Subject: [PATCH] Add proper unique_ids for tasks. --- NOTES.md | 25 +++++++++++++++++++++++++ app/playground/CMakeLists.txt | 2 +- app/playground/main.cpp | 14 ++++++-------- lib/pls/CMakeLists.txt | 2 +- lib/pls/include/pls/algorithms/invoke_parallel_impl.h | 7 +++++-- lib/pls/include/pls/internal/helpers/unique_id.h | 31 +++++++++++++++++++++++++++++++ lib/pls/include/pls/internal/scheduling/abstract_task.h | 14 ++------------ lib/pls/include/pls/internal/scheduling/root_task.h | 10 +++++++--- lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h | 8 ++++++-- lib/pls/include/pls/pls.h | 3 +++ test/scheduling_tests.cpp | 4 ++-- 11 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 lib/pls/include/pls/internal/helpers/unique_id.h diff --git a/NOTES.md b/NOTES.md index d8de36a..076b2ca 100644 --- a/NOTES.md +++ b/NOTES.md @@ -4,6 +4,31 @@ A collection of stuff that we noticed during development. Useful later on two write a project report and to go back in time to find out why certain decisions where made. +## 12.04.2019 - Unique IDs + +Assigning unique IDs to logical different tasks is key to the +current model of separating timing/memory guarantees for certain +parallel patterns. + +We do want to assign these IDs automatic in most cases (a call to +some parallel API should not require the end user to specific a +unique ID for each different call, as this would be error prone). +Instead we want to make sure that each DIFFERENT API call is separated +automatic, while leaving the option for manual ID assignment for later +implementations of GPU offloading (tasks need to have identifiers for +this to work properly). + +Our first approach was using the `__COUNTER__` macro, +but this only works in ONE COMPLIATION UNIT and is not +portable to all compilers. + +As all our unique instances are copled to a class/type +we decided to implement the unique IDs using +typeid(tuple) in automatic cases (bound to a specific type) +and fully manual IDs in other types. All this is wrapped in a +helper::unique_id class. + + ## 11.04.2019 - Lambda Pointer Abstraction The question is if we could use a pointer to a lambda without diff --git a/app/playground/CMakeLists.txt b/app/playground/CMakeLists.txt index bdcbebe..c1b57ee 100644 --- a/app/playground/CMakeLists.txt +++ b/app/playground/CMakeLists.txt @@ -1,4 +1,4 @@ add_executable(playground main.cpp) # Example for adding the library to your app (as a cmake project dependency) -target_link_libraries(playground pls) \ No newline at end of file +target_link_libraries(playground pls) diff --git a/app/playground/main.cpp b/app/playground/main.cpp index 4a33c29..cc7e784 100644 --- a/app/playground/main.cpp +++ b/app/playground/main.cpp @@ -4,16 +4,14 @@ #include #include #include +#include +#include -#include -#include -#include +#include +#include -using namespace pls; int main() { - malloc_scheduler_memory sched_memory{8}; - std::cout << (std::uintptr_t)sched_memory.thread_for(0) % 64 << ", " << (std::uintptr_t)sched_memory.thread_for(1) % 64 << ", " << (std::uintptr_t)sched_memory.thread_for(2) % 64 << ", " << std::endl; - std::cout << (std::uintptr_t)sched_memory.thread_state_for(0) % 64 << ", " << (std::uintptr_t)sched_memory.thread_state_for(1) % 64 << ", " << (std::uintptr_t)sched_memory.thread_state_for(2) % 64 << ", " << std::endl; - std::cout << (std::uintptr_t)sched_memory.task_stack_for(0) % 64 << ", " << (std::uintptr_t)sched_memory.task_stack_for(1) % 64 << ", " << (std::uintptr_t)sched_memory.task_stack_for(2) % 64 << ", " << std::endl; + std::cout << pls::internal::scheduling::root_task::create_id().type_.hash_code() << std::endl; + std::cout << pls::internal::helpers::unique_id::create>().type_.hash_code() << std::endl; } diff --git a/lib/pls/CMakeLists.txt b/lib/pls/CMakeLists.txt index 970adf0..4f8652a 100644 --- a/lib/pls/CMakeLists.txt +++ b/lib/pls/CMakeLists.txt @@ -29,7 +29,7 @@ add_library(pls STATIC include/pls/internal/scheduling/run_on_n_threads_task.h src/internal/scheduling/run_on_n_threads_task.cpp include/pls/internal/scheduling/fork_join_task.h src/internal/scheduling/fork_join_task.cpp include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp -) + include/pls/internal/helpers/unique_id.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_impl.h b/lib/pls/include/pls/algorithms/invoke_parallel_impl.h index 4a7746f..7dfbef8 100644 --- a/lib/pls/include/pls/algorithms/invoke_parallel_impl.h +++ b/lib/pls/include/pls/algorithms/invoke_parallel_impl.h @@ -4,6 +4,7 @@ #include "pls/internal/scheduling/fork_join_task.h" #include "pls/internal/scheduling/scheduler.h" +#include "pls/internal/helpers/unique_id.h" namespace pls { namespace algorithm { @@ -29,7 +30,8 @@ namespace pls { template void invoke_parallel(const Function1& function1, const Function2& function2) { using namespace ::pls::internal::scheduling; - static abstract_task::id id{PLS_UNIQUE_ID, true}; + using namespace ::pls::internal::helpers; + static abstract_task::id id = unique_id::create(); auto internal_body = [&] (fork_join_sub_task* this_task){ auto sub_task_body_1 = [&] (fork_join_sub_task*){ function1(); }; @@ -46,7 +48,8 @@ namespace pls { template void invoke_parallel(const Function1& function1, const Function2& function2, const Function3& function3) { using namespace ::pls::internal::scheduling; - static abstract_task::id id{PLS_UNIQUE_ID, true}; + using namespace ::pls::internal::helpers; + static abstract_task::id id = unique_id::create(); auto internal_body = [&] (fork_join_sub_task* this_task){ auto sub_task_body_1 = [&] (fork_join_sub_task*){ function1(); }; diff --git a/lib/pls/include/pls/internal/helpers/unique_id.h b/lib/pls/include/pls/internal/helpers/unique_id.h new file mode 100644 index 0000000..918021c --- /dev/null +++ b/lib/pls/include/pls/internal/helpers/unique_id.h @@ -0,0 +1,31 @@ + +#ifndef PLS_UNIQUE_ID_H +#define PLS_UNIQUE_ID_H + +#include +#include +#include + +namespace pls { + namespace internal { + namespace helpers { + struct unique_id { + const uint32_t id_; + const std::type_info& type_; + bool operator==(const unique_id& other) const { return id_ == other.id_ && type_ == other.type_; } + + static constexpr unique_id create(const uint32_t id) { + return unique_id(id, typeid(void)); + } + template + static constexpr unique_id create() { + return unique_id(UINT32_MAX, typeid(std::tuple)); + } + private: + explicit constexpr unique_id(const uint32_t id, const std::type_info& type): id_{id}, type_{type} {}; + }; + } + } +} + +#endif //PLS_UNIQUE_ID_H diff --git a/lib/pls/include/pls/internal/scheduling/abstract_task.h b/lib/pls/include/pls/internal/scheduling/abstract_task.h index 952a530..2531a1c 100644 --- a/lib/pls/include/pls/internal/scheduling/abstract_task.h +++ b/lib/pls/include/pls/internal/scheduling/abstract_task.h @@ -2,25 +2,15 @@ #ifndef PLS_ABSTRACT_TASK_H #define PLS_ABSTRACT_TASK_H -#define PLS_UNIQUE_ID __COUNTER__ - #include "pls/internal/base/spin_lock.h" +#include "pls/internal/helpers/unique_id.h" namespace pls { namespace internal { namespace scheduling { class abstract_task { public: - struct id { - uint32_t id_; - bool auto_generated_; - - explicit id(uint32_t id, bool auto_generated=false): id_{id}, auto_generated_{auto_generated} {}; - - bool operator==(const abstract_task::id& other) const { - return id_ == other.id_ && auto_generated_ == other.auto_generated_; - } - }; + using id = helpers::unique_id; private: int depth_; diff --git a/lib/pls/include/pls/internal/scheduling/root_task.h b/lib/pls/include/pls/internal/scheduling/root_task.h index 6834b6b..5b2c3cb 100644 --- a/lib/pls/include/pls/internal/scheduling/root_task.h +++ b/lib/pls/include/pls/internal/scheduling/root_task.h @@ -17,12 +17,14 @@ namespace pls { Function function_; std::atomic_uint8_t finished_; public: + static constexpr auto create_id = helpers::unique_id::create>; + explicit root_task(Function function): - abstract_task{0, id{0}}, + abstract_task{0, create_id()}, function_{function}, finished_{0} {} root_task(const root_task& other): - abstract_task{0, id{0}}, + abstract_task{0, create_id()}, function_{other.function_}, finished_{0} {} @@ -50,8 +52,10 @@ namespace pls { root_task* master_task_; public: + static constexpr auto create_id = root_task::create_id; + explicit root_worker_task(root_task* master_task): - abstract_task{0, id{0}}, + abstract_task{0, create_id()}, master_task_{master_task} {} void execute() override { diff --git a/lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h b/lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h index f8fd9ef..06539e1 100644 --- a/lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h +++ b/lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h @@ -36,8 +36,10 @@ namespace pls { return counter; } public: + static constexpr auto create_id = helpers::unique_id::create>; + run_on_n_threads_task(Function function, int num_threads): - abstract_task{0, id{PLS_UNIQUE_ID, true}}, + abstract_task{0, create_id()}, function_{function}, counter{num_threads - 1} {} @@ -65,8 +67,10 @@ namespace pls { Function function_; run_on_n_threads_task* root_; public: + static constexpr auto create_id = helpers::unique_id::create>; + run_on_n_threads_task_worker(Function function, run_on_n_threads_task* root): - abstract_task{0, id{PLS_UNIQUE_ID, true}}, + abstract_task{0, create_id()}, function_{function}, root_{root} {} diff --git a/lib/pls/include/pls/pls.h b/lib/pls/include/pls/pls.h index ac5c4ec..35cb545 100644 --- a/lib/pls/include/pls/pls.h +++ b/lib/pls/include/pls/pls.h @@ -5,6 +5,7 @@ #include "pls/internal/scheduling/abstract_task.h" #include "pls/internal/scheduling/fork_join_task.h" #include "pls/internal/scheduling/scheduler.h" +#include "pls/internal/helpers/unique_id.h" namespace pls { using internal::scheduling::static_scheduler_memory; @@ -13,6 +14,8 @@ namespace pls { using internal::scheduling::scheduler; using task_id = internal::scheduling::abstract_task::id; + using unique_id = internal::helpers::unique_id; + using internal::scheduling::fork_join_sub_task; using internal::scheduling::fork_join_task; diff --git a/test/scheduling_tests.cpp b/test/scheduling_tests.cpp index f116f1b..d3a340d 100644 --- a/test/scheduling_tests.cpp +++ b/test/scheduling_tests.cpp @@ -58,7 +58,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t my_scheduler.perform_work([&] (){ once_sub_task sub_task{&counter, start_counter}; - fork_join_task task{&sub_task, task_id{42}}; + fork_join_task task{&sub_task, unique_id::create(42)}; scheduler::execute_task(task); }); @@ -71,7 +71,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t my_scheduler.perform_work([&] (){ std::atomic dummy_parent{1}, overall_counter{8}; force_steal_sub_task sub_task{&dummy_parent, &overall_counter}; - fork_join_task task{&sub_task, task_id{42}}; + fork_join_task task{&sub_task, unique_id::create(42)}; scheduler::execute_task(task); }); my_scheduler.terminate(true); -- libgit2 0.26.0