Commit 646ed8e0 by Marcus Winter

Merge branch 'development' into embb458_mtapi_initialization

# Conflicts:
#	dataflow_cpp/include/embb/dataflow/internal/scheduler_mtapi.h
parents f304e139 8e973926
Embedded Multicore Building Blocks (EMB²) Embedded Multicore Building Blocks (EMB²)
========================================= =========================================
......
...@@ -35,6 +35,7 @@ class ClockListener { ...@@ -35,6 +35,7 @@ class ClockListener {
public: public:
virtual ~ClockListener() {} virtual ~ClockListener() {}
virtual void OnClock(int /*clock*/) = 0; virtual void OnClock(int /*clock*/) = 0;
virtual bool OnHasCycle(ClockListener * /*node*/) { return false; }
}; };
} // namespace internal } // namespace internal
......
...@@ -73,8 +73,20 @@ class In { ...@@ -73,8 +73,20 @@ class In {
bool IsConnected() const { return connected_; } bool IsConnected() const { return connected_; }
void SetConnected() { connected_ = true; } void SetConnected() { connected_ = true; }
bool HasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
void SetSlices(int slices) { void SetSlices(int slices) {
if (0 < slices_) {
for (int ii = 0; ii < slices_; ii++) {
values_[ii].~SignalType();
}
embb::base::Allocation::Free(values_);
values_ = NULL;
}
slices_ = slices; slices_ = slices;
if (0 < slices_) {
values_ = reinterpret_cast<SignalType*>( values_ = reinterpret_cast<SignalType*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(SignalType)*slices_)); sizeof(SignalType)*slices_));
...@@ -82,6 +94,7 @@ class In { ...@@ -82,6 +94,7 @@ class In {
new (&values_[ii]) SignalType(); new (&values_[ii]) SignalType();
} }
} }
}
void SetListener(ClockListener * listener) { listener_ = listener; } void SetListener(ClockListener * listener) { listener_ = listener; }
......
...@@ -59,6 +59,7 @@ class Inputs<embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -59,6 +59,7 @@ class Inputs<embb::base::internal::Nil, embb::base::internal::Nil,
bool IsFullyConnected() { bool IsFullyConnected() {
return true; return true;
} }
void SetSlices(int /*slices*/) {}
}; };
template <typename T1> template <typename T1>
...@@ -69,13 +70,23 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -69,13 +70,23 @@ 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:
explicit Inputs(int slices) : count_(NULL), slices_(slices) { Inputs() : count_(NULL), slices_(0) {
// empty
}
void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>( count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_)); sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) { for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 1; count_[ii] = 1;
} }
}
this->template Get<0>().SetSlices(slices_); this->template Get<0>().SetSlices(slices_);
} }
~Inputs() { ~Inputs() {
...@@ -106,6 +117,9 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -106,6 +117,9 @@ class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() { bool IsFullyConnected() {
return this->template Get<0>().IsConnected(); return this->template Get<0>().IsConnected();
} }
...@@ -122,13 +136,23 @@ class Inputs<T1, T2, embb::base::internal::Nil, ...@@ -122,13 +136,23 @@ 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:
explicit Inputs(int slices) : count_(NULL), slices_(slices) { Inputs() : count_(NULL), slices_(0) {
// empty
}
void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>( count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_)); sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) { for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 2; count_[ii] = 2;
} }
}
this->template Get<0>().SetSlices(slices_); this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_); this->template Get<1>().SetSlices(slices_);
} }
...@@ -164,6 +188,9 @@ class Inputs<T1, T2, embb::base::internal::Nil, ...@@ -164,6 +188,9 @@ class Inputs<T1, T2, embb::base::internal::Nil,
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() { bool IsFullyConnected() {
return this->template Get<0>().IsConnected() & return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected(); this->template Get<1>().IsConnected();
...@@ -181,13 +208,23 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil, ...@@ -181,13 +208,23 @@ 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:
explicit Inputs(int slices) : count_(NULL), slices_(slices) { Inputs() : count_(NULL), slices_(0) {
// empty
}
void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>( count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_)); sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) { for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 3; count_[ii] = 3;
} }
}
this->template Get<0>().SetSlices(slices_); this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_); this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_); this->template Get<2>().SetSlices(slices_);
...@@ -228,6 +265,9 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil, ...@@ -228,6 +265,9 @@ class Inputs<T1, T2, T3, embb::base::internal::Nil,
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() { bool IsFullyConnected() {
return this->template Get<0>().IsConnected() & return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected() & this->template Get<1>().IsConnected() &
...@@ -245,13 +285,23 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil> ...@@ -245,13 +285,23 @@ 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:
explicit Inputs(int slices) : count_(NULL), slices_(slices) { Inputs() : count_(NULL), slices_(0) {
// empty
}
void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>( count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_)); sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) { for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 4; count_[ii] = 4;
} }
}
this->template Get<0>().SetSlices(slices_); this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_); this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_); this->template Get<2>().SetSlices(slices_);
...@@ -297,6 +347,9 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil> ...@@ -297,6 +347,9 @@ class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() { bool IsFullyConnected() {
return this->template Get<0>().IsConnected() & return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected() & this->template Get<1>().IsConnected() &
...@@ -316,13 +369,23 @@ class Inputs ...@@ -316,13 +369,23 @@ class Inputs
In<T4>, In<T5> > In<T4>, In<T5> >
, public ClockListener { , public ClockListener {
public: public:
explicit Inputs(int slices) : count_(NULL), slices_(slices) { Inputs() : count_(NULL), slices_(0) {
// empty
}
void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>( count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_)); sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) { for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 5; count_[ii] = 5;
} }
}
this->template Get<0>().SetSlices(slices_); this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_); this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_); this->template Get<2>().SetSlices(slices_);
...@@ -373,6 +436,9 @@ class Inputs ...@@ -373,6 +436,9 @@ class Inputs
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual bool OnHasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
bool IsFullyConnected() { bool IsFullyConnected() {
return this->template Get<0>().IsConnected() && return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() & this->template Get<1>().IsConnected() &
......
...@@ -44,17 +44,27 @@ class Node { ...@@ -44,17 +44,27 @@ class Node {
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 IsFullyConnected() = 0;
virtual bool IsSequential() { return true; }
virtual bool HasCycle() { return false; }
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.");
} }
void SetScheduler(Scheduler * sched) {
sched_ = sched;
if (NULL != sched_) {
SetSlices(sched_->GetSlices());
} else {
SetSlices(0);
}
}
protected: protected:
Scheduler * sched_; Scheduler * sched_;
static int next_process_id_; static int next_process_id_;
void SetScheduler(Scheduler * sched) { sched_ = sched; }
static int GetNextProcessID() { return next_process_id_++; } static int GetNextProcessID() { return next_process_id_++; }
virtual void SetSlices(int /*slices*/) {}
}; };
} // namespace internal } // namespace internal
......
...@@ -36,6 +36,7 @@ namespace dataflow { ...@@ -36,6 +36,7 @@ namespace dataflow {
namespace internal { namespace internal {
class Scheduler; class Scheduler;
class ClockListener;
template <typename Type> template <typename Type>
class Out { class Out {
...@@ -70,6 +71,14 @@ class Out { ...@@ -70,6 +71,14 @@ class Out {
return targets_.size() > 0; 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: private:
std::vector< InType * > targets_; std::vector< InType * > targets_;
}; };
......
...@@ -42,6 +42,8 @@ template < ...@@ -42,6 +42,8 @@ template <
typename = embb::base::internal::Nil > typename = embb::base::internal::Nil >
class Outputs; class Outputs;
class ClockListener;
template <> template <>
class Outputs<embb::base::internal::Nil, embb::base::internal::Nil, 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,
...@@ -53,6 +55,9 @@ class Outputs<embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -53,6 +55,9 @@ class Outputs<embb::base::internal::Nil, embb::base::internal::Nil,
bool IsFullyConnected() { bool IsFullyConnected() {
return true; return true;
} }
bool HasCycle(ClockListener * /*node*/) {
return false;
}
}; };
template <typename T1> template <typename T1>
...@@ -65,6 +70,9 @@ class Outputs<T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -65,6 +70,9 @@ class Outputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
bool IsFullyConnected() { bool IsFullyConnected() {
return this->template Get<0>().IsConnected(); return this->template Get<0>().IsConnected();
} }
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node);
}
}; };
template <typename T1, typename T2> template <typename T1, typename T2>
...@@ -77,6 +85,10 @@ class Outputs<T1, T2, embb::base::internal::Nil, ...@@ -77,6 +85,10 @@ class Outputs<T1, T2, embb::base::internal::Nil,
return this->template Get<0>().IsConnected() && return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected(); this->template Get<1>().IsConnected();
} }
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node);
}
}; };
template <typename T1, typename T2, typename T3> template <typename T1, typename T2, typename T3>
...@@ -85,6 +97,16 @@ class Outputs<T1, T2, T3, embb::base::internal::Nil, ...@@ -85,6 +97,16 @@ class Outputs<T1, T2, T3, embb::base::internal::Nil,
: public Tuple<Out<T1>, Out<T2>, Out<T3>, : public Tuple<Out<T1>, Out<T2>, Out<T3>,
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() &&
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 <typename T1, typename T2, typename T3, typename T4> template <typename T1, typename T2, typename T3, typename T4>
...@@ -92,6 +114,18 @@ class Outputs<T1, T2, T3, T4, embb::base::internal::Nil> ...@@ -92,6 +114,18 @@ class Outputs<T1, T2, T3, T4, embb::base::internal::Nil>
: public Tuple<Out<T1>, Out<T2>, Out<T3>, : public Tuple<Out<T1>, Out<T2>, Out<T3>,
Out<T4>, embb::base::internal::Nil>{ Out<T4>, embb::base::internal::Nil>{
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &&
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 <typename T1, typename T2, typename T3, typename T4, template <typename T1, typename T2, typename T3, typename T4,
...@@ -100,6 +134,20 @@ class Outputs ...@@ -100,6 +134,20 @@ class Outputs
: public Tuple<Out<T1>, Out<T2>, Out<T3>, : public Tuple<Out<T1>, Out<T2>, Out<T3>,
Out<T4>, Out<T5> > { Out<T4>, Out<T5> > {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &&
this->template Get<2>().IsConnected() &&
this->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 } // namespace internal
......
...@@ -53,11 +53,11 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -53,11 +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;
Process(int slices, Scheduler * sched, FunctionType function) Process(Scheduler * sched, FunctionType function)
: inputs_(slices) : inputs_()
, executor_(function) , executor_(function)
, action_(NULL) , action_(NULL)
, slices_(slices) { , slices_(0) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0; queued_clock_ = 0;
bool ordered = Serial; bool ordered = Serial;
...@@ -67,12 +67,6 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -67,12 +67,6 @@ 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(sched); SetScheduler(sched);
} }
...@@ -98,6 +92,14 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -98,6 +92,14 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
return inputs_.IsFullyConnected() && outputs_.IsFullyConnected(); return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
} }
virtual bool IsSequential() {
return Serial;
}
virtual bool HasCycle() {
return outputs_.HasCycle(this);
}
InputsType & GetInputs() { InputsType & GetInputs() {
return inputs_; return inputs_;
} }
...@@ -160,6 +162,15 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -160,6 +162,15 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
} }
} }
virtual bool OnHasCycle(ClockListener * node) {
ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
}
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
...@@ -169,6 +180,23 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -169,6 +180,23 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
embb::base::Atomic<int> queued_clock_; embb::base::Atomic<int> queued_clock_;
int queue_id_; int queue_id_;
int slices_; int slices_;
virtual void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(action_);
action_ = NULL;
}
slices_ = slices;
inputs_.SetSlices(slices);
if (0 < slices_) {
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
}
}
}; };
} // namespace internal } // namespace internal
......
...@@ -40,6 +40,7 @@ class Scheduler { ...@@ -40,6 +40,7 @@ class Scheduler {
virtual void Start(Action & action) = 0; virtual void Start(Action & action) = 0;
virtual void Enqueue(int process_id, Action & action) = 0; virtual void Enqueue(int process_id, Action & action) = 0;
virtual void WaitForSlice(int slice) = 0; virtual void WaitForSlice(int slice) = 0;
virtual int GetSlices() = 0;
}; };
} // namespace internal } // namespace internal
......
...@@ -46,6 +46,13 @@ class SchedulerMTAPI : public Scheduler { ...@@ -46,6 +46,13 @@ class SchedulerMTAPI : public Scheduler {
: slices_(slices) { : slices_(slices) {
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
int tl = std::min(
static_cast<int>(node.GetTaskLimit()),
static_cast<int>(node.GetGroupCount()));
if (tl < slices_) {
slices_ = tl;
}
job_ = node.GetJob(EMBB_DATAFLOW_JOB_ID); job_ = node.GetJob(EMBB_DATAFLOW_JOB_ID);
action_ = node.CreateAction(EMBB_DATAFLOW_JOB_ID, SchedulerMTAPI::action_func); action_ = node.CreateAction(EMBB_DATAFLOW_JOB_ID, SchedulerMTAPI::action_func);
...@@ -103,6 +110,7 @@ class SchedulerMTAPI : public Scheduler { ...@@ -103,6 +110,7 @@ class SchedulerMTAPI : public Scheduler {
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
group_[slice] = node.CreateGroup(); group_[slice] = node.CreateGroup();
} }
virtual int GetSlices() { return slices_; }
private: private:
static void action_func( static void action_func(
......
...@@ -45,6 +45,7 @@ class SchedulerSequential : public Scheduler { ...@@ -45,6 +45,7 @@ class SchedulerSequential : public Scheduler {
action.RunSequential(); action.RunSequential();
} }
virtual void WaitForSlice(int /*slice*/) {} virtual void WaitForSlice(int /*slice*/) {}
virtual int GetSlices() { return 1; }
}; };
} // namespace internal } // namespace internal
......
...@@ -44,7 +44,7 @@ class Select ...@@ -44,7 +44,7 @@ class Select
typedef Inputs<bool, Type, Type> InputsType; typedef Inputs<bool, Type, Type> InputsType;
typedef Outputs<Type> OutputsType; typedef Outputs<Type> OutputsType;
Select(int slices, Scheduler * sched) : inputs_(slices), slices_(slices) { explicit Select(Scheduler * sched) : inputs_(), slices_(0) {
inputs_.SetListener(this); inputs_.SetListener(this);
SetScheduler(sched); SetScheduler(sched);
} }
...@@ -85,6 +85,15 @@ class Select ...@@ -85,6 +85,15 @@ class Select
return inputs_.IsFullyConnected() && outputs_.IsFullyConnected(); 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() { InputsType & GetInputs() {
return inputs_; return inputs_;
} }
...@@ -119,6 +128,11 @@ class Select ...@@ -119,6 +128,11 @@ class Select
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
int slices_; int slices_;
virtual void SetSlices(int slices) {
slices_ = slices;
inputs_.SetSlices(slices);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -48,23 +48,17 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -48,23 +48,17 @@ 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;
Sink(int slices, Scheduler * sched, ClockListener * listener, Sink(Scheduler * sched, ClockListener * listener,
FunctionType function) FunctionType function)
: inputs_(slices) : inputs_()
, executor_(function) , executor_(function)
, action_(NULL) , action_(NULL)
, slices_(slices) { , slices_(0) {
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*>( listener_ = listener;
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
SetListener(listener);
SetScheduler(sched); SetScheduler(sched);
} }
...@@ -74,10 +68,6 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -74,10 +68,6 @@ class Sink< Inputs<I1, I2, I3, I4, I5> >
} }
} }
void SetListener(ClockListener * listener) {
listener_ = listener;
}
virtual bool HasInputs() const { virtual bool HasInputs() const {
return inputs_.Size() > 0; return inputs_.Size() > 0;
} }
...@@ -143,6 +133,23 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -143,6 +133,23 @@ class Sink< Inputs<I1, I2, I3, I4, I5> >
embb::base::Atomic<int> queued_clock_; embb::base::Atomic<int> queued_clock_;
int queue_id_; int queue_id_;
int slices_; int slices_;
virtual void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(action_);
action_ = NULL;
}
slices_ = slices;
inputs_.SetSlices(slices);
if (0 < slices_) {
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
}
}
}; };
} // namespace internal } // namespace internal
......
...@@ -44,7 +44,7 @@ class Switch ...@@ -44,7 +44,7 @@ class Switch
typedef Inputs<bool, Type> InputsType; typedef Inputs<bool, Type> InputsType;
typedef Outputs<Type, Type> OutputsType; typedef Outputs<Type, Type> OutputsType;
Switch(int slices, Scheduler * sched) : inputs_(slices) { explicit Switch(Scheduler * sched) : inputs_() {
inputs_.SetListener(this); inputs_.SetListener(this);
SetScheduler(sched); SetScheduler(sched);
} }
...@@ -82,6 +82,15 @@ class Switch ...@@ -82,6 +82,15 @@ class Switch
return inputs_.IsFullyConnected() && outputs_.IsFullyConnected(); 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() { InputsType & GetInputs() {
return inputs_; return inputs_;
} }
...@@ -115,6 +124,10 @@ class Switch ...@@ -115,6 +124,10 @@ class Switch
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
virtual void SetSlices(int slices) {
inputs_.SetSlices(slices);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -58,6 +58,14 @@ class Network { ...@@ -58,6 +58,14 @@ class Network {
public: public:
/** /**
* Constructs an empty network. * Constructs an empty network.
* \note The number of concurrent tokens will automatically be derived from
* the structure of the network on the first call to operator(), and the
* corresponding resources will be allocated then.
*/
Network() {}
/**
* Constructs an empty network.
* \param slices Number of concurrent tokens allowed in the network. * \param slices Number of concurrent tokens allowed in the network.
*/ */
explicit Network(int slices) {} explicit Network(int slices) {}
...@@ -668,11 +676,19 @@ class Network { ...@@ -668,11 +676,19 @@ class Network {
/** /**
* Checks whether the network is completely connected and free of cycles. * Checks whether the network is completely connected and free of cycles.
* \returns \c true if everything is in order, \c false if not. * \returns \c true if everything is in order, \c false if not.
* \note Executing an invalid network results in an exception. For this
* reason, it is recommended to first check the network using IsValid().
*/ */
bool IsValid(); bool IsValid();
/** /**
* Executes the network until one of the the sources returns \c false. * Executes the network until one of the the sources returns \c false.
* \note If the network was default constructed, the number of concurrent
* tokens will automatically be derived from the structure of the network
* on the first call of the operator, and the corresponding resources will
* be allocated then.
* \note Executing an invalid network results in an exception. For this
* reason, it is recommended to first check the network using IsValid().
*/ */
void operator () (); void operator () ();
}; };
...@@ -681,16 +697,14 @@ class Network { ...@@ -681,16 +697,14 @@ class Network {
class Network : public internal::ClockListener { class Network : public internal::ClockListener {
public: public:
explicit Network(int slices) Network()
: sink_counter_(NULL), slices_(slices), sched_(NULL) { : sink_counter_(NULL), sink_count_(0), slices_(0), sched_(NULL) {
sched_ = embb::base::Allocation::New<internal::SchedulerMTAPI>(slices_); // empty
sink_counter_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
sink_counter_[ii] = 0;
} }
sink_count_ = 0;
explicit Network(int slices)
: sink_counter_(NULL), sink_count_(0), slices_(slices), sched_(NULL) {
PrepareSlices();
} }
~Network() { ~Network() {
...@@ -704,24 +718,22 @@ class Network : public internal::ClockListener { ...@@ -704,24 +718,22 @@ class Network : public internal::ClockListener {
} }
} }
template <typename T1, typename T2 = embb::base::internal::Nil, template <typename T1,
typename T2 = embb::base::internal::Nil,
typename T3 = embb::base::internal::Nil, typename T3 = embb::base::internal::Nil,
typename T4 = embb::base::internal::Nil, typename T4 = embb::base::internal::Nil,
typename T5 = embb::base::internal::Nil> typename T5 = embb::base::internal::Nil>
class Inputs : public internal::Inputs<T1, T2, T3, T4, T5> { class Inputs {
public: // empty
explicit Inputs(int slices)
: internal::Inputs<T1, T2, T3, T4, T5>(slices) {}
}; };
template <typename T1, typename T2 = embb::base::internal::Nil, template <typename T1,
typename T2 = embb::base::internal::Nil,
typename T3 = embb::base::internal::Nil, typename T3 = embb::base::internal::Nil,
typename T4 = embb::base::internal::Nil, typename T4 = embb::base::internal::Nil,
typename T5 = embb::base::internal::Nil> typename T5 = embb::base::internal::Nil>
class Outputs : public internal::Outputs<T1, T2, T3, T4, T5> { class Outputs {
public: // empty
Outputs()
: internal::Outputs<T1, T2, T3, T4, T5>() {}
}; };
template <class Inputs, class Outputs> class SerialProcess; template <class Inputs, class Outputs> class SerialProcess;
...@@ -743,7 +755,7 @@ class Network : public internal::ClockListener { ...@@ -743,7 +755,7 @@ class Network : public internal::ClockListener {
: internal::Process< true, : internal::Process< true,
internal::Inputs<I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<O1, O2, O3, O4, O5> >( internal::Outputs<O1, O2, O3, O4, O5> >(
network.slices_, network.sched_, function) { network.sched_, function) {
network.processes_.push_back(this); network.processes_.push_back(this);
} }
}; };
...@@ -767,7 +779,7 @@ class Network : public internal::ClockListener { ...@@ -767,7 +779,7 @@ class Network : public internal::ClockListener {
: internal::Process< false, : internal::Process< false,
internal::Inputs<I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<O1, O2, O3, O4, O5> >( internal::Outputs<O1, O2, O3, O4, O5> >(
network.slices_, network.sched_, function) { network.sched_, function) {
network.processes_.push_back(this); network.processes_.push_back(this);
} }
}; };
...@@ -776,7 +788,7 @@ class Network : public internal::ClockListener { ...@@ -776,7 +788,7 @@ class Network : public internal::ClockListener {
class Switch : public internal::Switch<Type> { class Switch : public internal::Switch<Type> {
public: public:
explicit Switch(Network & network) explicit Switch(Network & network)
: internal::Switch<Type>(network.slices_, network.sched_) { : internal::Switch<Type>(network.sched_) {
network.processes_.push_back(this); network.processes_.push_back(this);
} }
}; };
...@@ -785,7 +797,7 @@ class Network : public internal::ClockListener { ...@@ -785,7 +797,7 @@ class Network : public internal::ClockListener {
class Select : public internal::Select<Type> { class Select : public internal::Select<Type> {
public: public:
explicit Select(Network & network) explicit Select(Network & network)
: internal::Select<Type>(network.slices_, network.sched_) { : internal::Select<Type>(network.sched_) {
network.processes_.push_back(this); network.processes_.push_back(this);
} }
}; };
...@@ -803,7 +815,7 @@ class Network : public internal::ClockListener { ...@@ -803,7 +815,7 @@ class Network : public internal::ClockListener {
explicit Sink(Network & network, FunctionType function) explicit Sink(Network & network, FunctionType function)
: internal::Sink< : internal::Sink<
internal::Inputs<I1, I2, I3, I4, I5> >( internal::Inputs<I1, I2, I3, I4, I5> >(
network.slices_, network.sched_, &network, function) { network.sched_, &network, function) {
network.sinks_.push_back(this); network.sinks_.push_back(this);
network.sink_count_++; network.sink_count_++;
} }
...@@ -838,19 +850,45 @@ class Network : public internal::ClockListener { ...@@ -838,19 +850,45 @@ class Network : public internal::ClockListener {
bool IsValid() { bool IsValid() {
bool valid = true; bool valid = true;
// 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() && valid; ii++) {
valid = valid && processes_[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;
}
void operator () () {
if (0 >= slices_) {
slices_ = static_cast<int>(
sources_.size() +
sinks_.size());
for (size_t ii = 0; ii < processes_.size(); ii++) {
int tt = processes_[ii]->IsSequential() ? 1 :
static_cast<int>(embb_core_count_available());
slices_ += tt;
}
PrepareSlices();
for (size_t ii = 0; ii < sources_.size(); ii++) { for (size_t ii = 0; ii < sources_.size(); ii++) {
valid = valid & sources_[ii]->IsFullyConnected(); sources_[ii]->SetScheduler(sched_);
} }
for (size_t ii = 0; ii < processes_.size(); ii++) { for (size_t ii = 0; ii < processes_.size(); ii++) {
valid = valid & processes_[ii]->IsFullyConnected(); processes_[ii]->SetScheduler(sched_);
} }
for (size_t ii = 0; ii < sinks_.size(); ii++) { for (size_t ii = 0; ii < sinks_.size(); ii++) {
valid = valid & sinks_[ii]->IsFullyConnected(); sinks_[ii]->SetScheduler(sched_);
} }
return valid;
} }
void operator () () {
int clock = 0; int clock = 0;
while (clock >= 0) { while (clock >= 0) {
const int idx = clock % slices_; const int idx = clock % slices_;
...@@ -907,6 +945,19 @@ class Network : public internal::ClockListener { ...@@ -907,6 +945,19 @@ class Network : public internal::ClockListener {
} }
return result; return result;
} }
void PrepareSlices() {
sched_ = embb::base::Allocation::New<internal::SchedulerMTAPI>(slices_);
if (sched_->GetSlices() != slices_) {
slices_ = sched_->GetSlices();
}
sink_counter_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
sink_counter_[ii] = 0;
}
}
}; };
#endif // DOXYGEN #endif // DOXYGEN
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <embb_mtapi_action_t.h> #include <embb_mtapi_action_t.h>
#include <embb_mtapi_alloc.h> #include <embb_mtapi_alloc.h>
#include <embb_mtapi_queue_t.h> #include <embb_mtapi_queue_t.h>
#include <embb_mtapi_group_t.h>
/* ---- CLASS MEMBERS ------------------------------------------------------ */ /* ---- CLASS MEMBERS ------------------------------------------------------ */
...@@ -293,6 +294,8 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -293,6 +294,8 @@ int embb_mtapi_scheduler_worker(void * arg) {
/* check if there was work */ /* check if there was work */
if (MTAPI_NULL != task) { if (MTAPI_NULL != task) {
embb_mtapi_queue_t * local_queue = MTAPI_NULL; embb_mtapi_queue_t * local_queue = MTAPI_NULL;
embb_mtapi_group_t * local_group = MTAPI_NULL;
embb_mtapi_action_t * local_action = MTAPI_NULL;
/* is task associated with a queue? */ /* is task associated with a queue? */
if (embb_mtapi_queue_pool_is_handle_valid( if (embb_mtapi_queue_pool_is_handle_valid(
...@@ -302,6 +305,21 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -302,6 +305,21 @@ int embb_mtapi_scheduler_worker(void * arg) {
node->queue_pool, task->queue); node->queue_pool, task->queue);
} }
/* is task associated with a group? */
if (embb_mtapi_group_pool_is_handle_valid(
node->group_pool, task->group)) {
local_group =
embb_mtapi_group_pool_get_storage_for_handle(
node->group_pool, task->group);
}
if (embb_mtapi_action_pool_is_handle_valid(
node->action_pool, task->action)) {
local_action =
embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, task->action);
}
switch (embb_atomic_load_int(&task->state)) { switch (embb_atomic_load_int(&task->state)) {
case MTAPI_TASK_SCHEDULED: case MTAPI_TASK_SCHEDULED:
/* multi-instance task, another instance might be running */ /* multi-instance task, another instance might be running */
...@@ -328,7 +346,7 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -328,7 +346,7 @@ int embb_mtapi_scheduler_worker(void * arg) {
break; break;
case MTAPI_TASK_CANCELLED: case MTAPI_TASK_CANCELLED:
/* set return value to canceled */ /* set return value to cancelled */
task->error_code = MTAPI_ERR_ACTION_CANCELLED; task->error_code = MTAPI_ERR_ACTION_CANCELLED;
if (embb_atomic_fetch_and_add_unsigned_int( if (embb_atomic_fetch_and_add_unsigned_int(
&task->instances_todo, (unsigned int)-1) == 0) { &task->instances_todo, (unsigned int)-1) == 0) {
...@@ -336,6 +354,12 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -336,6 +354,12 @@ int embb_mtapi_scheduler_worker(void * arg) {
if (MTAPI_NULL != local_queue) { if (MTAPI_NULL != local_queue) {
embb_mtapi_queue_task_finished(local_queue); embb_mtapi_queue_task_finished(local_queue);
} }
if (MTAPI_NULL != local_group) {
embb_mtapi_task_queue_push(&local_group->queue, task);
}
}
if (MTAPI_NULL != local_action) {
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
} }
break; break;
......
...@@ -501,7 +501,6 @@ void mtapi_task_cancel( ...@@ -501,7 +501,6 @@ void mtapi_task_cancel(
if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) { if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) {
embb_mtapi_task_t* local_task = embb_mtapi_task_t* local_task =
embb_mtapi_task_pool_get_storage_for_handle(node->task_pool, task); embb_mtapi_task_pool_get_storage_for_handle(node->task_pool, task);
embb_mtapi_task_set_state(local_task, MTAPI_TASK_CANCELLED);
/* call plugin action cancel function */ /* call plugin action cancel function */
if (embb_mtapi_action_pool_is_handle_valid( if (embb_mtapi_action_pool_is_handle_valid(
...@@ -511,8 +510,14 @@ void mtapi_task_cancel( ...@@ -511,8 +510,14 @@ void mtapi_task_cancel(
node->action_pool, local_task->action); node->action_pool, local_task->action);
if (local_action->is_plugin_action) { if (local_action->is_plugin_action) {
local_action->plugin_task_cancel_function(task, &local_status); local_action->plugin_task_cancel_function(task, &local_status);
} else {
embb_mtapi_task_set_state(local_task, MTAPI_TASK_CANCELLED);
local_task->error_code = MTAPI_ERR_ACTION_CANCELLED;
local_status = MTAPI_SUCCESS;
} }
} else { } else {
embb_mtapi_task_set_state(local_task, MTAPI_TASK_CANCELLED);
local_task->error_code = MTAPI_ERR_ACTION_CANCELLED;
local_status = MTAPI_SUCCESS; local_status = MTAPI_SUCCESS;
} }
} else { } else {
......
...@@ -139,6 +139,24 @@ class Node { ...@@ -139,6 +139,24 @@ class Node {
} }
/** /**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* Starts a new Task. * Starts a new Task.
* *
* \returns The handle to the started Task. * \returns The handle to the started Task.
...@@ -349,6 +367,8 @@ class Node { ...@@ -349,6 +367,8 @@ class Node {
mtapi_status_t status; mtapi_status_t status;
mtapi_info_t info; mtapi_info_t info;
queue_count_ = attr.GetInternal().max_queues; queue_count_ = attr.GetInternal().max_queues;
group_count_ = attr.GetInternal().max_groups;
task_limit_ = attr.GetInternal().max_tasks;
mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status); mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status);
internal::CheckStatus(status); internal::CheckStatus(status);
...@@ -383,6 +403,8 @@ class Node { ...@@ -383,6 +403,8 @@ class Node {
mtapi_uint_t core_count_; mtapi_uint_t core_count_;
mtapi_uint_t worker_thread_count_; mtapi_uint_t worker_thread_count_;
mtapi_uint_t queue_count_; mtapi_uint_t queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
}; };
} // namespace mtapi } // namespace mtapi
......
...@@ -28,9 +28,10 @@ ...@@ -28,9 +28,10 @@
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
#include <string.h> #include <string.h>
void embb_mtapi_network_buffer_initialize( int embb_mtapi_network_buffer_initialize(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int capacity) { int capacity) {
int result = 1;
that->position = 0; that->position = 0;
that->size = 0; that->size = 0;
that->data = (char*)embb_alloc((size_t)capacity); that->data = (char*)embb_alloc((size_t)capacity);
...@@ -38,7 +39,9 @@ void embb_mtapi_network_buffer_initialize( ...@@ -38,7 +39,9 @@ void embb_mtapi_network_buffer_initialize(
that->capacity = capacity; that->capacity = capacity;
} else { } else {
that->capacity = 0; that->capacity = 0;
result = 0;
} }
return result;
} }
void embb_mtapi_network_buffer_finalize( void embb_mtapi_network_buffer_finalize(
......
...@@ -43,7 +43,7 @@ struct embb_mtapi_network_buffer_struct { ...@@ -43,7 +43,7 @@ struct embb_mtapi_network_buffer_struct {
typedef struct embb_mtapi_network_buffer_struct embb_mtapi_network_buffer_t; typedef struct embb_mtapi_network_buffer_struct embb_mtapi_network_buffer_t;
void embb_mtapi_network_buffer_initialize( int embb_mtapi_network_buffer_initialize(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int capacity int capacity
); );
......
...@@ -116,7 +116,8 @@ int embb_mtapi_network_socket_connect( ...@@ -116,7 +116,8 @@ int embb_mtapi_network_socket_connect(
if (SOCKET_ERROR == connect(that->handle, (struct sockaddr *)&addr, if (SOCKET_ERROR == connect(that->handle, (struct sockaddr *)&addr,
sizeof(addr))) { sizeof(addr))) {
#ifdef _WIN32 #ifdef _WIN32
if (WSAEWOULDBLOCK != WSAGetLastError()) int err = WSAGetLastError();
if (WSAEWOULDBLOCK != err)
#else #else
if (EAGAIN != errno) if (EAGAIN != errno)
#endif #endif
......
...@@ -61,13 +61,52 @@ static void test( ...@@ -61,13 +61,52 @@ static void test(
} }
} }
static void cancel_test(
void const * /*arguments*/,
mtapi_size_t /*arguments_size*/,
void * /*result_buffer*/,
mtapi_size_t /*result_buffer_size*/,
void const * /*node_local_data*/,
mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t * context) {
mtapi_status_t status;
while (true) {
mtapi_task_state_t state = mtapi_context_taskstate_get(context, &status);
if (status != MTAPI_SUCCESS) {
break;
} else {
if (state == MTAPI_TASK_CANCELLED) {
break;
}
}
}
}
NetworkTaskTest::NetworkTaskTest() { NetworkTaskTest::NetworkTaskTest() {
CreateUnit("mtapi network task test").Add(&NetworkTaskTest::TestBasic, this); CreateUnit("mtapi network task test")
.Add(&NetworkTaskTest::TestBasic, this);
} }
void NetworkTaskTest::TestBasic() { void NetworkTaskTest::TestBasic() {
mtapi_status_t status; mtapi_status_t status;
mtapi_initialize(
NETWORK_DOMAIN,
NETWORK_LOCAL_NODE,
MTAPI_NULL,
MTAPI_NULL,
&status);
MTAPI_CHECK_STATUS(status);
TestSimple();
TestCancel();
mtapi_finalize(&status);
MTAPI_CHECK_STATUS(status);
}
void NetworkTaskTest::TestSimple() {
mtapi_status_t status;
mtapi_job_hndl_t job; mtapi_job_hndl_t job;
mtapi_task_hndl_t task; mtapi_task_hndl_t task;
mtapi_action_hndl_t network_action, local_action; mtapi_action_hndl_t network_action, local_action;
...@@ -81,14 +120,6 @@ void NetworkTaskTest::TestBasic() { ...@@ -81,14 +120,6 @@ void NetworkTaskTest::TestBasic() {
arguments[ii + kElements] = static_cast<float>(ii); arguments[ii + kElements] = static_cast<float>(ii);
} }
mtapi_initialize(
NETWORK_DOMAIN,
NETWORK_LOCAL_NODE,
MTAPI_NULL,
MTAPI_NULL,
&status);
MTAPI_CHECK_STATUS(status);
mtapi_network_plugin_initialize("127.0.0.1", 12345, 5, mtapi_network_plugin_initialize("127.0.0.1", 12345, 5,
kElements * 4 * 3 + 32, &status); kElements * 4 * 3 + 32, &status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
...@@ -139,7 +170,68 @@ void NetworkTaskTest::TestBasic() { ...@@ -139,7 +170,68 @@ void NetworkTaskTest::TestBasic() {
mtapi_network_plugin_finalize(&status); mtapi_network_plugin_finalize(&status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
}
void NetworkTaskTest::TestCancel() {
mtapi_status_t status;
mtapi_job_hndl_t job;
mtapi_task_hndl_t task;
mtapi_action_hndl_t network_action, local_action;
float argument = 1.0f;
float result;
mtapi_network_plugin_initialize("127.0.0.1", 12345, 5,
4 * 3 + 32, &status);
MTAPI_CHECK_STATUS(status);
mtapi_finalize(&status); float node_remote = 1.0f;
local_action = mtapi_action_create(
NETWORK_REMOTE_JOB,
cancel_test,
&node_remote, sizeof(float),
MTAPI_DEFAULT_ACTION_ATTRIBUTES,
&status);
MTAPI_CHECK_STATUS(status);
network_action = mtapi_network_action_create(
NETWORK_DOMAIN,
NETWORK_LOCAL_JOB,
NETWORK_REMOTE_JOB,
"127.0.0.1", 12345,
&status);
MTAPI_CHECK_STATUS(status);
status = MTAPI_ERR_UNKNOWN;
job = mtapi_job_get(NETWORK_LOCAL_JOB, NETWORK_DOMAIN, &status);
MTAPI_CHECK_STATUS(status);
task = mtapi_task_start(
MTAPI_TASK_ID_NONE,
job,
&argument, sizeof(float),
&result, sizeof(float),
MTAPI_DEFAULT_TASK_ATTRIBUTES,
MTAPI_GROUP_NONE,
&status);
MTAPI_CHECK_STATUS(status);
mtapi_task_wait(task, 1, &status);
PT_ASSERT_EQ(status, MTAPI_TIMEOUT);
mtapi_task_cancel(task, &status);
MTAPI_CHECK_STATUS(status);
mtapi_task_wait(task, MTAPI_INFINITE, &status);
PT_ASSERT_NE(status, MTAPI_TIMEOUT);
PT_ASSERT_EQ(status, MTAPI_ERR_ACTION_CANCELLED);
mtapi_action_delete(network_action, MTAPI_INFINITE, &status);
MTAPI_CHECK_STATUS(status);
mtapi_action_delete(local_action, MTAPI_INFINITE, &status);
MTAPI_CHECK_STATUS(status);
mtapi_network_plugin_finalize(&status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
} }
...@@ -35,6 +35,9 @@ class NetworkTaskTest : public partest::TestCase { ...@@ -35,6 +35,9 @@ class NetworkTaskTest : public partest::TestCase {
private: private:
void TestBasic(); void TestBasic();
void TestSimple();
void TestCancel();
}; };
#endif // MTAPI_PLUGINS_C_MTAPI_NETWORK_C_TEST_EMBB_MTAPI_NETWORK_TEST_TASK_H_ #endif // MTAPI_PLUGINS_C_MTAPI_NETWORK_C_TEST_EMBB_MTAPI_NETWORK_TEST_TASK_H_
...@@ -130,6 +130,24 @@ class Node { ...@@ -130,6 +130,24 @@ class Node {
} }
/** /**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* Returns the number of available cores. * Returns the number of available cores.
* \return The number of available cores * \return The number of available cores
* \waitfree * \waitfree
...@@ -229,6 +247,8 @@ class Node { ...@@ -229,6 +247,8 @@ class Node {
mtapi_task_context_t * context); mtapi_task_context_t * context);
mtapi_uint_t queue_count_; mtapi_uint_t queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
mtapi_uint_t core_count_; mtapi_uint_t core_count_;
mtapi_uint_t worker_thread_count_; mtapi_uint_t worker_thread_count_;
mtapi_action_hndl_t action_handle_; mtapi_action_hndl_t action_handle_;
......
...@@ -78,6 +78,12 @@ Node::Node( ...@@ -78,6 +78,12 @@ Node::Node(
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_QUEUES, &queue_count_, mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_QUEUES, &queue_count_,
sizeof(queue_count_), &status); sizeof(queue_count_), &status);
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_GROUPS, &group_count_,
sizeof(group_count_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_TASKS, &task_limit_,
sizeof(queue_count_), &status);
assert(MTAPI_SUCCESS == status);
core_count_ = info.hardware_concurrency; core_count_ = info.hardware_concurrency;
worker_thread_count_ = embb_core_set_count(&attr->core_affinity); worker_thread_count_ = embb_core_set_count(&attr->core_affinity);
action_handle_ = mtapi_action_create(TASKS_CPP_JOB, action_func, action_handle_ = mtapi_action_create(TASKS_CPP_JOB, action_func,
......
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