Commit b7f42e2b by FritzFlorian

Add proper unique_ids for tasks.

parent 48804e8f
Pipeline #1149 passed with stages
in 3 minutes 35 seconds
...@@ -4,6 +4,31 @@ A collection of stuff that we noticed during development. ...@@ -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 Useful later on two write a project report and to go back
in time to find out why certain decisions where made. 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<T..>) 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 ## 11.04.2019 - Lambda Pointer Abstraction
The question is if we could use a pointer to a lambda without The question is if we could use a pointer to a lambda without
......
add_executable(playground main.cpp) add_executable(playground main.cpp)
# Example for adding the library to your app (as a cmake project dependency) # Example for adding the library to your app (as a cmake project dependency)
target_link_libraries(playground pls) target_link_libraries(playground pls)
\ No newline at end of file
...@@ -4,16 +4,14 @@ ...@@ -4,16 +4,14 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <typeindex>
#include <tuple>
#include <pls/pls.h> #include <pls/internal/scheduling/root_task.h>
#include <pls/internal/helpers/prohibit_new.h> #include <pls/internal/helpers/unique_id.h>
#include <pls/internal/scheduling/thread_state.h>
using namespace pls;
int main() { int main() {
malloc_scheduler_memory sched_memory{8}; std::cout << pls::internal::scheduling::root_task<void(*)>::create_id().type_.hash_code() << std::endl;
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 << pls::internal::helpers::unique_id::create<pls::internal::scheduling::root_task<void(*)>>().type_.hash_code() << 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;
} }
...@@ -29,7 +29,7 @@ add_library(pls STATIC ...@@ -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/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/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/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 # Add everything in `./include` to be in the include path of this project
target_include_directories(pls target_include_directories(pls
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "pls/internal/scheduling/fork_join_task.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 pls {
namespace algorithm { namespace algorithm {
...@@ -29,7 +30,8 @@ namespace pls { ...@@ -29,7 +30,8 @@ namespace pls {
template<typename Function1, typename Function2> template<typename Function1, typename Function2>
void invoke_parallel(const Function1& function1, const Function2& function2) { void invoke_parallel(const Function1& function1, const Function2& function2) {
using namespace ::pls::internal::scheduling; 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<Function1, Function2>();
auto internal_body = [&] (fork_join_sub_task* this_task){ auto internal_body = [&] (fork_join_sub_task* this_task){
auto sub_task_body_1 = [&] (fork_join_sub_task*){ function1(); }; auto sub_task_body_1 = [&] (fork_join_sub_task*){ function1(); };
...@@ -46,7 +48,8 @@ namespace pls { ...@@ -46,7 +48,8 @@ namespace pls {
template<typename Function1, typename Function2, typename Function3> template<typename Function1, typename Function2, typename Function3>
void invoke_parallel(const Function1& function1, const Function2& function2, const Function3& function3) { void invoke_parallel(const Function1& function1, const Function2& function2, const Function3& function3) {
using namespace ::pls::internal::scheduling; 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<Function1, Function2, Function3>();
auto internal_body = [&] (fork_join_sub_task* this_task){ auto internal_body = [&] (fork_join_sub_task* this_task){
auto sub_task_body_1 = [&] (fork_join_sub_task*){ function1(); }; auto sub_task_body_1 = [&] (fork_join_sub_task*){ function1(); };
......
#ifndef PLS_UNIQUE_ID_H
#define PLS_UNIQUE_ID_H
#include <typeindex>
#include <tuple>
#include <stdint.h>
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<typename ...T>
static constexpr unique_id create() {
return unique_id(UINT32_MAX, typeid(std::tuple<T...>));
}
private:
explicit constexpr unique_id(const uint32_t id, const std::type_info& type): id_{id}, type_{type} {};
};
}
}
}
#endif //PLS_UNIQUE_ID_H
...@@ -2,25 +2,15 @@ ...@@ -2,25 +2,15 @@
#ifndef PLS_ABSTRACT_TASK_H #ifndef PLS_ABSTRACT_TASK_H
#define PLS_ABSTRACT_TASK_H #define PLS_ABSTRACT_TASK_H
#define PLS_UNIQUE_ID __COUNTER__
#include "pls/internal/base/spin_lock.h" #include "pls/internal/base/spin_lock.h"
#include "pls/internal/helpers/unique_id.h"
namespace pls { namespace pls {
namespace internal { namespace internal {
namespace scheduling { namespace scheduling {
class abstract_task { class abstract_task {
public: public:
struct id { using id = helpers::unique_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_;
}
};
private: private:
int depth_; int depth_;
......
...@@ -17,12 +17,14 @@ namespace pls { ...@@ -17,12 +17,14 @@ namespace pls {
Function function_; Function function_;
std::atomic_uint8_t finished_; std::atomic_uint8_t finished_;
public: public:
static constexpr auto create_id = helpers::unique_id::create<root_task<Function>>;
explicit root_task(Function function): explicit root_task(Function function):
abstract_task{0, id{0}}, abstract_task{0, create_id()},
function_{function}, function_{function},
finished_{0} {} finished_{0} {}
root_task(const root_task& other): root_task(const root_task& other):
abstract_task{0, id{0}}, abstract_task{0, create_id()},
function_{other.function_}, function_{other.function_},
finished_{0} {} finished_{0} {}
...@@ -50,8 +52,10 @@ namespace pls { ...@@ -50,8 +52,10 @@ namespace pls {
root_task<Function>* master_task_; root_task<Function>* master_task_;
public: public:
static constexpr auto create_id = root_task<Function>::create_id;
explicit root_worker_task(root_task<Function>* master_task): explicit root_worker_task(root_task<Function>* master_task):
abstract_task{0, id{0}}, abstract_task{0, create_id()},
master_task_{master_task} {} master_task_{master_task} {}
void execute() override { void execute() override {
......
...@@ -36,8 +36,10 @@ namespace pls { ...@@ -36,8 +36,10 @@ namespace pls {
return counter; return counter;
} }
public: public:
static constexpr auto create_id = helpers::unique_id::create<run_on_n_threads_task<Function>>;
run_on_n_threads_task(Function function, int num_threads): 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}, function_{function},
counter{num_threads - 1} {} counter{num_threads - 1} {}
...@@ -65,8 +67,10 @@ namespace pls { ...@@ -65,8 +67,10 @@ namespace pls {
Function function_; Function function_;
run_on_n_threads_task<Function>* root_; run_on_n_threads_task<Function>* root_;
public: public:
static constexpr auto create_id = helpers::unique_id::create<run_on_n_threads_task_worker<Function>>;
run_on_n_threads_task_worker(Function function, run_on_n_threads_task<Function>* root): run_on_n_threads_task_worker(Function function, run_on_n_threads_task<Function>* root):
abstract_task{0, id{PLS_UNIQUE_ID, true}}, abstract_task{0, create_id()},
function_{function}, function_{function},
root_{root} {} root_{root} {}
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "pls/internal/scheduling/abstract_task.h" #include "pls/internal/scheduling/abstract_task.h"
#include "pls/internal/scheduling/fork_join_task.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 pls {
using internal::scheduling::static_scheduler_memory; using internal::scheduling::static_scheduler_memory;
...@@ -13,6 +14,8 @@ namespace pls { ...@@ -13,6 +14,8 @@ namespace pls {
using internal::scheduling::scheduler; using internal::scheduling::scheduler;
using task_id = internal::scheduling::abstract_task::id; 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_sub_task;
using internal::scheduling::fork_join_task; using internal::scheduling::fork_join_task;
......
...@@ -58,7 +58,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t ...@@ -58,7 +58,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t
my_scheduler.perform_work([&] (){ my_scheduler.perform_work([&] (){
once_sub_task sub_task{&counter, start_counter}; 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); scheduler::execute_task(task);
}); });
...@@ -71,7 +71,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t ...@@ -71,7 +71,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t
my_scheduler.perform_work([&] (){ my_scheduler.perform_work([&] (){
std::atomic<int> dummy_parent{1}, overall_counter{8}; std::atomic<int> dummy_parent{1}, overall_counter{8};
force_steal_sub_task sub_task{&dummy_parent, &overall_counter}; 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); scheduler::execute_task(task);
}); });
my_scheduler.terminate(true); my_scheduler.terminate(true);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment