Commit 84ec2d6b by FritzFlorian

Make stack allocator selectable by templated constructor.

I am not sure if this is appropriate, but it works and is no focus of this project.
parent c0f0863c
Pipeline #1423 failed with stages
in 32 seconds
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <memory>
#include "pls/internal/helpers/profiler.h" #include "pls/internal/helpers/profiler.h"
...@@ -38,7 +39,17 @@ class scheduler { ...@@ -38,7 +39,17 @@ class scheduler {
* *
* @param num_threads The number of worker threads to be created. * @param num_threads The number of worker threads to be created.
*/ */
explicit scheduler(unsigned int num_threads, size_t computation_depth, size_t stack_size, bool reuse_thread = true); explicit scheduler(unsigned int num_threads,
size_t computation_depth,
size_t stack_size,
bool reuse_thread = true);
template<typename ALLOC>
explicit scheduler(unsigned int num_threads,
size_t computation_depth,
size_t stack_size,
bool reuse_thread,
ALLOC &&stack_allocator);
/** /**
* The scheduler is implicitly terminated as soon as it leaves the scope. * The scheduler is implicitly terminated as soon as it leaves the scope.
...@@ -105,8 +116,7 @@ class scheduler { ...@@ -105,8 +116,7 @@ class scheduler {
bool terminated_; bool terminated_;
// TODO: remove this into a public wrapper class with templating std::shared_ptr<base::stack_allocator> stack_allocator_;
base::mmap_stack_allocator stack_allocator_{};
}; };
} }
......
...@@ -14,6 +14,46 @@ ...@@ -14,6 +14,46 @@
namespace pls::internal::scheduling { namespace pls::internal::scheduling {
template<typename ALLOC>
scheduler::scheduler(unsigned int num_threads,
size_t computation_depth,
size_t stack_size,
bool reuse_thread,
ALLOC &&stack_allocator) :
num_threads_{num_threads},
reuse_thread_{reuse_thread},
sync_barrier_{num_threads + 1 - reuse_thread},
worker_threads_{},
thread_states_{},
main_thread_starter_function_{nullptr},
work_section_done_{false},
terminated_{false},
stack_allocator_{std::make_shared<ALLOC>(std::forward<ALLOC>(stack_allocator))} {
worker_threads_.reserve(num_threads);
task_managers_.reserve(num_threads);
thread_states_.reserve(num_threads);
for (unsigned int i = 0; i < num_threads_; i++) {
auto &this_task_manager =
task_managers_.emplace_back(std::make_unique<task_manager>(i,
computation_depth,
stack_size,
stack_allocator_));
auto &this_thread_state = thread_states_.emplace_back(std::make_unique<thread_state>(*this, i, *this_task_manager));
if (reuse_thread && i == 0) {
worker_threads_.emplace_back();
continue; // Skip over first/main thread when re-using the users thread, as this one will replace the first one.
}
auto *this_thread_state_pointer = this_thread_state.get();
worker_threads_.emplace_back([this_thread_state_pointer] {
thread_state::set(this_thread_state_pointer);
work_thread_main_loop();
});
}
}
class scheduler::init_function { class scheduler::init_function {
public: public:
virtual void run() = 0; virtual void run() = 0;
......
...@@ -26,7 +26,7 @@ class task_manager { ...@@ -26,7 +26,7 @@ class task_manager {
explicit task_manager(unsigned thread_id, explicit task_manager(unsigned thread_id,
size_t num_tasks, size_t num_tasks,
size_t stack_size, size_t stack_size,
stack_allocator &stack_allocator); std::shared_ptr<stack_allocator> stack_allocator);
~task_manager(); ~task_manager();
void push_resource_on_task(task *target_task, task *spare_task_chain); void push_resource_on_task(task *target_task, task *spare_task_chain);
...@@ -51,14 +51,29 @@ class task_manager { ...@@ -51,14 +51,29 @@ class task_manager {
bool try_clean_return(context_switcher::continuation &result_cont); bool try_clean_return(context_switcher::continuation &result_cont);
/**
* Helper to check if a task chain is correctly chained forward form the given starting task.
*
* @param start_task The start of the 'to be clean' chain
* @return true if the chain is clean/consistent.
*/
bool check_task_chain_forward(task *start_task); bool check_task_chain_forward(task *start_task);
/**
* Helper to check if a task chain is correctly chained backward form the given starting task.
*
* @param start_task The end of the 'to be clean' chain
* @return true if the chain was is clean/consistent.
*/
bool check_task_chain_backward(task *start_task); bool check_task_chain_backward(task *start_task);
/**
* Check the task chain maintained by this task manager.
*
* @return true if the chain is in a clean/consistent state.
*/
bool check_task_chain(); bool check_task_chain();
private: private:
size_t num_tasks_; std::shared_ptr<stack_allocator> stack_allocator_;
stack_allocator &stack_allocator_;
std::vector<std::unique_ptr<task>> tasks_; std::vector<std::unique_ptr<task>> tasks_;
task *active_task_; task *active_task_;
......
...@@ -7,41 +7,19 @@ ...@@ -7,41 +7,19 @@
namespace pls::internal::scheduling { namespace pls::internal::scheduling {
scheduler::scheduler(unsigned int num_threads, size_t computation_depth, size_t stack_size, bool reuse_thread) : scheduler::scheduler(unsigned int num_threads,
num_threads_{num_threads}, size_t computation_depth,
reuse_thread_{reuse_thread}, size_t stack_size,
sync_barrier_{num_threads + 1 - reuse_thread}, bool reuse_thread) : scheduler(num_threads,
worker_threads_{}, computation_depth,
thread_states_{}, stack_size,
main_thread_starter_function_{nullptr}, reuse_thread,
work_section_done_{false}, base::mmap_stack_allocator{}) {}
terminated_{false} {
worker_threads_.reserve(num_threads);
task_managers_.reserve(num_threads);
thread_states_.reserve(num_threads);
for (unsigned int i = 0; i < num_threads_; i++) {
auto &this_task_manager =
task_managers_.emplace_back(std::make_unique<task_manager>(i, computation_depth, stack_size, stack_allocator_));
auto &this_thread_state = thread_states_.emplace_back(std::make_unique<thread_state>(*this, i, *this_task_manager));
if (reuse_thread && i == 0) {
worker_threads_.emplace_back();
continue; // Skip over first/main thread when re-using the users thread, as this one will replace the first one.
}
auto *this_thread_state_pointer = this_thread_state.get();
worker_threads_.emplace_back([this_thread_state_pointer] {
thread_state::set(this_thread_state_pointer);
work_thread_main_loop();
});
}
}
scheduler::~scheduler() { scheduler::~scheduler() {
terminate(); terminate();
} }
void scheduler::work_thread_main_loop() { void scheduler::work_thread_main_loop() {
auto &scheduler = thread_state::get().get_scheduler(); auto &scheduler = thread_state::get().get_scheduler();
while (true) { while (true) {
......
...@@ -9,14 +9,13 @@ namespace pls::internal::scheduling { ...@@ -9,14 +9,13 @@ namespace pls::internal::scheduling {
task_manager::task_manager(unsigned thread_id, task_manager::task_manager(unsigned thread_id,
size_t num_tasks, size_t num_tasks,
size_t stack_size, size_t stack_size,
stack_allocator &stack_allocator) : num_tasks_{num_tasks}, std::shared_ptr<stack_allocator> stack_allocator) : stack_allocator_{stack_allocator},
stack_allocator_{stack_allocator}, tasks_{},
tasks_{}, deque_{thread_id, num_tasks} {
deque_{thread_id, num_tasks_} {
tasks_.reserve(num_tasks); tasks_.reserve(num_tasks);
for (size_t i = 0; i < num_tasks - 1; i++) { for (size_t i = 0; i < num_tasks - 1; i++) {
char *stack_memory = stack_allocator.allocate_stack(stack_size); char *stack_memory = stack_allocator->allocate_stack(stack_size);
tasks_.emplace_back(std::make_unique<task>(stack_memory, stack_size, i, thread_id)); tasks_.emplace_back(std::make_unique<task>(stack_memory, stack_size, i, thread_id));
if (i > 0) { if (i > 0) {
...@@ -29,7 +28,7 @@ task_manager::task_manager(unsigned thread_id, ...@@ -29,7 +28,7 @@ task_manager::task_manager(unsigned thread_id,
task_manager::~task_manager() { task_manager::~task_manager() {
for (auto &task : tasks_) { for (auto &task : tasks_) {
stack_allocator_.free_stack(task->stack_size_, task->stack_memory_); stack_allocator_->free_stack(task->stack_size_, task->stack_memory_);
} }
} }
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
using namespace pls::internal::scheduling; using namespace pls::internal::scheduling;
constexpr int MAX_NUM_THREADS = 8;
constexpr int MAX_NUM_TASKS = 32; constexpr int MAX_NUM_TASKS = 32;
constexpr int MAX_STACK_SIZE = 1024 * 8; constexpr int MAX_STACK_SIZE = 1024 * 8;
......
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