From 7554679160e9d15e585db8eb9a7a9d82025a25dd Mon Sep 17 00:00:00 2001 From: Marcus Winter Date: Mon, 4 Apr 2016 11:16:29 +0200 Subject: [PATCH] dataflow_cpp: check for cycles in graph --- dataflow_cpp/include/embb/dataflow/internal/clock_listener.h | 1 + dataflow_cpp/include/embb/dataflow/internal/in.h | 4 ++++ dataflow_cpp/include/embb/dataflow/internal/inputs.h | 15 +++++++++++++++ dataflow_cpp/include/embb/dataflow/internal/node.h | 1 + dataflow_cpp/include/embb/dataflow/internal/out.h | 9 +++++++++ dataflow_cpp/include/embb/dataflow/internal/outputs.h | 30 ++++++++++++++++++++++++++++++ dataflow_cpp/include/embb/dataflow/internal/process.h | 13 +++++++++++++ dataflow_cpp/include/embb/dataflow/internal/select.h | 9 +++++++++ dataflow_cpp/include/embb/dataflow/internal/switch.h | 9 +++++++++ dataflow_cpp/include/embb/dataflow/network.h | 17 +++++++++++------ 10 files changed, 102 insertions(+), 6 deletions(-) diff --git a/dataflow_cpp/include/embb/dataflow/internal/clock_listener.h b/dataflow_cpp/include/embb/dataflow/internal/clock_listener.h index f814d5b..d7993b2 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/clock_listener.h +++ b/dataflow_cpp/include/embb/dataflow/internal/clock_listener.h @@ -35,6 +35,7 @@ class ClockListener { public: virtual ~ClockListener() {} virtual void OnClock(int /*clock*/) = 0; + virtual bool OnHasCycle(ClockListener * /*node*/) { return false; } }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/in.h b/dataflow_cpp/include/embb/dataflow/internal/in.h index ec3d476..cb5d6ca 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/in.h +++ b/dataflow_cpp/include/embb/dataflow/internal/in.h @@ -73,6 +73,10 @@ class In { bool IsConnected() const { return connected_; } void SetConnected() { connected_ = true; } + bool HasCycle(ClockListener * node) { + return listener_->OnHasCycle(node); + } + void SetSlices(int slices) { slices_ = slices; values_ = reinterpret_cast( diff --git a/dataflow_cpp/include/embb/dataflow/internal/inputs.h b/dataflow_cpp/include/embb/dataflow/internal/inputs.h index 81282dd..bcbed54 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/inputs.h +++ b/dataflow_cpp/include/embb/dataflow/internal/inputs.h @@ -106,6 +106,9 @@ class InputsOnClock(clock); } } + virtual bool OnHasCycle(ClockListener * node) { + return listener_->OnHasCycle(node); + } bool IsFullyConnected() { return this->template Get<0>().IsConnected(); } @@ -164,6 +167,9 @@ class InputsOnClock(clock); } } + virtual bool OnHasCycle(ClockListener * node) { + return listener_->OnHasCycle(node); + } bool IsFullyConnected() { return this->template Get<0>().IsConnected() & this->template Get<1>().IsConnected(); @@ -228,6 +234,9 @@ class InputsOnClock(clock); } } + virtual bool OnHasCycle(ClockListener * node) { + return listener_->OnHasCycle(node); + } bool IsFullyConnected() { return this->template Get<0>().IsConnected() & this->template Get<1>().IsConnected() & @@ -297,6 +306,9 @@ class Inputs listener_->OnClock(clock); } } + virtual bool OnHasCycle(ClockListener * node) { + return listener_->OnHasCycle(node); + } bool IsFullyConnected() { return this->template Get<0>().IsConnected() & this->template Get<1>().IsConnected() & @@ -373,6 +385,9 @@ class Inputs listener_->OnClock(clock); } } + virtual bool OnHasCycle(ClockListener * node) { + return listener_->OnHasCycle(node); + } bool IsFullyConnected() { return this->template Get<0>().IsConnected() && this->template Get<1>().IsConnected() & diff --git a/dataflow_cpp/include/embb/dataflow/internal/node.h b/dataflow_cpp/include/embb/dataflow/internal/node.h index 5dfebd8..206d56a 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/node.h +++ b/dataflow_cpp/include/embb/dataflow/internal/node.h @@ -44,6 +44,7 @@ class Node { virtual bool HasOutputs() const { return false; } virtual void Run(int clock) = 0; virtual bool IsFullyConnected() = 0; + virtual bool HasCycle() { return false; } virtual bool Start(int /*clock*/) { EMBB_THROW(embb::base::ErrorException, "Nodes are started implicitly."); diff --git a/dataflow_cpp/include/embb/dataflow/internal/out.h b/dataflow_cpp/include/embb/dataflow/internal/out.h index 3f5aea4..72ff3c8 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/out.h +++ b/dataflow_cpp/include/embb/dataflow/internal/out.h @@ -36,6 +36,7 @@ namespace dataflow { namespace internal { class Scheduler; +class ClockListener; template class Out { @@ -70,6 +71,14 @@ class Out { return targets_.size() > 0; } + bool HasCycle(ClockListener * node) { + bool result = false; + for (size_t ii = 0; ii < targets_.size() && !result; ii++) { + result = result || targets_[ii]->HasCycle(node); + } + return result; + } + private: std::vector< InType * > targets_; }; diff --git a/dataflow_cpp/include/embb/dataflow/internal/outputs.h b/dataflow_cpp/include/embb/dataflow/internal/outputs.h index dee7e9d..f969267 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/outputs.h +++ b/dataflow_cpp/include/embb/dataflow/internal/outputs.h @@ -42,6 +42,8 @@ template < typename = embb::base::internal::Nil > class Outputs; +class ClockListener; + template <> class Outputs @@ -65,6 +70,9 @@ class Outputstemplate Get<0>().IsConnected(); } + bool HasCycle(ClockListener * node) { + return this->template Get<0>().HasCycle(node); + } }; template @@ -77,6 +85,10 @@ class Outputstemplate Get<0>().IsConnected() && this->template Get<1>().IsConnected(); } + bool HasCycle(ClockListener * node) { + return this->template Get<0>().HasCycle(node) || + this->template Get<1>().HasCycle(node); + } }; template @@ -90,6 +102,11 @@ class Outputstemplate Get<1>().IsConnected() && this->template Get<2>().IsConnected(); } + bool HasCycle(ClockListener * node) { + return this->template Get<0>().HasCycle(node) || + this->template Get<1>().HasCycle(node) || + this->template Get<2>().HasCycle(node); + } }; template @@ -103,6 +120,12 @@ class Outputs this->template Get<2>().IsConnected() && this->template Get<3>().IsConnected(); } + bool HasCycle(ClockListener * node) { + return this->template Get<0>().HasCycle(node) || + this->template Get<1>().HasCycle(node) || + this->template Get<2>().HasCycle(node) || + this->template Get<3>().HasCycle(node); + } }; template template Get<3>().IsConnected() && this->template Get<4>().IsConnected(); } + bool HasCycle(ClockListener * node) { + return this->template Get<0>().HasCycle(node) || + this->template Get<1>().HasCycle(node) || + this->template Get<2>().HasCycle(node) || + this->template Get<3>().HasCycle(node) || + this->template Get<4>().HasCycle(node); + } }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/process.h b/dataflow_cpp/include/embb/dataflow/internal/process.h index 1dfade2..1b111bf 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/process.h +++ b/dataflow_cpp/include/embb/dataflow/internal/process.h @@ -98,6 +98,10 @@ class Process< Serial, Inputs, return inputs_.IsFullyConnected() && outputs_.IsFullyConnected(); } + virtual bool HasCycle() { + return outputs_.HasCycle(this); + } + InputsType & GetInputs() { return inputs_; } @@ -160,6 +164,15 @@ class Process< Serial, Inputs, } } + virtual bool OnHasCycle(ClockListener * node) { + ClockListener * this_node = this; + if (this_node == node) { + return true; + } else { + return outputs_.HasCycle(node); + } + } + private: InputsType inputs_; OutputsType outputs_; diff --git a/dataflow_cpp/include/embb/dataflow/internal/select.h b/dataflow_cpp/include/embb/dataflow/internal/select.h index c90758f..770591f 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/select.h +++ b/dataflow_cpp/include/embb/dataflow/internal/select.h @@ -85,6 +85,15 @@ class Select return inputs_.IsFullyConnected() && outputs_.IsFullyConnected(); } + virtual bool OnHasCycle(ClockListener * node) { + ClockListener * this_node = this; + if (this_node == node) { + return true; + } else { + return outputs_.HasCycle(node); + } + } + InputsType & GetInputs() { return inputs_; } diff --git a/dataflow_cpp/include/embb/dataflow/internal/switch.h b/dataflow_cpp/include/embb/dataflow/internal/switch.h index db02058..1ce0ccb 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/switch.h +++ b/dataflow_cpp/include/embb/dataflow/internal/switch.h @@ -82,6 +82,15 @@ class Switch return inputs_.IsFullyConnected() && outputs_.IsFullyConnected(); } + virtual bool OnHasCycle(ClockListener * node) { + ClockListener * this_node = this; + if (this_node == node) { + return true; + } else { + return outputs_.HasCycle(node); + } + } + InputsType & GetInputs() { return inputs_; } diff --git a/dataflow_cpp/include/embb/dataflow/network.h b/dataflow_cpp/include/embb/dataflow/network.h index 7a20c58..bb6f3ea 100644 --- a/dataflow_cpp/include/embb/dataflow/network.h +++ b/dataflow_cpp/include/embb/dataflow/network.h @@ -838,14 +838,19 @@ class Network : public internal::ClockListener { bool IsValid() { bool valid = true; - for (size_t ii = 0; ii < sources_.size(); ii++) { - valid = valid & sources_[ii]->IsFullyConnected(); + // check connectivity + for (size_t ii = 0; ii < sources_.size() && valid; ii++) { + valid = valid && sources_[ii]->IsFullyConnected(); } - for (size_t ii = 0; ii < processes_.size(); ii++) { - valid = valid & processes_[ii]->IsFullyConnected(); + for (size_t ii = 0; ii < processes_.size() && valid; ii++) { + valid = valid && processes_[ii]->IsFullyConnected(); } - for (size_t ii = 0; ii < sinks_.size(); ii++) { - valid = valid & sinks_[ii]->IsFullyConnected(); + for (size_t ii = 0; ii < sinks_.size() && valid; ii++) { + valid = valid && sinks_[ii]->IsFullyConnected(); + } + // check for cycles + for (size_t ii = 0; ii < processes_.size() && valid; ii++) { + valid = valid && !processes_[ii]->HasCycle(); } return valid; } -- libgit2 0.26.0