Commit d3b64a85 by FritzFlorian

WIP: Initialization of continuation chains.

parent 740ae661
Pipeline #1333 failed with stages
in 25 seconds
...@@ -35,11 +35,19 @@ class delayed_initialization_wrapper { ...@@ -35,11 +35,19 @@ class delayed_initialization_wrapper {
template<typename ...ARGS> template<typename ...ARGS>
void initialize(ARGS &&...args) { void initialize(ARGS &&...args) {
PLS_ASSERT(initialized_, "Can only initialize delayed wrapper object once!") PLS_ASSERT(!initialized_, "Can only initialize delayed wrapper object once!")
new(memory_) T(std::forward<ARGS>(args)...); new(memory_) T(std::forward<ARGS>(args)...);
initialized_ = true; initialized_ = true;
} }
void destroy() {
PLS_ASSERT(initialized_, "Can only destroy initialized objects!")
memory_->~T();
initialized_ = false;
}
T &object() { T &object() {
PLS_ASSERT(initialized_, "Can not use an uninitialized delayed wrapper object!") PLS_ASSERT(initialized_, "Can not use an uninitialized delayed wrapper object!")
return *reinterpret_cast<T *>(memory_); return *reinterpret_cast<T *>(memory_);
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#define PLS_CONT_MANAGER_H_ #define PLS_CONT_MANAGER_H_
#include <memory> #include <memory>
#include <tuple>
#include <array>
#include "pls/internal/data_structures/aligned_stack.h" #include "pls/internal/data_structures/aligned_stack.h"
#include "pls/internal/scheduling/continuation.h" #include "pls/internal/scheduling/continuation.h"
...@@ -13,14 +15,45 @@ namespace scheduling { ...@@ -13,14 +15,45 @@ namespace scheduling {
class cont_manager { class cont_manager {
public: public:
explicit cont_manager(size_t num_conts, size_t max_cont_size, data_structures::aligned_stack &cont_storage) template<size_t NUM_CONTS, size_t MAX_CONT_SIZE>
: num_conts_{num_conts}, max_cont_size_{max_cont_size}, cont_storage_{cont_storage} { explicit cont_manager(data_structures::aligned_stack &cont_storage) {
//TODO: Init linked list like structure // First node is currently active and our local start
start_node_ = active_node_ = init_cont_node<MAX_CONT_SIZE>(cont_storage, nullptr, nullptr);
// Build up chain after it
continuation_node *current_node = start_node_;
for (size_t i = 1; i < NUM_CONTS; i++) {
continuation_node *next_node = init_cont_node<MAX_CONT_SIZE>(cont_storage, start_node_, current_node);
current_node->set_prev(next_node);
}
}; };
continuation_node *fast_path_get_next() {
active_node_ = active_node_->get_next();
return active_node_;
}
void fast_path_return() {
active_node_ = active_node_->get_prev();
}
private:
template<size_t MAX_CONT_SIZE>
static continuation_node *init_cont_node(data_structures::aligned_stack &cont_storage,
continuation_node *cont_chain_start,
continuation_node *prev) {
// Represents one cont node and its corresponding memory buffer (as one continuous block of memory).
using cont_node_memory_pair = std::tuple<continuation_node,
std::array<char, MAX_CONT_SIZE - sizeof(continuation_node)>>;
char *tuple_memory = cont_storage.push_bytes<cont_node_memory_pair>();
char *cont_node_address = tuple_memory;
char *cont_node_memory_address = tuple_memory + sizeof(continuation_node);
return new(cont_node_address) continuation_node(cont_node_memory_address, cont_chain_start, prev);
}
private: private:
const size_t num_conts_, max_cont_size_; continuation_node *start_node_;
data_structures::aligned_stack &cont_storage_; continuation_node *active_node_;
}; };
template<size_t NUM_CONTS, size_t MAX_CONT_SIZE> template<size_t NUM_CONTS, size_t MAX_CONT_SIZE>
......
...@@ -20,10 +20,27 @@ class base_continuation { ...@@ -20,10 +20,27 @@ class base_continuation {
class continuation_node { class continuation_node {
public: public:
continuation_node(char *continuation_memory, continuation_node *cont_chain_start, continuation_node *prev)
: continuation_memory_{continuation_memory},
continuation_{nullptr},
cont_chain_start_{cont_chain_start},
prev_{prev},
next_{nullptr},
offered_chain_{nullptr} {}
void set_cont_chain_start(continuation_node *cont_chain_start) { cont_chain_start_ = cont_chain_start; }
continuation_node *get_cont_chain_start() { return cont_chain_start_; }
void set_next(continuation_node *next) { next_ = next; }
continuation_node *get_next() { return next_; }
void set_prev(continuation_node *prev) { prev_ = prev; }
continuation_node *get_prev() { return prev_; }
base_continuation *continuation() { return continuation_; }
private: private:
// Pointer to memory region reserved for the companion continuation. // Pointer to memory region reserved for the companion continuation.
// Must be a buffer big enough to hold any continuation encountered in the program. // Must be a buffer big enough to hold any continuation encountered in the program.
char *continuation_memory_;
base_continuation *continuation_; base_continuation *continuation_;
// Linked list property of continuations (continuation chains as memory management). // Linked list property of continuations (continuation chains as memory management).
...@@ -47,6 +64,10 @@ class continuation : public base_continuation { ...@@ -47,6 +64,10 @@ class continuation : public base_continuation {
// E.g. handle passing the result to the parent continuation // E.g. handle passing the result to the parent continuation
function_.object()(result_1_.object(), result_2_.object()); function_.object()(result_1_.object(), result_2_.object());
} }
// Warning: De-constructor only called once the continuation is actually needed.
// This should be a non issue, as all memory in the continuation is uninitialized
// until the first use anyways to save runtime.
~continuation() override = default; ~continuation() override = default;
template<typename R1ARG> template<typename R1ARG>
...@@ -76,14 +97,15 @@ class continuation : public base_continuation { ...@@ -76,14 +97,15 @@ class continuation : public base_continuation {
template<typename T> template<typename T>
using delayed_init = data_structures::delayed_initialization_wrapper<T>; using delayed_init = data_structures::delayed_initialization_wrapper<T>;
delayed_init<R1> result_1_;
delayed_init<R2> result_2_;
delayed_init<F> function_;
// Also uninitialized at first, only take the atomic write on the slow path. // Also uninitialized at first, only take the atomic write on the slow path.
// The stealer will init it to 2 while stealing, the 'stolen' sync will then make sure // The stealer will init it to 2 while stealing, the 'stolen' sync will then make sure
// everyone sees the value in correct order. // everyone sees the value in correct order.
std::atomic<unsigned short> results_missing_{}; std::atomic<unsigned short> results_missing_{};
// All fields/actual values stay uninitialized (save time on the fast path if we don not need them).
delayed_init<R1> result_1_;
delayed_init<R2> result_2_;
delayed_init<F> function_;
}; };
} }
......
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