From e403e498b89c056752b422022e7ef76d3df2bc5a Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Thu, 1 Aug 2019 11:47:14 +0200 Subject: [PATCH] Change both stack and queue to same offset counters. This allows the stack and deque class to use the same offset, making it work better with each other. --- app/benchmark_fft/main.cpp | 2 +- lib/pls/include/pls/internal/base/alignment.h | 1 - lib/pls/include/pls/internal/data_structures/aligned_stack.h | 24 ++++++++++++++---------- lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h | 6 ++++-- lib/pls/include/pls/internal/data_structures/locking_deque.h | 2 +- lib/pls/include/pls/internal/data_structures/locking_deque_impl.h | 4 ++-- lib/pls/include/pls/internal/data_structures/work_stealing_deque.h | 58 ++++++++++++++++++++++++++-------------------------------- lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------- lib/pls/include/pls/internal/helpers/mini_benchmark.h | 2 +- lib/pls/include/pls/internal/scheduling/scheduler_impl.h | 2 +- lib/pls/include/pls/internal/scheduling/task.h | 32 ++++++++++++++++++++++++-------- lib/pls/src/internal/data_structures/aligned_stack.cpp | 25 ++++++++++++++++--------- lib/pls/src/internal/scheduling/scheduler.cpp | 8 ++++---- lib/pls/src/internal/scheduling/task.cpp | 6 +++--- test/data_structures_test.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------- 15 files changed, 221 insertions(+), 182 deletions(-) diff --git a/app/benchmark_fft/main.cpp b/app/benchmark_fft/main.cpp index 6b41c52..80de92c 100644 --- a/app/benchmark_fft/main.cpp +++ b/app/benchmark_fft/main.cpp @@ -80,7 +80,7 @@ int main() { pls::internal::helpers::run_mini_benchmark([&] { complex_vector input = initial_input; fft(input.begin(), input.size()); - }, 7, 30000); + }, 7, 1000); PROFILE_SAVE("test_profile.prof") } diff --git a/lib/pls/include/pls/internal/base/alignment.h b/lib/pls/include/pls/internal/base/alignment.h index 2d05e07..70aac52 100644 --- a/lib/pls/include/pls/internal/base/alignment.h +++ b/lib/pls/include/pls/internal/base/alignment.h @@ -21,7 +21,6 @@ void *allocate_aligned(size_t size); system_details::pointer_t next_alignment(system_details::pointer_t size); system_details::pointer_t previous_alignment(system_details::pointer_t size); -char *next_alignment(char *pointer); } diff --git a/lib/pls/include/pls/internal/data_structures/aligned_stack.h b/lib/pls/include/pls/internal/data_structures/aligned_stack.h index 133d02d..926ffc5 100644 --- a/lib/pls/include/pls/internal/data_structures/aligned_stack.h +++ b/lib/pls/include/pls/internal/data_structures/aligned_stack.h @@ -27,16 +27,10 @@ using base::system_details::pointer_t; * stack.pop(); // Remove the top object of type T */ class aligned_stack { - // Keep bounds of our memory block - pointer_t memory_start_; - pointer_t memory_end_; - - // Current head will always be aligned to cache lines - pointer_t head_; public: - typedef pointer_t state; + typedef size_t stack_offset; - aligned_stack() : memory_start_{0}, memory_end_{0}, head_{0} {}; + aligned_stack() : aligned_memory_start_{0}, aligned_memory_end_{0}, max_offset_{0}, current_offset_{0} {}; aligned_stack(pointer_t memory_region, std::size_t size); aligned_stack(char *memory_region, std::size_t size); @@ -48,8 +42,18 @@ class aligned_stack { template T pop(); - state save_state() const { return head_; } - void reset_state(state new_state) { head_ = new_state; } + void *memory_at_offset(stack_offset offset) const; + + stack_offset save_offset() const { return current_offset_; } + void reset_offset(stack_offset new_offset) { current_offset_ = new_offset; } + + private: + // Keep bounds of our memory block + pointer_t aligned_memory_start_; + pointer_t aligned_memory_end_; + + stack_offset max_offset_; + stack_offset current_offset_; }; } diff --git a/lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h b/lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h index e04567b..cf500c4 100644 --- a/lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h +++ b/lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h @@ -21,8 +21,10 @@ void *aligned_stack::push_bytes() { template T aligned_stack::pop() { - head_ = head_ - base::alignment::next_alignment(sizeof(T)); - return *reinterpret_cast(head_); + auto num_cache_lines = base::alignment::next_alignment(sizeof(T)) / base::system_details::CACHE_LINE_SIZE; + current_offset_ -= num_cache_lines; + + return *reinterpret_cast(memory_at_offset(current_offset_)); } } diff --git a/lib/pls/include/pls/internal/data_structures/locking_deque.h b/lib/pls/include/pls/internal/data_structures/locking_deque.h index 98b75aa..72e046a 100644 --- a/lib/pls/include/pls/internal/data_structures/locking_deque.h +++ b/lib/pls/include/pls/internal/data_structures/locking_deque.h @@ -48,7 +48,7 @@ class locking_deque { base::spin_lock lock_; public: - using state = aligned_stack::state; + using state = aligned_stack::stack_offset; explicit locking_deque(aligned_stack *stack) : stack_{stack}, head_{nullptr}, tail_{nullptr}, lock_{} {} diff --git a/lib/pls/include/pls/internal/data_structures/locking_deque_impl.h b/lib/pls/include/pls/internal/data_structures/locking_deque_impl.h index 51a4c65..94a9414 100644 --- a/lib/pls/include/pls/internal/data_structures/locking_deque_impl.h +++ b/lib/pls/include/pls/internal/data_structures/locking_deque_impl.h @@ -75,11 +75,11 @@ Item *locking_deque::pop_head() { template void locking_deque::release_memory_until(state state) { - stack_->reset_state(state); + stack_->reset_offset(state); } template typename locking_deque::state locking_deque::save_state() { - return stack_->save_state(); + return stack_->save_offset(); } } diff --git a/lib/pls/include/pls/internal/data_structures/work_stealing_deque.h b/lib/pls/include/pls/internal/data_structures/work_stealing_deque.h index d985632..63c109d 100644 --- a/lib/pls/include/pls/internal/data_structures/work_stealing_deque.h +++ b/lib/pls/include/pls/internal/data_structures/work_stealing_deque.h @@ -17,7 +17,7 @@ using base::system_details::pointer_t; // Integer split into two halfs, can be used in CAS operations using data_structures::stamped_integer; -using offset_t = stamped_integer::member_t; +using deque_offset = stamped_integer::member_t; // Single Item in the deque class work_stealing_deque_item { @@ -29,8 +29,8 @@ class work_stealing_deque_item { // Pointer to the actual data std::atomic data_; // Index (relative to stack base) to the next and previous element - std::atomic next_item_; - offset_t previous_item_; + std::atomic next_item_; + deque_offset previous_item_; public: work_stealing_deque_item() : data_{0}, next_item_{}, previous_item_{} {} @@ -45,54 +45,48 @@ class work_stealing_deque_item { data_ = reinterpret_cast(data); } - offset_t next_item() const { return next_item_.load(); } - void set_next_item(offset_t next_item) { next_item_ = next_item; } + deque_offset next_item() const { return next_item_.load(); } + void set_next_item(deque_offset next_item) { next_item_ = next_item; } - offset_t previous_item() const { return previous_item_; } - void set_previous_item(offset_t previous_item) { previous_item_ = previous_item; } + deque_offset previous_item() const { return previous_item_; } + void set_previous_item(deque_offset previous_item) { previous_item_ = previous_item; } }; -static_assert(sizeof(work_stealing_deque_item) < base::system_details::CACHE_LINE_SIZE, - "Work stealing deque relies on memory layout and requires cache lines to be longer than one 'work_stealing_deque_item' instance!"); -template +template class work_stealing_deque { // Deque 'takes over' stack and handles memory management while in use. // At any point in time the deque can stop using more memory and the stack can be used by other entities. aligned_stack *stack_; - pointer_t base_pointer_; std::atomic head_; - std::atomic tail_; - offset_t previous_tail_; + std::atomic tail_; + deque_offset previous_tail_; - public: - using state = aligned_stack::state; + Task* last_pushed_task_; + public: explicit work_stealing_deque(aligned_stack *stack) : stack_{stack}, - base_pointer_{0}, head_{stamped_integer{0, 0}}, tail_{0}, - previous_tail_{0} { - reset_base_pointer(); - } + previous_tail_{0}, + last_pushed_task_{0} {} template - T *push_tail(ARGS &&... args); - template - T *push_tail_cb(const Function &after_creation, ARGS &&... args); - Item *pop_tail(); - Item *pop_head(); + T *push_task(ARGS &&... args); + template + T *push_object(ARGS &&... args); + void *push_bytes(size_t size); + void publish_last_task(); - void release_memory_until(state state); - state save_state(); + Task *pop_local_task(); + Task *pop_external_task(); - private: - void reset_base_pointer(); - work_stealing_deque_item *item_at(offset_t offset); - offset_t current_stack_offset(); + void reset_offset(deque_offset offset); + deque_offset save_offset(); - template - std::pair *allocate_item(ARGS &&... args); + private: + work_stealing_deque_item *item_at(deque_offset offset); + deque_offset current_stack_offset(); }; } diff --git a/lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h b/lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h index 0730674..415809c 100644 --- a/lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h +++ b/lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h @@ -9,26 +9,23 @@ namespace pls { namespace internal { namespace data_structures { -template -void work_stealing_deque::reset_base_pointer() { - base_pointer_ = reinterpret_cast(stack_->save_state()); // Keep the base of our region in the stack +template +work_stealing_deque_item *work_stealing_deque::item_at(deque_offset offset) { + return reinterpret_cast(stack_->memory_at_offset(offset)); } -template -work_stealing_deque_item *work_stealing_deque::item_at(offset_t offset) { - return reinterpret_cast(base_pointer_ - + (base::system_details::CACHE_LINE_SIZE * offset)); +template +deque_offset work_stealing_deque::current_stack_offset() { + return stack_->save_offset(); } -template -offset_t work_stealing_deque::current_stack_offset() { - return (stack_->save_state() - base_pointer_) / base::system_details::CACHE_LINE_SIZE; -} - -template +template template -std::pair *work_stealing_deque::allocate_item(ARGS &&... args) { - // 'Union' type to push both on stack +T *work_stealing_deque::push_task(ARGS &&... args) { + static_assert(std::is_same::value || std::is_base_of::value, + "Must only push types of onto work_stealing_deque"); + + // 'Union' type to push both the task and the deque entry as one part onto the stack using pair_t = std::pair; // Allocate space on stack auto new_pair = reinterpret_cast(stack_->push_bytes()); @@ -36,43 +33,45 @@ std::pair *work_stealing_deque::allocate_item new((void *) &(new_pair->first)) work_stealing_deque_item(); new((void *) &(new_pair->second)) T(std::forward(args)...); - return new_pair; + // Keep reference for later publishing + last_pushed_task_ = &new_pair->second; + + // Item is not publicly visible until it is published + return &(new_pair->second); } -template +template template -T *work_stealing_deque::push_tail(ARGS &&... args) { - return push_tail_cb([](T *) {}, std::forward(args)...); +T *work_stealing_deque::push_object(ARGS &&... args) { + // Simply add data to the stack, do not publish it in any way + return stack_->push(std::forward(args)...); } -template -template -T *work_stealing_deque::push_tail_cb(const Function &after_creation, ARGS &&... args) { - static_assert(std::is_same::value || std::is_base_of::value, - "Must only push types of onto work_stealing_deque"); - - offset_t local_tail = tail_; +template +void *work_stealing_deque::push_bytes(size_t size) { + // Simply add data to the stack, do not publish it in any way + return stack_->push_bytes(size); +} - auto new_pair = allocate_item(std::forward(args)...); - after_creation(&(new_pair->second)); // callback for time after creation but before being visible to others +template +void work_stealing_deque::publish_last_task() { + deque_offset local_tail = tail_; - // Prepare current tail to point to correct next items + // Prepare current tail to point to correct next task auto tail_deque_item = item_at(local_tail); - tail_deque_item->set_data(&(new_pair->second)); + tail_deque_item->set_data(last_pushed_task_); tail_deque_item->set_next_item(current_stack_offset()); tail_deque_item->set_previous_item(previous_tail_); previous_tail_ = local_tail; - // Linearization point, item appears after this write - offset_t new_tail = current_stack_offset(); + // Linearization point, task appears after this write + deque_offset new_tail = current_stack_offset(); tail_ = new_tail; - - return &(new_pair->second); } -template -Item *work_stealing_deque::pop_tail() { - offset_t local_tail = tail_; +template +Task *work_stealing_deque::pop_local_task() { + deque_offset local_tail = tail_; stamped_integer local_head = head_; if (local_tail <= local_head.value) { @@ -80,7 +79,7 @@ Item *work_stealing_deque::pop_tail() { } work_stealing_deque_item *previous_tail_item = item_at(previous_tail_); - offset_t new_tail = previous_tail_; + deque_offset new_tail = previous_tail_; previous_tail_ = previous_tail_item->previous_item(); // Publish our wish to set the tail back @@ -89,14 +88,14 @@ Item *work_stealing_deque::pop_tail() { local_head = head_; // Linearization point, outside knows list is empty if (local_head.value < new_tail) { - return previous_tail_item->data(); // Success, enough distance to other threads + return previous_tail_item->data(); // Success, enough distance to other threads } if (local_head.value == new_tail) { stamped_integer new_head = stamped_integer{local_head.stamp + 1, new_tail}; // Try competing with consumers by updating the head's stamp value if (head_.compare_exchange_strong(local_head, new_head)) { - return previous_tail_item->data(); // SUCCESS, we won the competition with other threads + return previous_tail_item->data(); // SUCCESS, we won the competition with other threads } } @@ -108,10 +107,10 @@ Item *work_stealing_deque::pop_tail() { return nullptr; // EMPTY, we lost the competition with other threads } -template -Item *work_stealing_deque::pop_head() { +template +Task *work_stealing_deque::pop_external_task() { stamped_integer local_head = head_; - offset_t local_tail = tail_; + deque_offset local_tail = tail_; if (local_tail <= local_head.value) { return nullptr; // EMPTY @@ -121,8 +120,8 @@ Item *work_stealing_deque::pop_head() { // there has to be a competition over the tail -> the stamp increased and our next // operation will fail anyways! work_stealing_deque_item *head_deque_item = item_at(local_head.value); - offset_t next_item_offset = head_deque_item->next_item(); - Item *head_data_item = head_deque_item->data(); + deque_offset next_item_offset = head_deque_item->next_item(); + Task *head_data_item = head_deque_item->data(); // We try to set the head to this new position. // Possible outcomes: @@ -137,26 +136,23 @@ Item *work_stealing_deque::pop_head() { return nullptr; // EMPTY, we lost the competition } -template -void work_stealing_deque::release_memory_until(state state) { - unsigned long item_offset = (state - base_pointer_) / base::system_details::CACHE_LINE_SIZE; +template +void work_stealing_deque::reset_offset(deque_offset offset) { + stack_->reset_offset(offset); stamped_integer local_head = head_; - offset_t local_tail = tail_; - - stack_->reset_state(state); - - if (item_offset < local_tail) { - tail_ = item_offset; + deque_offset local_tail = tail_; + if (offset < local_tail) { + tail_ = offset; if (local_head.value >= local_tail) { - head_ = stamped_integer{local_head.stamp + 1, item_offset}; + head_ = stamped_integer{local_head.stamp + 1, offset}; } } } -template -typename work_stealing_deque::state work_stealing_deque::save_state() { - return stack_->save_state(); +template +deque_offset work_stealing_deque::save_offset() { + return current_stack_offset(); } } diff --git a/lib/pls/include/pls/internal/helpers/mini_benchmark.h b/lib/pls/include/pls/internal/helpers/mini_benchmark.h index 0868cf6..0b7fa63 100644 --- a/lib/pls/include/pls/internal/helpers/mini_benchmark.h +++ b/lib/pls/include/pls/internal/helpers/mini_benchmark.h @@ -21,7 +21,7 @@ void run_mini_benchmark(const Function &lambda, using namespace std; using namespace pls::internal::scheduling; - malloc_scheduler_memory scheduler_memory{max_threads, 2u << 14}; + malloc_scheduler_memory scheduler_memory{max_threads, 2u << 17u}; for (unsigned int num_threads = 1; num_threads <= max_threads; num_threads++) { scheduler local_scheduler{&scheduler_memory, num_threads}; diff --git a/lib/pls/include/pls/internal/scheduling/scheduler_impl.h b/lib/pls/include/pls/internal/scheduling/scheduler_impl.h index 1eb8c95..386a32b 100644 --- a/lib/pls/include/pls/internal/scheduling/scheduler_impl.h +++ b/lib/pls/include/pls/internal/scheduling/scheduler_impl.h @@ -28,7 +28,7 @@ void scheduler::perform_work(Function work_section) { // Do work (see if we can remove this duplicated code) root_task.parent_ = nullptr; - root_task.deque_state_ = my_state->deque_.save_state(); + root_task.deque_offset_ = my_state->deque_.save_offset(); root_task.execute(); work_section_done_ = true; diff --git a/lib/pls/include/pls/internal/scheduling/task.h b/lib/pls/include/pls/internal/scheduling/task.h index 3801d6f..73771f4 100644 --- a/lib/pls/include/pls/internal/scheduling/task.h +++ b/lib/pls/include/pls/internal/scheduling/task.h @@ -24,7 +24,7 @@ class task { task *parent_; // Stack Management (reset stack pointer after wait_for_all() calls) - data_structures::deque::state deque_state_; + data_structures::deque_offset deque_offset_; protected: /* @@ -66,20 +66,36 @@ void task::spawn_child(ARGS &&... args) { ref_count_++; // Push on our deque - thread_state::get()->deque_.push_tail_cb([this](T *item) { - // Assign forced values (for stack and parent management) - item->parent_ = this; - item->finished_construction_ = true; - item->deque_state_ = thread_state::get()->deque_.save_state(); - }, std::forward(args)...); + auto item = thread_state::get()->deque_.push_task(std::forward(args)...); + + // Assign forced values (for stack and parent management) + item->parent_ = this; + item->finished_construction_ = true; + item->deque_offset_ = thread_state::get()->deque_.save_offset(); + + // Make new task visible to others + thread_state::get()->deque_.publish_last_task(); } template void task::spawn_child_and_wait(ARGS &&... args) { static_assert(std::is_base_of::type>::value, "Only pass task subclasses!"); - // TODO: See if we can inline this (avoid counters/deque) while maintaining memory management spawn_child(std::forward(args)...); + // TODO: Check why 'direct spawn' (even when pushing it onto the tas queue) seems to be slower + // (Also check if it even is slower or if it only appears so on our laptop) +// // Push on our deque +// auto task = thread_state::get()->deque_.push_task(std::forward(args)...); +// +// // Assign forced values (for stack and parent management) +// task->parent_ = nullptr; // ...do not assign this to a parent => it will not notify our reference counter +// task->finished_construction_ = true; +// task->deque_offset_ = thread_state::get()->deque_.save_offset(); +// +// // Execute it +// task->execute(); + + // Wait for the rest of the tasks wait_for_all(); } diff --git a/lib/pls/src/internal/data_structures/aligned_stack.cpp b/lib/pls/src/internal/data_structures/aligned_stack.cpp index 269032c..2719462 100644 --- a/lib/pls/src/internal/data_structures/aligned_stack.cpp +++ b/lib/pls/src/internal/data_structures/aligned_stack.cpp @@ -6,21 +6,28 @@ namespace internal { namespace data_structures { aligned_stack::aligned_stack(pointer_t memory_region, const std::size_t size) : - memory_start_{memory_region}, - memory_end_{memory_region + size}, - head_{base::alignment::next_alignment(memory_start_)} {} + aligned_memory_start_{base::alignment::next_alignment(memory_region)}, + aligned_memory_end_{base::alignment::previous_alignment(memory_region + size)}, + max_offset_{(aligned_memory_end_ - aligned_memory_start_) / base::system_details::CACHE_LINE_SIZE}, + current_offset_{0} {} aligned_stack::aligned_stack(char *memory_region, const std::size_t size) : - memory_start_{(pointer_t) memory_region}, - memory_end_{(pointer_t) memory_region + size}, - head_{base::alignment::next_alignment(memory_start_)} {} + aligned_stack((pointer_t) memory_region, size) {} + +void *aligned_stack::memory_at_offset(stack_offset offset) const { + const auto byte_offset = offset * base::system_details::CACHE_LINE_SIZE; + return reinterpret_cast(aligned_memory_start_ + byte_offset); +} void *aligned_stack::push_bytes(size_t size) { - void *result = reinterpret_cast(head_); + size_t round_up_size = base::alignment::next_alignment(size); + size_t num_cache_lines = round_up_size / base::system_details::CACHE_LINE_SIZE; + + void *result = memory_at_offset(current_offset_); // Move head to next aligned position after new object - head_ = base::alignment::next_alignment(head_ + size); - if (head_ >= memory_end_) { + current_offset_ += num_cache_lines; + if (current_offset_ > max_offset_) { PLS_ERROR("Tried to allocate object on alligned_stack without sufficient memory!"); } diff --git a/lib/pls/src/internal/scheduling/scheduler.cpp b/lib/pls/src/internal/scheduling/scheduler.cpp index 9c6d2ce..522908b 100644 --- a/lib/pls/src/internal/scheduling/scheduler.cpp +++ b/lib/pls/src/internal/scheduling/scheduler.cpp @@ -53,7 +53,7 @@ void scheduler::worker_routine() { // Main Thread auto root_task = scheduler->main_thread_root_task_; root_task->parent_ = nullptr; - root_task->deque_state_ = my_state->deque_.save_state(); + root_task->deque_offset_ = my_state->deque_.save_offset(); root_task->execute(); scheduler->work_section_done_ = true; @@ -90,7 +90,7 @@ void scheduler::terminate() { task *scheduler::get_local_task() { PROFILE_STEALING("Get Local Task") - return thread_state::get()->deque_.pop_tail(); + return thread_state::get()->deque_.pop_local_task(); } task *scheduler::steal_task() { @@ -112,7 +112,7 @@ task *scheduler::steal_task() { auto target_state = thread_state_for(target); // TODO: See if we should re-try popping if it failed due to contention - auto result = target_state->deque_.pop_head(); + auto result = target_state->deque_.pop_external_task(); if (result != nullptr) { return result; } @@ -137,7 +137,7 @@ bool scheduler::try_execute_local() { bool scheduler::try_execute_stolen() { task *stolen_task = steal_task(); if (stolen_task != nullptr) { - stolen_task->deque_state_ = thread_state::get()->deque_.save_state(); + stolen_task->deque_offset_ = thread_state::get()->deque_.save_offset(); stolen_task->execute(); return true; } diff --git a/lib/pls/src/internal/scheduling/task.cpp b/lib/pls/src/internal/scheduling/task.cpp index b682203..1b25604 100644 --- a/lib/pls/src/internal/scheduling/task.cpp +++ b/lib/pls/src/internal/scheduling/task.cpp @@ -12,13 +12,13 @@ task::task() : finished_construction_{false}, ref_count_{0}, parent_{nullptr}, - deque_state_{0} {} + deque_offset_{0} {} void *task::allocate_memory(long size) { if (finished_construction_) { PLS_ERROR("Must not allocate dynamic task memory after it's construction.") } - return thread_state::get()->task_stack_->push_bytes(size); + return thread_state::get()->deque_.push_bytes(size); } void task::execute() { @@ -45,7 +45,7 @@ void task::wait_for_all() { scheduler->try_execute_stolen(); } } - thread_state::get()->deque_.release_memory_until(deque_state_); + thread_state::get()->deque_.reset_offset(deque_offset_); } } diff --git a/test/data_structures_test.cpp b/test/data_structures_test.cpp index 4117139..9142b5c 100644 --- a/test/data_structures_test.cpp +++ b/test/data_structures_test.cpp @@ -85,77 +85,98 @@ TEST_CASE("work_stealing_deque functions correctly", "[internal/data_structures/ int one = 1, two = 2, three = 3, four = 4; SECTION("add and remove items form the tail") { - deque.push_tail(one); - deque.push_tail(two); - deque.push_tail(three); - - REQUIRE(*deque.pop_tail() == three); - REQUIRE(*deque.pop_tail() == two); - REQUIRE(*deque.pop_tail() == one); + deque.push_task(one); + deque.publish_last_task(); + deque.push_task(two); + deque.publish_last_task(); + deque.push_task(three); + deque.publish_last_task(); + + REQUIRE(*deque.pop_local_task() == three); + REQUIRE(*deque.pop_local_task() == two); + REQUIRE(*deque.pop_local_task() == one); } SECTION("handles getting empty by popping the tail correctly") { - deque.push_tail(one); - REQUIRE(*deque.pop_tail() == one); + deque.push_task(one); + deque.publish_last_task(); + REQUIRE(*deque.pop_local_task() == one); - deque.push_tail(two); - REQUIRE(*deque.pop_tail() == two); + deque.push_task(two); + deque.publish_last_task(); + REQUIRE(*deque.pop_local_task() == two); } SECTION("remove items form the head") { - deque.push_tail(one); - deque.push_tail(two); - deque.push_tail(three); - - REQUIRE(*deque.pop_head() == one); - REQUIRE(*deque.pop_head() == two); - REQUIRE(*deque.pop_head() == three); + deque.push_task(one); + deque.publish_last_task(); + deque.push_task(two); + deque.publish_last_task(); + deque.push_task(three); + deque.publish_last_task(); + + REQUIRE(*deque.pop_external_task() == one); + REQUIRE(*deque.pop_external_task() == two); + REQUIRE(*deque.pop_external_task() == three); } SECTION("handles getting empty by popping the head correctly") { - deque.push_tail(one); - REQUIRE(*deque.pop_head() == one); + deque.push_task(one); + deque.publish_last_task(); + REQUIRE(*deque.pop_external_task() == one); - deque.push_tail(two); - REQUIRE(*deque.pop_head() == two); + deque.push_task(two); + deque.publish_last_task(); + REQUIRE(*deque.pop_external_task() == two); } SECTION("handles getting empty by popping the head and tail correctly") { - deque.push_tail(one); - REQUIRE(*deque.pop_tail() == one); + deque.push_task(one); + deque.publish_last_task(); + REQUIRE(*deque.pop_local_task() == one); - deque.push_tail(two); - REQUIRE(*deque.pop_head() == two); + deque.push_task(two); + deque.publish_last_task(); + REQUIRE(*deque.pop_external_task() == two); - deque.push_tail(three); - REQUIRE(*deque.pop_tail() == three); + deque.push_task(three); + deque.publish_last_task(); + REQUIRE(*deque.pop_local_task() == three); } SECTION("handles jumps bigger 1 correctly") { - deque.push_tail(one); - deque.push_tail(two); - REQUIRE(*deque.pop_tail() == two); - - deque.push_tail(three); - deque.push_tail(four); - REQUIRE(*deque.pop_head() == one); - REQUIRE(*deque.pop_head() == three); - REQUIRE(*deque.pop_head() == four); + deque.push_task(one); + deque.publish_last_task(); + deque.push_task(two); + deque.publish_last_task(); + REQUIRE(*deque.pop_local_task() == two); + + deque.push_task(three); + deque.publish_last_task(); + deque.push_task(four); + deque.publish_last_task(); + REQUIRE(*deque.pop_external_task() == one); + REQUIRE(*deque.pop_external_task() == three); + REQUIRE(*deque.pop_external_task() == four); } SECTION("handles stack reset 1 correctly when emptied by tail") { - deque.push_tail(one); - auto state = deque.save_state(); - deque.push_tail(two); - REQUIRE(*deque.pop_tail() == two); - - deque.release_memory_until(state); - REQUIRE(*deque.pop_tail() == one); - - deque.push_tail(three); - deque.push_tail(four); - REQUIRE(*deque.pop_head() == three); - REQUIRE(*deque.pop_tail() == four); + deque.push_task(one); + deque.publish_last_task(); + auto state = deque.save_offset(); + deque.push_task(two); + deque.publish_last_task(); + REQUIRE(*deque.pop_local_task() == two); + + deque.reset_offset(state); + REQUIRE(*deque.pop_local_task() == one); + + deque.push_task(three); + deque.publish_last_task(); + deque.push_task(four); + deque.publish_last_task(); + REQUIRE(*deque.pop_external_task() == three); + REQUIRE(*deque.pop_local_task() == four); } } } -- libgit2 0.26.0