Blender  V2.93
task_graph.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_task.h"
26 
27 #include <memory>
28 #include <vector>
29 
30 #ifdef WITH_TBB
31 # include <tbb/flow_graph.h>
32 #endif
33 
34 /* Task Graph */
35 struct TaskGraph {
36 #ifdef WITH_TBB
37  tbb::flow::graph tbb_graph;
38 #endif
39  std::vector<std::unique_ptr<TaskNode>> nodes;
40 
41 #ifdef WITH_CXX_GUARDEDALLOC
42  MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskGraph")
43 #endif
44 };
45 
46 /* TaskNode - a node in the task graph. */
47 struct TaskNode {
48  /* TBB Node. */
49 #ifdef WITH_TBB
50  tbb::flow::continue_node<tbb::flow::continue_msg> tbb_node;
51 #endif
52  /* Successors to execute after this task, for serial execution fallback. */
53  std::vector<TaskNode *> successors;
54 
55  /* User function to be executed with given task data. */
57  void *task_data;
58  /* Optional callback to free task data along with the graph. If task data
59  * is shared between nodes, only a single task node should free the data. */
61 
62  TaskNode(TaskGraph *task_graph,
64  void *task_data,
66  :
67 #ifdef WITH_TBB
68  tbb_node(task_graph->tbb_graph,
69  tbb::flow::unlimited,
70  [&](const tbb::flow::continue_msg input) { run(input); }),
71 #endif
75  {
76 #ifndef WITH_TBB
77  UNUSED_VARS(task_graph);
78 #endif
79  }
80 
81  TaskNode(const TaskNode &other) = delete;
82  TaskNode &operator=(const TaskNode &other) = delete;
83 
85  {
86  if (task_data && free_func) {
88  }
89  }
90 
91 #ifdef WITH_TBB
92  tbb::flow::continue_msg run(const tbb::flow::continue_msg UNUSED(input))
93  {
94  tbb::this_task_arena::isolate([this] { run_func(task_data); });
95  return tbb::flow::continue_msg();
96  }
97 #endif
98 
99  void run_serial()
100  {
102  for (TaskNode *successor : successors) {
103  successor->run_serial();
104  }
105  }
106 
107 #ifdef WITH_CXX_GUARDEDALLOC
108  MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskNode")
109 #endif
110 };
111 
113 {
114  return new TaskGraph();
115 }
116 
118 {
119  delete task_graph;
120 }
121 
123 {
124 #ifdef WITH_TBB
125  task_graph->tbb_graph.wait_for_all();
126 #else
127  UNUSED_VARS(task_graph);
128 #endif
129 }
130 
131 struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
133  void *user_data,
135 {
136  TaskNode *task_node = new TaskNode(task_graph, run, user_data, free_func);
137  task_graph->nodes.push_back(std::unique_ptr<TaskNode>(task_node));
138  return task_node;
139 }
140 
142 {
143 #ifdef WITH_TBB
144  if (BLI_task_scheduler_num_threads() > 1) {
145  return task_node->tbb_node.try_put(tbb::flow::continue_msg());
146  }
147 #endif
148 
149  task_node->run_serial();
150  return true;
151 }
152 
153 void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node)
154 {
155 #ifdef WITH_TBB
156  if (BLI_task_scheduler_num_threads() > 1) {
157  tbb::flow::make_edge(from_node->tbb_node, to_node->tbb_node);
158  return;
159  }
160 #endif
161 
162  from_node->successors.push_back(to_node);
163 }
int BLI_task_scheduler_num_threads(void)
void(* TaskGraphNodeFreeFunction)(void *task_data)
Definition: BLI_task.h:307
void(* TaskGraphNodeRunFunction)(void *__restrict task_data)
Definition: BLI_task.h:306
#define UNUSED_VARS(...)
#define UNUSED(x)
Read Guarded memory(de)allocation.
static PyObject * free_func(PyObject *, PyObject *value)
Depsgraph * graph
void * user_data
std::vector< std::unique_ptr< TaskNode > > nodes
Definition: task_graph.cc:39
TaskNode(TaskGraph *task_graph, TaskGraphNodeRunFunction run_func, void *task_data, TaskGraphNodeFreeFunction free_func)
Definition: task_graph.cc:62
TaskNode(const TaskNode &other)=delete
std::vector< TaskNode * > successors
Definition: task_graph.cc:53
TaskGraphNodeFreeFunction free_func
Definition: task_graph.cc:60
TaskNode & operator=(const TaskNode &other)=delete
void run_serial()
Definition: task_graph.cc:99
TaskGraphNodeRunFunction run_func
Definition: task_graph.cc:56
void * task_data
Definition: task_graph.cc:57
TaskGraph * BLI_task_graph_create(void)
Definition: task_graph.cc:112
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node)
Definition: task_graph.cc:153
bool BLI_task_graph_node_push_work(struct TaskNode *task_node)
Definition: task_graph.cc:141
void BLI_task_graph_work_and_wait(TaskGraph *task_graph)
Definition: task_graph.cc:122
struct TaskNode * BLI_task_graph_node_create(struct TaskGraph *task_graph, TaskGraphNodeRunFunction run, void *user_data, TaskGraphNodeFreeFunction free_func)
Definition: task_graph.cc:131
void BLI_task_graph_free(TaskGraph *task_graph)
Definition: task_graph.cc:117