Cpp-Taskflow  2.3.0
core/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  public:
25 
29  Taskflow(const std::string& name);
30 
34  Taskflow();
35 
39  virtual ~Taskflow();
40 
46  void dump(std::ostream& ostream) const;
47 
51  std::string dump() const;
52 
56  size_t num_tasks() const;
57 
61  bool empty() const;
62 
68  tf::Taskflow& name(const std::string&);
69 
73  const std::string& name() const ;
74 
78  void clear();
79 
83  template <typename V>
84  void for_each_task(V&& visitor) const;
85 
86  private:
87 
88  std::string _name;
89 
90  Graph _graph;
91 
92  std::mutex _mtx;
93 
94  std::list<Topology> _topologies;
95 
96  void _dump(std::ostream&, const Taskflow*) const;
97 
98  void _dump(
99  std::ostream&,
100  const Node*,
103  ) const;
104 
105  void _dump(
106  std::ostream&,
107  const Graph&,
110  ) const;
111 };
112 
113 // Constructor
115  FlowBuilder {_graph},
116  _name {name} {
117 }
118 
119 // Constructor
120 inline Taskflow::Taskflow() : FlowBuilder{_graph} {
121 }
122 
123 // Destructor
125  assert(_topologies.empty());
126 }
127 
128 // Procedure:
129 inline void Taskflow::clear() {
130  _graph.clear();
131 }
132 
133 // Function: num_noces
134 inline size_t Taskflow::num_tasks() const {
135  return _graph.size();
136 }
137 
138 // Function: empty
139 inline bool Taskflow::empty() const {
140  return _graph.empty();
141 }
142 
143 // Function: name
145  _name = name;
146  return *this;
147 }
148 
149 // Function: name
150 inline const std::string& Taskflow::name() const {
151  return _name;
152 }
153 
154 // Function: for_each_task
155 template <typename V>
156 void Taskflow::for_each_task(V&& visitor) const {
157  for(size_t i=0; i<_graph._nodes.size(); ++i) {
158  visitor(Task(_graph._nodes[i]));
159  }
160 }
161 
162 // Procedure: dump
163 inline std::string Taskflow::dump() const {
164  std::ostringstream oss;
165  dump(oss);
166  return oss.str();
167 }
168 
169 // Function: dump
170 inline void Taskflow::dump(std::ostream& os) const {
171  os << "digraph Taskflow {\n";
172  _dump(os, this);
173  os << "}\n";
174 }
175 
176 // Procedure: _dump
177 inline void Taskflow::_dump(std::ostream& os, const Taskflow* top) const {
178 
181 
182  stack.push(top);
183  visited.insert(top);
184 
185  while(!stack.empty()) {
186 
187  auto f = stack.top();
188  stack.pop();
189 
190  os << "subgraph cluster_p" << f << " {\nlabel=\"Taskflow: ";
191  if(f->_name.empty()) os << 'p' << f;
192  else os << f->_name;
193  os << "\";\n";
194  _dump(os, f->_graph, stack, visited);
195  os << "}\n";
196  }
197 }
198 
199 // Procedure: _dump
200 inline void Taskflow::_dump(
201  std::ostream& os,
202  const Node* node,
205 ) const {
206 
207  os << 'p' << node << "[label=\"";
208  if(node->_name.empty()) os << 'p' << node;
209  else os << node->_name;
210  os << "\" ";
211 
212  // condition node is colored green
213  if(node->_handle.index() == Node::CONDITION_WORK) {
214  os << " shape=diamond color=black fillcolor=aquamarine style=filled";
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  if(node->_handle.index() == Node::DYNAMIC_WORK) {
236 
237  auto& sbg = nstd::get<Node::DynamicWork>(node->_handle).subgraph;
238 
239  //if(node->_subgraph && !node->_subgraph->empty()) {
240  if(!sbg.empty()) {
241 
242  os << "subgraph cluster_p" << node << " {\nlabel=\"Subflow: ";
243  if(node->_name.empty()) os << 'p' << node;
244  else os << node->_name;
245 
246  os << "\";\n" << "color=blue\n";
247  _dump(os, sbg, stack, visited);
248  os << "}\n";
249  }
250  }
251 }
252 
253 // Procedure: _dump
254 inline void Taskflow::_dump(
255  std::ostream& os,
256  const Graph& graph,
259 ) const {
260 
261  for(const auto& n : graph._nodes) {
262 
263  // regular task
264  if(n->_handle.index() != Node::MODULE_WORK) {
265  _dump(os, n, stack, visited);
266  }
267  // module task
268  else {
269 
270  auto module = nstd::get<Node::ModuleWork>(n->_handle).module;
271 
272  os << 'p' << n << "[shape=box, color=blue, label=\"";
273  if(n->_name.empty()) os << n;
274  else os << n->_name;
275  os << " [Taskflow: ";
276  if(module->_name.empty()) os << 'p' << module;
277  else os << module->_name;
278  os << "]\"];\n";
279 
280  if(visited.find(module) == visited.end()) {
281  visited.insert(module);
282  stack.push(module);
283  }
284 
285  for(const auto s : n->_successors) {
286  os << 'p' << n << "->" << 'p' << s << ";\n";
287  }
288  }
289  }
290 }
291 
292 // ----------------------------------------------------------------------------
293 // Backward compatibility
294 // ----------------------------------------------------------------------------
295 
296 using Framework = Taskflow;
297 
298 } // end of namespace tf. ---------------------------------------------------
299 
Taskflow()
constructs a taskflow
Definition: core/taskflow.hpp:120
Definition: taskflow.hpp:5
void for_each_task(V &&visitor) const
applies an visitor callable to each task in the taskflow
Definition: core/taskflow.hpp:156
const std::string & name() const
queries the name of the taskflow
Definition: core/taskflow.hpp:150
void clear()
clears the associated task dependency graph
Definition: core/taskflow.hpp:129
the class to create a task dependency graph
Definition: core/taskflow.hpp:18
bool empty() const
queries the emptiness of the taskflow
Definition: core/taskflow.hpp:139
std::string dump() const
dumps the taskflow in DOT format to a std::string
Definition: core/taskflow.hpp:163
Building blocks of a task dependency graph.
Definition: flow_builder.hpp:13
task handle to a node in a task dependency graph
Definition: task.hpp:51
The executor class to run a taskflow graph.
Definition: executor.hpp:33
size_t num_tasks() const
queries the number of tasks in the taskflow
Definition: core/taskflow.hpp:134
virtual ~Taskflow()
destroy the taskflow (virtual call)
Definition: core/taskflow.hpp:124