Taskflow  2.4-master-branch
taskflow.hpp
1 #pragma once
2 
3 #include <stack>
4 
5 #include "flow_builder.hpp"
6 #include "topology.hpp"
7 
8 namespace tf {
9 
10 // ----------------------------------------------------------------------------
11 
18 class Taskflow : public FlowBuilder {
19 
20  friend class Topology;
21  friend class Executor;
22  friend class FlowBuilder;
23 
24  struct Dumper {
27  };
28 
29  public:
30 
34  Taskflow(const std::string& name);
35 
39  Taskflow();
40 
44  virtual ~Taskflow();
45 
51  void dump(std::ostream& ostream) const;
52 
56  std::string dump() const;
57 
61  size_t num_tasks() const;
62 
66  bool empty() const;
67 
73  void name(const std::string&);
74 
78  const std::string& name() const ;
79 
83  void clear();
84 
88  template <typename V>
89  void for_each_task(V&& visitor) const;
90 
91  private:
92 
93  std::string _name;
94 
95  Graph _graph;
96 
97  std::mutex _mtx;
98 
99  std::list<Topology> _topologies;
100 
101  void _dump(std::ostream&, const Taskflow*) const;
102  void _dump(std::ostream&, const Node*, Dumper&) const;
103  void _dump(std::ostream&, const Graph&, Dumper&) const;
104 };
105 
106 // Constructor
107 inline Taskflow::Taskflow(const std::string& name) :
108  FlowBuilder {_graph},
109  _name {name} {
110 }
111 
112 // Constructor
113 inline Taskflow::Taskflow() : FlowBuilder{_graph} {
114 }
115 
116 // Destructor
118  assert(_topologies.empty());
119 }
120 
121 // Procedure:
122 inline void Taskflow::clear() {
123  _graph.clear();
124 }
125 
126 // Function: num_noces
127 inline size_t Taskflow::num_tasks() const {
128  return _graph.size();
129 }
130 
131 // Function: empty
132 inline bool Taskflow::empty() const {
133  return _graph.empty();
134 }
135 
136 // Function: name
137 inline void Taskflow::name(const std::string &name) {
138  _name = name;
139 }
140 
141 // Function: name
142 inline const std::string& Taskflow::name() const {
143  return _name;
144 }
145 
146 // Function: for_each_task
147 template <typename V>
148 void Taskflow::for_each_task(V&& visitor) const {
149  for(size_t i=0; i<_graph._nodes.size(); ++i) {
150  visitor(Task(_graph._nodes[i]));
151  }
152 }
153 
154 // Procedure: dump
155 inline std::string Taskflow::dump() const {
156  std::ostringstream oss;
157  dump(oss);
158  return oss.str();
159 }
160 
161 // Function: dump
162 inline void Taskflow::dump(std::ostream& os) const {
163  os << "digraph Taskflow {\n";
164  _dump(os, this);
165  os << "}\n";
166 }
167 
168 // Procedure: _dump
169 inline void Taskflow::_dump(std::ostream& os, const Taskflow* top) const {
170 
171  Dumper dumper;
172 
173  dumper.stack.push(top);
174  dumper.visited.insert(top);
175 
176  while(!dumper.stack.empty()) {
177 
178  auto f = dumper.stack.top();
179  dumper.stack.pop();
180 
181  os << "subgraph cluster_p" << f << " {\nlabel=\"Taskflow: ";
182  if(f->_name.empty()) os << 'p' << f;
183  else os << f->_name;
184  os << "\";\n";
185  _dump(os, f->_graph, dumper);
186  os << "}\n";
187  }
188 }
189 
190 // Procedure: _dump
191 inline void Taskflow::_dump(
192  std::ostream& os, const Node* node, Dumper& dumper
193 ) const {
194 
195  os << 'p' << node << "[label=\"";
196  if(node->_name.empty()) os << 'p' << node;
197  else os << node->_name;
198  os << "\" ";
199 
200  // shape for node
201  switch(node->_handle.index()) {
202 
203  case Node::CONDITION_WORK:
204  os << "shape=diamond color=black fillcolor=aquamarine style=filled";
205  break;
206 
207 #ifdef TF_ENABLE_CUDA
208  case Node::CUDAFLOW_WORK:
209  os << "shape=folder fillcolor=cyan style=filled";
210  break;
211 #endif
212 
213  default:
214  break;
215  }
216 
217  os << "];\n";
218 
219  for(size_t s=0; s<node->_successors.size(); ++s) {
220  if(node->_handle.index() == Node::CONDITION_WORK) {
221  // case edge is dashed
222  os << 'p' << node << " -> p" << node->_successors[s]
223  << " [style=dashed label=\"" << s << "\"];\n";
224  }
225  else {
226  os << 'p' << node << " -> p" << node->_successors[s] << ";\n";
227  }
228  }
229 
230  // subflow join node
231  if(node->_parent && node->_successors.size() == 0) {
232  os << 'p' << node << " -> p" << node->_parent << ";\n";
233  }
234 
235  switch(node->_handle.index()) {
236 
237  case Node::DYNAMIC_WORK: {
238  auto& sbg = nstd::get<Node::DynamicWork>(node->_handle).subgraph;
239  if(!sbg.empty()) {
240  os << "subgraph cluster_p" << node << " {\nlabel=\"Subflow: ";
241  if(node->_name.empty()) os << 'p' << node;
242  else os << node->_name;
243 
244  os << "\";\n" << "color=blue\n";
245  _dump(os, sbg, dumper);
246  os << "}\n";
247  }
248  }
249  break;
250 
251 #ifdef TF_ENABLE_CUDA
252  case Node::CUDAFLOW_WORK: {
253  auto& cfg = nstd::get<Node::cudaFlowWork>(node->_handle).graph;
254  if(!cfg.empty()) {
255  os << "subgraph cluster_p" << node << " {\nlabel=\"cudaFlow: ";
256  if(node->_name.empty()) os << 'p' << node;
257  else os << node->_name;
258 
259  os << "\";\n" << "color=\"purple\"\n";
260 
261  for(const auto& v : cfg._nodes) {
262 
263  os << 'p' << v.get() << "[label=\"";
264  if(v->_name.empty()) {
265  os << 'p' << v.get() << "\"";
266  }
267  else {
268  os << v->_name << "\"";
269  }
270 
271  switch(v->_handle.index()) {
272  case cudaNode::NOOP:
273  break;
274 
275  case cudaNode::COPY:
276  //os << " shape=\"cds\"";
277  break;
278 
279  case cudaNode::KERNEL:
280  os << " style=\"filled\""
281  << " color=\"white\" fillcolor=\"black\""
282  << " fontcolor=\"white\""
283  << " shape=\"box3d\"";
284  break;
285 
286  default:
287  break;
288  }
289 
290  os << "];\n";
291  for(const auto s : v->_successors) {
292  os << 'p' << v.get() << " -> " << 'p' << s << ";\n";
293  }
294 
295  if(v->_successors.size() == 0) {
296  os << 'p' << v.get() << " -> p" << node << ";\n";
297  }
298 
299  }
300  os << "}\n";
301  }
302  }
303  break;
304 #endif
305 
306  default:
307  break;
308  }
309 }
310 
311 // Procedure: _dump
312 inline void Taskflow::_dump(
313  std::ostream& os, const Graph& graph, Dumper& dumper
314 ) const {
315 
316  for(const auto& n : graph._nodes) {
317 
318  // regular task
319  if(n->_handle.index() != Node::MODULE_WORK) {
320  _dump(os, n, dumper);
321  }
322  // module task
323  else {
324 
325  auto module = nstd::get<Node::ModuleWork>(n->_handle).module;
326 
327  os << 'p' << n << "[shape=box3d, color=blue, label=\"";
328  if(n->_name.empty()) os << n;
329  else os << n->_name;
330  os << " [Taskflow: ";
331  if(module->_name.empty()) os << 'p' << module;
332  else os << module->_name;
333  os << "]\"];\n";
334 
335  if(dumper.visited.find(module) == dumper.visited.end()) {
336  dumper.visited.insert(module);
337  dumper.stack.push(module);
338  }
339 
340  for(const auto s : n->_successors) {
341  os << 'p' << n << "->" << 'p' << s << ";\n";
342  }
343  }
344  }
345 }
346 
347 // ----------------------------------------------------------------------------
348 // Backward compatibility
349 // ----------------------------------------------------------------------------
350 using Framework = Taskflow;
351 
352 } // end of namespace tf. ---------------------------------------------------
353 
Taskflow()
constructs a taskflow
Definition: taskflow.hpp:113
Definition: error.hpp:9
void for_each_task(V &&visitor) const
applies an visitor callable to each task in the taskflow
Definition: taskflow.hpp:148
const std::string & name() const
queries the name of the taskflow
Definition: taskflow.hpp:142
void clear()
clears the associated task dependency graph
Definition: taskflow.hpp:122
main entry to create a task dependency graph
Definition: taskflow.hpp:18
bool empty() const
queries the emptiness of the taskflow
Definition: taskflow.hpp:132
std::string dump() const
dumps the taskflow in DOT format to a std::string
Definition: taskflow.hpp:155
building methods of a task dependency graph
Definition: flow_builder.hpp:13
handle to a node in a task dependency graph
Definition: task.hpp:113
execution interface for running a taskflow graph
Definition: executor.hpp:43
size_t num_tasks() const
queries the number of tasks in the taskflow
Definition: taskflow.hpp:127
virtual ~Taskflow()
destroy the taskflow (virtual call)
Definition: taskflow.hpp:117