diff --git a/lib/pls/include/pls/dataflow/internal/graph.h b/lib/pls/include/pls/dataflow/internal/graph.h index 0004ed3..67d2a95 100644 --- a/lib/pls/include/pls/dataflow/internal/graph.h +++ b/lib/pls/include/pls/dataflow/internal/graph.h @@ -98,7 +98,7 @@ class graph, outputs> : public node { int num_successors() const override { return 0; } - node *successor_at(int pos) const override { + node *successor_at(int) const override { PLS_ERROR("A graph instance has no direct successor!") } @@ -110,7 +110,7 @@ class graph, outputs> : public node { return sizeof(invocation_memory); } void init_instance_buffer(void *memory) const override { - auto invocation = new(memory) invocation_memory{}; + new(memory) invocation_memory{}; }; private: diff --git a/lib/pls/include/pls/dataflow/internal/in_port.h b/lib/pls/include/pls/dataflow/internal/in_port.h index 8aaace0..981808b 100644 --- a/lib/pls/include/pls/dataflow/internal/in_port.h +++ b/lib/pls/include/pls/dataflow/internal/in_port.h @@ -74,7 +74,7 @@ class multi_in_port : public in_port { using child_type = multi_in_port; using value_type = I0; - explicit multi_in_port(node *owning_node, CB *cb) : in_port{owning_node}, cb_{cb}, rec_{owning_node, cb} {}; + explicit multi_in_port(node *owning_node, CB *cb) : in_port{owning_node}, rec_{owning_node, cb}, cb_{cb} {}; void token_pushed(token token) override { cb_->template token_pushed(token); diff --git a/lib/pls/include/pls/dataflow/internal/out_port.h b/lib/pls/include/pls/dataflow/internal/out_port.h index b499150..f8eb266 100644 --- a/lib/pls/include/pls/dataflow/internal/out_port.h +++ b/lib/pls/include/pls/dataflow/internal/out_port.h @@ -100,7 +100,7 @@ class multi_out_port { template struct next_node { const out_port_tupel_type *outputs_; - node *get(int i) { + node *get(int) { PLS_ERROR("Try to access invalid successor node index!") } }; diff --git a/lib/pls/include/pls/dataflow/internal/split_node.h b/lib/pls/include/pls/dataflow/internal/split_node.h index 09d106d..c0956d2 100644 --- a/lib/pls/include/pls/dataflow/internal/split_node.h +++ b/lib/pls/include/pls/dataflow/internal/split_node.h @@ -57,8 +57,8 @@ class split_node : public node { int instance_buffer_size() const override { return 0; } - void init_instance_buffer(void *memory) const override { - // No need for memory, we simply forward + void init_instance_buffer(void *) const override { + // No need for memory, we simply forward entries without buffering }; private: diff --git a/lib/pls/include/pls/internal/data_structures/deque.h b/lib/pls/include/pls/internal/data_structures/deque.h index f8a3f39..5f90a41 100644 --- a/lib/pls/include/pls/internal/data_structures/deque.h +++ b/lib/pls/include/pls/internal/data_structures/deque.h @@ -9,8 +9,8 @@ namespace pls { namespace internal { namespace data_structures { -template -using deque = work_stealing_deque; +template +using deque = work_stealing_deque; } } 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 72e046a..73caa68 100644 --- a/lib/pls/include/pls/internal/data_structures/locking_deque.h +++ b/lib/pls/include/pls/internal/data_structures/locking_deque.h @@ -11,6 +11,8 @@ namespace pls { namespace internal { namespace data_structures { +using deque_offset = aligned_stack::stack_offset; + /** * Wraps any object into a deque item. */ @@ -45,23 +47,26 @@ class locking_deque { locking_deque_item *head_; locking_deque_item *tail_; + locking_deque_item *last_inserted_; + base::spin_lock lock_; public: - using state = aligned_stack::stack_offset; - explicit locking_deque(aligned_stack *stack) : stack_{stack}, head_{nullptr}, tail_{nullptr}, lock_{} {} template - T *push_tail(ARGS &&... args); - template - T *push_tail_cb(const Function &after_creation, ARGS &&... args); - Item *pop_tail(); - Item *pop_head(); - - void release_memory_until(state state); - state save_state(); + T *push_task(ARGS &&... args); + template + T *push_object(ARGS &&... args); + void *push_bytes(size_t size); + void publish_last_task(); + + Item *pop_local_task(); + Item *pop_external_task(); + + void reset_offset(deque_offset state); + deque_offset save_offset(); }; } 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 94a9414..7657fcf 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 @@ -6,37 +6,52 @@ namespace pls { namespace internal { namespace data_structures { -template +template template -T *locking_deque::push_tail(ARGS &&... args) { - return push_tail_cb([](T *) {}, std::forward(args)...); +T *locking_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"); + + // Allocate object + auto deque_item = stack_->push>(std::forward(args)...); + deque_item->item_ = &deque_item->content_; + + // Keep for later publishing + last_inserted_ = deque_item; + + // ...actual data reference + return &deque_item->content_; } -template -template -T *locking_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"); +template +template +T *locking_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 +void *locking_deque::push_bytes(size_t size) { + // Simply add data to the stack, do not publish it in any way + return stack_->push_bytes(size); +} +template +void locking_deque::publish_last_task() { std::lock_guard lock{lock_}; - auto deque_item = stack_->push>(std::forward(args)...); - deque_item->item_ = &deque_item->content_; - after_creation(&deque_item->content_); if (tail_ != nullptr) { - tail_->next_ = deque_item; + tail_->next_ = last_inserted_; } else { - head_ = deque_item; + head_ = last_inserted_; } - deque_item->prev_ = tail_; - deque_item->next_ = nullptr; - tail_ = deque_item; - - return &deque_item->content_; + last_inserted_->prev_ = tail_; + last_inserted_->next_ = nullptr; + tail_ = last_inserted_; } -template -Item *locking_deque::pop_tail() { +template +Task *locking_deque::pop_local_task() { std::lock_guard lock{lock_}; if (tail_ == nullptr) { @@ -54,8 +69,8 @@ Item *locking_deque::pop_tail() { return result->item_; } -template -Item *locking_deque::pop_head() { +template +Task *locking_deque::pop_external_task() { std::lock_guard lock{lock_}; if (head_ == nullptr) { @@ -73,12 +88,13 @@ Item *locking_deque::pop_head() { return result->item_; } -template -void locking_deque::release_memory_until(state state) { +template +void locking_deque::reset_offset(deque_offset state) { stack_->reset_offset(state); } -template -typename locking_deque::state locking_deque::save_state() { + +template +deque_offset locking_deque::save_offset() { return stack_->save_offset(); } diff --git a/test/data_structures_test.cpp b/test/data_structures_test.cpp index 9142b5c..02932e3 100644 --- a/test/data_structures_test.cpp +++ b/test/data_structures_test.cpp @@ -191,77 +191,98 @@ TEST_CASE("locking_deque functions correctly", "[internal/data_structures/lockin 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); + 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_tail() == three); - REQUIRE(*deque.pop_tail() == two); - REQUIRE(*deque.pop_tail() == one); + 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); + 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_head() == one); - REQUIRE(*deque.pop_head() == two); - REQUIRE(*deque.pop_head() == three); + 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); } } }