Commit 4dadd0cd by Marcus Winter

dataflow_cpp: removed Network::Make for simpler usage, added Network:IsValid to…

dataflow_cpp: removed Network::Make for simpler usage, added Network:IsValid to check network for errors
tutorial: adapted to reflect changes to dataflow_cpp
examples: adapted to reflect changes to dataflow_cpp
parent ed0ecbf4
...@@ -31,20 +31,10 @@ namespace embb { ...@@ -31,20 +31,10 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
class Scheduler;
class ClockListener;
struct InitData {
int slices;
Scheduler * sched;
ClockListener * sink_listener;
};
class ClockListener { class ClockListener {
public: public:
virtual ~ClockListener() {} virtual ~ClockListener() {}
virtual void OnClock(int /*clock*/) = 0; virtual void OnClock(int /*clock*/) = 0;
virtual void OnInit(InitData * /*sched*/) = 0;
}; };
} // namespace internal } // namespace internal
......
...@@ -46,7 +46,10 @@ class ConstantSource ...@@ -46,7 +46,10 @@ class ConstantSource
Type value_; Type value_;
public: public:
explicit ConstantSource(Type value) : value_(value) {} explicit ConstantSource(Network & network, Type value)
: value_(value) {
SetScheduler(network.GetScheduler());
}
virtual bool HasOutputs() const { virtual bool HasOutputs() const {
return outputs_.Size() > 0; return outputs_.Size() > 0;
...@@ -56,9 +59,8 @@ class ConstantSource ...@@ -56,9 +59,8 @@ class ConstantSource
GetOutput<0>().Send(Signal<Type>(clock, value_)); GetOutput<0>().Send(Signal<Type>(clock, value_));
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return outputs_.IsFullyConnected();
GetOutput<0>().SendInit(init_data);
} }
virtual bool Start(int clock) { virtual bool Start(int clock) {
......
...@@ -113,11 +113,6 @@ class In { ...@@ -113,11 +113,6 @@ class In {
lock_.Unlock(); lock_.Unlock();
#endif #endif
} }
void ReceiveInit(InitData * init_data) {
SetSlices(init_data->slices);
listener_->OnInit(init_data);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -56,7 +56,9 @@ class Inputs<embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -56,7 +56,9 @@ class Inputs<embb::base::internal::Nil, embb::base::internal::Nil,
bool AreNoneBlank(int /*clock*/) { return false; } bool AreNoneBlank(int /*clock*/) { return false; }
bool AreAtClock(int /*clock*/) { return true; } bool AreAtClock(int /*clock*/) { return true; }
virtual void OnClock(int /*clock*/) {} virtual void OnClock(int /*clock*/) {}
virtual void OnInit(InitData * /*init_data*/) {} bool IsFullyConnected() {
return true;
}
}; };
template <typename T1> template <typename T1>
...@@ -67,8 +69,14 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -67,8 +69,14 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() : count_(NULL) { explicit Inputs(int slices) : count_(NULL), slices_(slices) {
test_count_ = 1; count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 1;
}
this->template Get<0>().SetSlices(slices_);
} }
~Inputs() { ~Inputs() {
if (NULL != count_) { if (NULL != count_) {
...@@ -98,21 +106,11 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -98,21 +106,11 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { bool IsFullyConnected() {
if (--test_count_ == 0) { return this->template Get<0>().IsConnected();
slices_ = init_data->slices;
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 1;
}
listener_->OnInit(init_data);
}
} }
private: private:
embb::base::Atomic<int> * count_; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_; int slices_;
}; };
...@@ -124,8 +122,15 @@ class Inputs<T1, T2, embb::base::internal::Nil, ...@@ -124,8 +122,15 @@ class Inputs<T1, T2, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() : count_(NULL) { explicit Inputs(int slices) : count_(NULL), slices_(slices) {
test_count_ = 2; count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 2;
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
} }
~Inputs() { ~Inputs() {
if (NULL != count_) { if (NULL != count_) {
...@@ -159,21 +164,12 @@ class Inputs<T1, T2, embb::base::internal::Nil, ...@@ -159,21 +164,12 @@ class Inputs<T1, T2, embb::base::internal::Nil,
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { bool IsFullyConnected() {
if (--test_count_ == 0) { return this->template Get<0>().IsConnected() &
slices_ = init_data->slices; this->template Get<1>().IsConnected();
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 2;
}
listener_->OnInit(init_data);
} }
} private:
private:
embb::base::Atomic<int> * count_; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_; int slices_;
}; };
...@@ -185,8 +181,16 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil, ...@@ -185,8 +181,16 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() : count_(NULL) { explicit Inputs(int slices) : count_(NULL), slices_(slices) {
test_count_ = 3; count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 3;
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_);
} }
~Inputs() { ~Inputs() {
if (NULL != count_) { if (NULL != count_) {
...@@ -224,21 +228,13 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil, ...@@ -224,21 +228,13 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil,
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { bool IsFullyConnected() {
if (--test_count_ == 0) { return this->template Get<0>().IsConnected() &
slices_ = init_data->slices; this->template Get<1>().IsConnected() &
count_ = reinterpret_cast<embb::base::Atomic<int>*>( this->template Get<2>().IsConnected();
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 3;
} }
listener_->OnInit(init_data); private:
}
}
private:
embb::base::Atomic<int> * count_; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_; int slices_;
}; };
...@@ -249,8 +245,17 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil> ...@@ -249,8 +245,17 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
In<T4>, embb::base::internal::Nil> In<T4>, embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() : count_(NULL) { explicit Inputs(int slices) : count_(NULL), slices_(slices) {
test_count_ = 4; count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 4;
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_);
this->template Get<3>().SetSlices(slices_);
} }
~Inputs() { ~Inputs() {
if (NULL != count_) { if (NULL != count_) {
...@@ -292,21 +297,14 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil> ...@@ -292,21 +297,14 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { bool IsFullyConnected() {
if (--test_count_ == 0) { return this->template Get<0>().IsConnected() &
slices_ = init_data->slices; this->template Get<1>().IsConnected() &
count_ = reinterpret_cast<embb::base::Atomic<int>*>( this->template Get<2>().IsConnected() &
embb::base::Allocation::Allocate( this->template Get<3>().IsConnected();
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 4;
}
listener_->OnInit(init_data);
}
} }
private: private:
embb::base::Atomic<int> * count_; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_; int slices_;
}; };
...@@ -318,8 +316,18 @@ class Inputs ...@@ -318,8 +316,18 @@ class Inputs
In<T4>, In<T5> > In<T4>, In<T5> >
, public ClockListener { , public ClockListener {
public: public:
Inputs() : count_(NULL) { explicit Inputs(int slices) : count_(NULL), slices_(slices) {
test_count_ = 5; count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 5;
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_);
this->template Get<3>().SetSlices(slices_);
this->template Get<4>().SetSlices(slices_);
} }
~Inputs() { ~Inputs() {
if (NULL != count_) { if (NULL != count_) {
...@@ -365,21 +373,15 @@ class Inputs ...@@ -365,21 +373,15 @@ class Inputs
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { bool IsFullyConnected() {
if (--test_count_ == 0) { return this->template Get<0>().IsConnected() &&
slices_ = init_data->slices; this->template Get<1>().IsConnected() &
count_ = reinterpret_cast<embb::base::Atomic<int>*>( this->template Get<2>().IsConnected() &
embb::base::Allocation::Allocate( this->template Get<3>().IsConnected() &
sizeof(embb::base::Atomic<int>)*slices_)); this->template Get<4>().IsConnected();
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 5;
}
listener_->OnInit(init_data);
}
} }
private: private:
embb::base::Atomic<int> * count_; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_; int slices_;
}; };
......
...@@ -43,11 +43,11 @@ class Node { ...@@ -43,11 +43,11 @@ class Node {
virtual bool HasInputs() const { return false; } virtual bool HasInputs() const { return false; }
virtual bool HasOutputs() const { return false; } virtual bool HasOutputs() const { return false; }
virtual void Run(int clock) = 0; virtual void Run(int clock) = 0;
virtual bool IsFullyConnected() = 0;
virtual bool Start(int /*clock*/) { virtual bool Start(int /*clock*/) {
EMBB_THROW(embb::base::ErrorException, EMBB_THROW(embb::base::ErrorException,
"Nodes are started implicitly."); "Nodes are started implicitly.");
} }
virtual void Init(InitData * init_data) = 0;
protected: protected:
Scheduler * sched_; Scheduler * sched_;
......
...@@ -52,12 +52,6 @@ class Out { ...@@ -52,12 +52,6 @@ class Out {
} }
} }
void SendInit(InitData * init_data) {
for (size_t ii = 0; ii < targets_.size(); ii++) {
targets_[ii]->ReceiveInit(init_data);
}
}
void Connect(InType & input) { void Connect(InType & input) {
if (input.IsConnected()) { if (input.IsConnected()) {
EMBB_THROW(embb::base::ErrorException, EMBB_THROW(embb::base::ErrorException,
...@@ -72,6 +66,10 @@ class Out { ...@@ -72,6 +66,10 @@ class Out {
Connect(input); Connect(input);
} }
bool IsConnected() const {
return targets_.size() > 0;
}
private: private:
std::vector< InType * > targets_; std::vector< InType * > targets_;
}; };
......
...@@ -50,6 +50,9 @@ class Outputs<embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -50,6 +50,9 @@ class Outputs<embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> { embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return true;
}
}; };
template <typename T1> template <typename T1>
...@@ -59,6 +62,9 @@ class Outputs<T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -59,6 +62,9 @@ class Outputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> { embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected();
}
}; };
template <typename T1, typename T2> template <typename T1, typename T2>
...@@ -67,6 +73,10 @@ class Outputs<T1, T2, embb::base::internal::Nil, ...@@ -67,6 +73,10 @@ class Outputs<T1, T2, embb::base::internal::Nil,
: public Tuple<Out<T1>, Out<T2>, embb::base::internal::Nil, : public Tuple<Out<T1>, Out<T2>, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> { embb::base::internal::Nil, embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected();
}
}; };
template <typename T1, typename T2, typename T3> template <typename T1, typename T2, typename T3>
......
...@@ -53,10 +53,11 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -53,10 +53,11 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
typedef ProcessExecutor< InputsType, OutputsType > ExecutorType; typedef ProcessExecutor< InputsType, OutputsType > ExecutorType;
typedef typename ExecutorType::FunctionType FunctionType; typedef typename ExecutorType::FunctionType FunctionType;
explicit Process(FunctionType function) explicit Process(Network & network, FunctionType function)
: executor_(function) : inputs_(network.GetSlices())
, executor_(function)
, action_(NULL) , action_(NULL)
, slices_(0) { , slices_(network.GetSlices()) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0; queued_clock_ = 0;
bool ordered = Serial; bool ordered = Serial;
...@@ -66,6 +67,13 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -66,6 +67,13 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
queue_id_ = 0; queue_id_ = 0;
} }
inputs_.SetListener(this); inputs_.SetListener(this);
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
SetScheduler(network.GetScheduler());
} }
~Process() { ~Process() {
...@@ -86,17 +94,8 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -86,17 +94,8 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
executor_.Execute(clock, inputs_, outputs_); executor_.Execute(clock, inputs_, outputs_);
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
slices_ = init_data->slices; return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
//inputs_.SetSlices(init_data->slices);
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
SetScheduler(init_data->sched);
executor_.Init(init_data, outputs_);
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -161,10 +160,6 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -161,10 +160,6 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
} }
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
......
...@@ -62,10 +62,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1> > { ...@@ -62,10 +62,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1> > {
} }
} }
void Init(InitData * init_data, Outputs<O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -95,11 +91,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1, O2> > { ...@@ -95,11 +91,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1, O2> > {
} }
} }
void Init(InitData * init_data, Outputs<O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -133,12 +124,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1, O2, O3> > { ...@@ -133,12 +124,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1, O2, O3> > {
} }
} }
void Init(InitData * init_data, Outputs<O1, O2, O3> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -176,13 +161,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1, O2, O3, O4> > { ...@@ -176,13 +161,6 @@ class ProcessExecutor< Inputs<I1>, Outputs<O1, O2, O3, O4> > {
} }
} }
void Init(InitData * init_data, Outputs<O1, O2, O3, O4> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
outputs.template Get<3>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -211,10 +189,6 @@ class ProcessExecutor< Inputs<I1, I2>, Outputs<O1> > { ...@@ -211,10 +189,6 @@ class ProcessExecutor< Inputs<I1, I2>, Outputs<O1> > {
} }
} }
void Init(InitData * init_data, Outputs<O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -246,11 +220,6 @@ class ProcessExecutor< Inputs<I1, I2>, Outputs<O1, O2> > { ...@@ -246,11 +220,6 @@ class ProcessExecutor< Inputs<I1, I2>, Outputs<O1, O2> > {
} }
} }
void Init(InitData * init_data, Outputs<O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -286,12 +255,6 @@ class ProcessExecutor< Inputs<I1, I2>, Outputs<O1, O2, O3> > { ...@@ -286,12 +255,6 @@ class ProcessExecutor< Inputs<I1, I2>, Outputs<O1, O2, O3> > {
} }
} }
void Init(InitData * init_data, Outputs<O1, O2, O3> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -321,10 +284,6 @@ class ProcessExecutor< Inputs<I1, I2, I3>, Outputs<O1> > { ...@@ -321,10 +284,6 @@ class ProcessExecutor< Inputs<I1, I2, I3>, Outputs<O1> > {
} }
} }
void Init(InitData * init_data, Outputs<O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -358,11 +317,6 @@ class ProcessExecutor< Inputs<I1, I2, I3>, Outputs<O1, O2> > { ...@@ -358,11 +317,6 @@ class ProcessExecutor< Inputs<I1, I2, I3>, Outputs<O1, O2> > {
} }
} }
void Init(InitData * init_data, Outputs<O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -394,10 +348,6 @@ class ProcessExecutor< Inputs<I1, I2, I3, I4>, Outputs<O1> > { ...@@ -394,10 +348,6 @@ class ProcessExecutor< Inputs<I1, I2, I3, I4>, Outputs<O1> > {
} }
} }
void Init(InitData * init_data, Outputs<O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
namespace embb { namespace embb {
namespace dataflow { namespace dataflow {
class Network;
namespace internal { namespace internal {
template <typename Type> template <typename Type>
...@@ -44,8 +47,10 @@ class Select ...@@ -44,8 +47,10 @@ class Select
typedef Inputs<bool, Type, Type> InputsType; typedef Inputs<bool, Type, Type> InputsType;
typedef Outputs<Type> OutputsType; typedef Outputs<Type> OutputsType;
Select() { Select(Network & network) : inputs_(network.GetSlices()) {
inputs_.SetListener(this); inputs_.SetListener(this);
slices_ = network.GetSlices();
SetScheduler(network.GetScheduler());
} }
virtual bool HasInputs() const { virtual bool HasInputs() const {
...@@ -80,11 +85,8 @@ class Select ...@@ -80,11 +85,8 @@ class Select
} }
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
slices_ = init_data->slices; return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
//inputs_.SetSlices(slices_);
SetScheduler(init_data->sched);
GetOutput<0>().SendInit(init_data);
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -117,10 +119,6 @@ class Select ...@@ -117,10 +119,6 @@ class Select
Run(clock); Run(clock);
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
......
...@@ -48,13 +48,23 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -48,13 +48,23 @@ class Sink< Inputs<I1, I2, I3, I4, I5> >
typedef SinkExecutor< InputsType > ExecutorType; typedef SinkExecutor< InputsType > ExecutorType;
typedef typename ExecutorType::FunctionType FunctionType; typedef typename ExecutorType::FunctionType FunctionType;
explicit Sink(FunctionType function) explicit Sink(Network & network, FunctionType function)
: executor_(function) : inputs_(network.GetSlices())
, action_(NULL) { , executor_(function)
, action_(NULL)
, slices_(network.GetSlices()) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0; queued_clock_ = 0;
queue_id_ = GetNextProcessID(); queue_id_ = GetNextProcessID();
inputs_.SetListener(this); inputs_.SetListener(this);
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
SetListener(&network);
SetScheduler(network.GetScheduler());
} }
~Sink() { ~Sink() {
...@@ -78,17 +88,8 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -78,17 +88,8 @@ class Sink< Inputs<I1, I2, I3, I4, I5> >
listener_->OnClock(clock); listener_->OnClock(clock);
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
slices_ = init_data->slices; return inputs_.IsFullyConnected();
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
SetListener(init_data->sink_listener);
SetScheduler(init_data->sched);
listener_->OnInit(init_data);
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -132,10 +133,6 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -132,10 +133,6 @@ class Sink< Inputs<I1, I2, I3, I4, I5> >
} }
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
ExecutorType executor_; ExecutorType executor_;
......
...@@ -48,8 +48,9 @@ class Source< Outputs<O1, O2, O3, O4, O5> > ...@@ -48,8 +48,9 @@ class Source< Outputs<O1, O2, O3, O4, O5> >
typedef SourceExecutor< OutputsType > ExecutorType; typedef SourceExecutor< OutputsType > ExecutorType;
typedef typename ExecutorType::FunctionType FunctionType; typedef typename ExecutorType::FunctionType FunctionType;
explicit Source(FunctionType function) explicit Source(Network & network, FunctionType function)
: executor_(function), not_done_(true) { : executor_(function), not_done_(true) {
SetScheduler(network.GetScheduler());
} }
virtual bool HasOutputs() const { virtual bool HasOutputs() const {
...@@ -60,9 +61,8 @@ class Source< Outputs<O1, O2, O3, O4, O5> > ...@@ -60,9 +61,8 @@ class Source< Outputs<O1, O2, O3, O4, O5> >
not_done_ = executor_.Execute(clock, outputs_); not_done_ = executor_.Execute(clock, outputs_);
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return outputs_.IsFullyConnected();
executor_.Init(init_data, outputs_);
} }
virtual bool Start(int clock) { virtual bool Start(int clock) {
......
...@@ -36,8 +36,6 @@ namespace embb { ...@@ -36,8 +36,6 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
class Scheduler;
template <class OUTPUTS> template <class OUTPUTS>
class SourceExecutor; class SourceExecutor;
...@@ -59,10 +57,6 @@ class SourceExecutor< Outputs<O1> > { ...@@ -59,10 +57,6 @@ class SourceExecutor< Outputs<O1> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -87,11 +81,6 @@ class SourceExecutor< Outputs<O1, O2> > { ...@@ -87,11 +81,6 @@ class SourceExecutor< Outputs<O1, O2> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -118,12 +107,6 @@ class SourceExecutor< Outputs<O1, O2, O3> > { ...@@ -118,12 +107,6 @@ class SourceExecutor< Outputs<O1, O2, O3> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<O1, O2, O3> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -152,13 +135,6 @@ class SourceExecutor< Outputs<O1, O2, O3, O4> > { ...@@ -152,13 +135,6 @@ class SourceExecutor< Outputs<O1, O2, O3, O4> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<O1, O2, O3, O4> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
outputs.template Get<3>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
...@@ -190,15 +166,6 @@ class SourceExecutor< Outputs<O1, O2, O3, O4, O5> > { ...@@ -190,15 +166,6 @@ class SourceExecutor< Outputs<O1, O2, O3, O4, O5> > {
return result; return result;
} }
void Init(
InitData * init_data, Outputs<O1, O2, O3, O4, O5> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
outputs.template Get<3>().SendInit(init_data);
outputs.template Get<4>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
namespace embb { namespace embb {
namespace dataflow { namespace dataflow {
class Network;
namespace internal { namespace internal {
template <typename Type> template <typename Type>
...@@ -44,8 +47,9 @@ class Switch ...@@ -44,8 +47,9 @@ class Switch
typedef Inputs<bool, Type> InputsType; typedef Inputs<bool, Type> InputsType;
typedef Outputs<Type, Type> OutputsType; typedef Outputs<Type, Type> OutputsType;
Switch() { Switch(Network & network) : inputs_(network.GetSlices()) {
inputs_.SetListener(this); inputs_.SetListener(this);
SetScheduler(network.GetScheduler());
} }
virtual bool HasInputs() const { virtual bool HasInputs() const {
...@@ -77,11 +81,8 @@ class Switch ...@@ -77,11 +81,8 @@ class Switch
} }
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
//inputs_.SetSlices(init_data->slices); return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
SetScheduler(init_data->sched);
GetOutput<0>().SendInit(init_data);
GetOutput<1>().SendInit(init_data);
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -114,10 +115,6 @@ class Switch ...@@ -114,10 +115,6 @@ class Switch
Run(clock); Run(clock);
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
......
...@@ -42,12 +42,12 @@ ...@@ -42,12 +42,12 @@
typedef embb::dataflow::Network MyNetwork; typedef embb::dataflow::Network MyNetwork;
typedef MyNetwork::ConstantSource< int > MyConstantSource; typedef MyNetwork::ConstantSource< int > MyConstantSource;
typedef MyNetwork::Source< int > MySource; typedef MyNetwork::Source< int > MySource;
typedef MyNetwork::SerialProcess< MyNetwork::Inputs<int>::Type, typedef MyNetwork::SerialProcess< MyNetwork::Inputs<int>,
MyNetwork::Outputs<bool>::Type > MyPred; MyNetwork::Outputs<bool> > MyPred;
typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int>::Type, typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int>,
MyNetwork::Outputs<int>::Type > MyFilter; MyNetwork::Outputs<int> > MyFilter;
typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int, int>::Type, typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int, int>,
MyNetwork::Outputs<int>::Type > MyMult; MyNetwork::Outputs<int> > MyMult;
typedef MyNetwork::Sink< int > MySink; typedef MyNetwork::Sink< int > MySink;
typedef MyNetwork::Switch< int > MySwitch; typedef MyNetwork::Switch< int > MySwitch;
typedef MyNetwork::Select< int > MySelect; typedef MyNetwork::Select< int > MySelect;
...@@ -165,15 +165,15 @@ void SimpleTest::TestBasic() { ...@@ -165,15 +165,15 @@ void SimpleTest::TestBasic() {
for (int ii = 0; ii < 10000; ii++) { for (int ii = 0; ii < 10000; ii++) {
ArraySink<TEST_COUNT> asink; ArraySink<TEST_COUNT> asink;
MyNetwork network; MyNetwork network(NUM_SLICES);
MyConstantSource constant(4); MyConstantSource constant(network, 4);
MySource source(embb::base::MakeFunction(sourceFunc)); MySource source(network, embb::base::MakeFunction(sourceFunc));
MyFilter filter(embb::base::MakeFunction(filterFunc)); MyFilter filter(network, embb::base::MakeFunction(filterFunc));
MyMult mult(embb::base::MakeFunction(multFunc)); MyMult mult(network, embb::base::MakeFunction(multFunc));
MySink sink(embb::base::MakeFunction(asink, &ArraySink<TEST_COUNT>::Run)); MySink sink(network, embb::base::MakeFunction(asink, &ArraySink<TEST_COUNT>::Run));
MyPred pred(embb::base::MakeFunction(predFunc)); MyPred pred(network, embb::base::MakeFunction(predFunc));
MySwitch sw; MySwitch sw(network);
MySelect sel; MySelect sel(network);
for (int kk = 0; kk < TEST_COUNT; kk++) { for (int kk = 0; kk < TEST_COUNT; kk++) {
source_array[kk] = -1; source_array[kk] = -1;
...@@ -208,12 +208,15 @@ void SimpleTest::TestBasic() { ...@@ -208,12 +208,15 @@ void SimpleTest::TestBasic() {
sel.GetOutput<0>() >> sink.GetInput<0>(); sel.GetOutput<0>() >> sink.GetInput<0>();
network.AddSource(constant); // network.AddSource(constant);
network.AddSource(source); // network.AddSource(source);
network.Make(NUM_SLICES); // network.Initialize(NUM_SLICES);
try { try {
if (!network.IsValid()) {
EMBB_THROW(embb::base::ErrorException, "network is invalid");
}
network(); network();
} catch (embb::base::ErrorException & e) { } catch (embb::base::ErrorException & e) {
PT_ASSERT_MSG(false, e.What()); PT_ASSERT_MSG(false, e.What());
......
...@@ -6,15 +6,14 @@ ...@@ -6,15 +6,14 @@
Network::Source<int> Network::Source<int>
source1( source1(
network,
embb::base::MakeFunction(producer1, &Producer<int>::Run) ), embb::base::MakeFunction(producer1, &Producer<int>::Run) ),
source2( source2(
network,
embb::base::MakeFunction(producer2, &Producer<int>::Run) ), embb::base::MakeFunction(producer2, &Producer<int>::Run) ),
source3( source3(
network,
embb::base::MakeFunction(producer3, &Producer<int>::Run) ), embb::base::MakeFunction(producer3, &Producer<int>::Run) ),
source4( source4(
network,
embb::base::MakeFunction(producer4, &Producer<int>::Run) ); embb::base::MakeFunction(producer4, &Producer<int>::Run) );
nw.AddSource(source1);
nw.AddSource(source2);
nw.AddSource(source3);
nw.AddSource(source4);
Network::ParallelProcess< Network::ParallelProcess<
Network::Inputs<std::string>::Type, Network::Inputs<std::string>,
Network::Outputs<std::string>::Type> replace( Network::Outputs<std::string> > replace(
embb::base::MakeFunction(ReplaceFunction) network, embb::base::MakeFunction(ReplaceFunction)
); );
Network::Sink<std::string> write( Network::Sink<std::string> write(
embb::base::MakeFunction(SinkFunction) network, embb::base::MakeFunction(SinkFunction)
); );
Network::Source<std::string> read( Network::Source<std::string> read(
embb::base::MakeFunction(SourceFunction) network, embb::base::MakeFunction(SourceFunction)
); );
...@@ -52,11 +52,10 @@ std::string with("hello"); ...@@ -52,11 +52,10 @@ std::string with("hello");
#include "dataflow/dataflow_sink_function-snippet.h" #include "dataflow/dataflow_sink_function-snippet.h"
void RunDataflowLinear() { void RunDataflowLinear() {
#include "dataflow/dataflow_make-snippet.h"
#include "dataflow/dataflow_declare_source-snippet.h" #include "dataflow/dataflow_declare_source-snippet.h"
#include "dataflow/dataflow_declare_replace-snippet.h" #include "dataflow/dataflow_declare_replace-snippet.h"
#include "dataflow/dataflow_declare_sink-snippet.h" #include "dataflow/dataflow_declare_sink-snippet.h"
#include "dataflow/dataflow_connect-snippet.h" #include "dataflow/dataflow_connect-snippet.h"
#include "dataflow/dataflow_add-snippet.h"
#include "dataflow/dataflow_make-snippet.h"
#include "dataflow/dataflow_run-snippet.h" #include "dataflow/dataflow_run-snippet.h"
} }
typedef embb::dataflow::Network Network; typedef embb::dataflow::Network Network;
static Network nw;
...@@ -48,22 +48,28 @@ static int SimpleRand(int & seed) { ...@@ -48,22 +48,28 @@ static int SimpleRand(int & seed) {
#include "dataflow/dataflow_network-snippet.h" #include "dataflow/dataflow_network-snippet.h"
void RunDataflowNonLinear() { void RunDataflowNonLinear() {
#include "dataflow/dataflow_make-snippet.h"
#include "dataflow/dataflow_declare_add_sources-snippet.h" #include "dataflow/dataflow_declare_add_sources-snippet.h"
Comparator<int> comparator; Comparator<int> comparator;
Network::ParallelProcess< Network::ParallelProcess<
Network::Inputs<int, int>::Type, Network::Outputs<int, int>::Type> Network::Inputs<int, int>, Network::Outputs<int, int> >
process1( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), process1(network,
process2( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process3( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), process2(network,
process4( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process5( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ); process3(network,
embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process4(network,
embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process5(network,
embb::base::MakeFunction(comparator, &Comparator<int>::Run));
Consumer<int> consumer; Consumer<int> consumer;
Network::Sink<int, int, int, int> Network::Sink<int, int, int, int>
sink1(embb::base::MakeFunction(consumer, &Consumer<int>::Run)); sink1(network, embb::base::MakeFunction(consumer, &Consumer<int>::Run));
source1.GetOutput<0>() >> process1.GetInput<0>(); source1.GetOutput<0>() >> process1.GetInput<0>();
source2.GetOutput<0>() >> process2.GetInput<0>(); source2.GetOutput<0>() >> process2.GetInput<0>();
...@@ -83,6 +89,5 @@ void RunDataflowNonLinear() { ...@@ -83,6 +89,5 @@ void RunDataflowNonLinear() {
process5.GetOutput<1>() >> sink1.GetInput<2>(); process5.GetOutput<1>() >> sink1.GetInput<2>();
process4.GetOutput<1>() >> sink1.GetInput<3>(); process4.GetOutput<1>() >> sink1.GetInput<3>();
nw.Make(4); #include "dataflow/dataflow_run-snippet.h"
nw();
} }
...@@ -108,6 +108,10 @@ Then, we have to construct a \emph{network}. A network consists of a set of proc ...@@ -108,6 +108,10 @@ Then, we have to construct a \emph{network}. A network consists of a set of proc
% %
\\\inputlisting{../examples/dataflow/dataflow_network-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_network-snippet.h}
% %
We need to prepare the network for the desired maximum number of elements that can be in the network at a time. The number of elements is limited to avoid that the network is flooded with new elements before the previous elements have been processed. In a linear pipeline, for example, this may happen if the source is faster than the sink. In our example, at most four elements may be processed simultaneously: one in the source, one in the sink, and two in the middle stage (see below). Finding an optimal value depends on the application and usually requires some experimentation. In general, large values boost the throughput but also increase the latency. Conversely, small values reduce the latency but may lead to a drop of performance in terms of throughput:
%
\\\inputlisting{../examples/dataflow/dataflow_make-snippet.h}
%
As the next step, we have to construct the processes shown in Figure~\ref{fig:replace_par}. The easiest way to construct a process is to wrap the user-defined code in a lambda function and to pass it to the network. The network constructs an object for that process and executes the lambda function whenever new data is available. There are several methods for constructing processes depending on their type. The process \textbf{read} is a \emph{source} process, since it produces data (by reading it from the specified file) but does not consume any data. Source processes are constructed from a function object As the next step, we have to construct the processes shown in Figure~\ref{fig:replace_par}. The easiest way to construct a process is to wrap the user-defined code in a lambda function and to pass it to the network. The network constructs an object for that process and executes the lambda function whenever new data is available. There are several methods for constructing processes depending on their type. The process \textbf{read} is a \emph{source} process, since it produces data (by reading it from the specified file) but does not consume any data. Source processes are constructed from a function object
% %
\\\inputlisting{../examples/dataflow/dataflow_source_function-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_source_function-snippet.h}
...@@ -142,19 +146,10 @@ is used to construct the sink: ...@@ -142,19 +146,10 @@ is used to construct the sink:
\emph{\textbf{Note:} If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.} \emph{\textbf{Note:} If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.}
The network needs to know about the source declared above, so we add it to our network:
%
\\\inputlisting{../examples/dataflow/dataflow_add-snippet.h}
%
As the last step, we have to connect the processes (ports). This is straightforward using the C++ stream operator: As the last step, we have to connect the processes (ports). This is straightforward using the C++ stream operator:
% %
\\\inputlisting{../examples/dataflow/dataflow_connect-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_connect-snippet.h}
% %
Once all connections have been established, we need to prepare the network for the desired maximum number of elements that can be in the network at a time. The number of elements is limited to avoid that the network is flooded with new elements before the previous elements have been processed. In a linear pipeline, for example, this may happen if the source is faster than the sink. In our example, at most four elements may be processed simultaneously: one in the source, one in the sink, and two in the middle stage (see above). Finding an optimal value depends on the application and usually requires some experimentation. In general, large values boost the throughput but also increase the latency. Conversely, small values reduce the latency but may lead to a drop of performance in terms of throughput:
%
\\\inputlisting{../examples/dataflow/dataflow_make-snippet.h}
%
Then we can start the network: Then we can start the network:
% %
\\\inputlisting{../examples/dataflow/dataflow_run-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_run-snippet.h}
......
...@@ -41,7 +41,7 @@ namespace { ...@@ -41,7 +41,7 @@ namespace {
static embb::tasks::Node * node_instance = NULL; static embb::tasks::Node * node_instance = NULL;
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if TASKS_CPP_AUTOMATIC_INITIALIZE
static embb::base::Mutex init_mutex; static embb_spinlock_t init_mutex = { 0 };
#endif #endif
} }
...@@ -207,13 +207,13 @@ bool Node::IsInitialized() { ...@@ -207,13 +207,13 @@ bool Node::IsInitialized() {
Node & Node::GetInstance() { Node & Node::GetInstance() {
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if TASKS_CPP_AUTOMATIC_INITIALIZE
if (!IsInitialized()) { if (!IsInitialized()) {
init_mutex.Lock(); embb_spin_lock(&init_mutex);
if (!IsInitialized()) { if (!IsInitialized()) {
Node::Initialize( Node::Initialize(
TASKS_CPP_AUTOMATIC_DOMAIN_ID, TASKS_CPP_AUTOMATIC_NODE_ID); TASKS_CPP_AUTOMATIC_DOMAIN_ID, TASKS_CPP_AUTOMATIC_NODE_ID);
atexit(Node::Finalize); atexit(Node::Finalize);
} }
init_mutex.Unlock(); embb_spin_unlock(&init_mutex);
} }
return *node_instance; return *node_instance;
#else #else
......
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