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 * The Original Code is Copyright (C) 2014 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup depsgraph
22 *
23 * Implementation of tools for debugging the depsgraph
24 */
25
26 #include "BLI_utildefines.h"
27
28 #include "DNA_scene_types.h"
29
30 #include "DNA_object_types.h"
31
32 #include "DEG_depsgraph.h"
33 #include "DEG_depsgraph_build.h"
34 #include "DEG_depsgraph_debug.h"
35 #include "DEG_depsgraph_query.h"
36
37 #include "intern/debug/deg_debug.h"
38 #include "intern/depsgraph.h"
39 #include "intern/depsgraph_relation.h"
40 #include "intern/depsgraph_type.h"
41 #include "intern/node/deg_node_component.h"
42 #include "intern/node/deg_node_id.h"
43 #include "intern/node/deg_node_time.h"
44
45 namespace deg = blender::deg;
46
DEG_debug_flags_set(Depsgraph * depsgraph,int flags)47 void DEG_debug_flags_set(Depsgraph *depsgraph, int flags)
48 {
49 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
50 deg_graph->debug.flags = flags;
51 }
52
DEG_debug_flags_get(const Depsgraph * depsgraph)53 int DEG_debug_flags_get(const Depsgraph *depsgraph)
54 {
55 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
56 return deg_graph->debug.flags;
57 }
58
DEG_debug_name_set(struct Depsgraph * depsgraph,const char * name)59 void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name)
60 {
61 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
62 deg_graph->debug.name = name;
63 }
64
DEG_debug_name_get(struct Depsgraph * depsgraph)65 const char *DEG_debug_name_get(struct Depsgraph *depsgraph)
66 {
67 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
68 return deg_graph->debug.name.c_str();
69 }
70
DEG_debug_compare(const struct Depsgraph * graph1,const struct Depsgraph * graph2)71 bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2)
72 {
73 BLI_assert(graph1 != nullptr);
74 BLI_assert(graph2 != nullptr);
75 const deg::Depsgraph *deg_graph1 = reinterpret_cast<const deg::Depsgraph *>(graph1);
76 const deg::Depsgraph *deg_graph2 = reinterpret_cast<const deg::Depsgraph *>(graph2);
77 if (deg_graph1->operations.size() != deg_graph2->operations.size()) {
78 return false;
79 }
80 /* TODO(sergey): Currently we only do real stupid check,
81 * which is fast but which isn't 100% reliable.
82 *
83 * Would be cool to make it more robust, but it's good enough
84 * for now. Also, proper graph check is actually NP-complex
85 * problem. */
86 return true;
87 }
88
DEG_debug_graph_relations_validate(Depsgraph * graph,Main * bmain,Scene * scene,ViewLayer * view_layer)89 bool DEG_debug_graph_relations_validate(Depsgraph *graph,
90 Main *bmain,
91 Scene *scene,
92 ViewLayer *view_layer)
93 {
94 Depsgraph *temp_depsgraph = DEG_graph_new(bmain, scene, view_layer, DEG_get_mode(graph));
95 bool valid = true;
96 DEG_graph_build_from_view_layer(temp_depsgraph);
97 if (!DEG_debug_compare(temp_depsgraph, graph)) {
98 fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n");
99 BLI_assert(!"This should not happen!");
100 valid = false;
101 }
102 DEG_graph_free(temp_depsgraph);
103 return valid;
104 }
105
DEG_debug_consistency_check(Depsgraph * graph)106 bool DEG_debug_consistency_check(Depsgraph *graph)
107 {
108 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
109 /* Validate links exists in both directions. */
110 for (deg::OperationNode *node : deg_graph->operations) {
111 for (deg::Relation *rel : node->outlinks) {
112 int counter1 = 0;
113 for (deg::Relation *tmp_rel : node->outlinks) {
114 if (tmp_rel == rel) {
115 counter1++;
116 }
117 }
118 int counter2 = 0;
119 for (deg::Relation *tmp_rel : rel->to->inlinks) {
120 if (tmp_rel == rel) {
121 counter2++;
122 }
123 }
124 if (counter1 != counter2) {
125 printf(
126 "Relation exists in outgoing direction but not in "
127 "incoming (%d vs. %d).\n",
128 counter1,
129 counter2);
130 return false;
131 }
132 }
133 }
134
135 for (deg::OperationNode *node : deg_graph->operations) {
136 for (deg::Relation *rel : node->inlinks) {
137 int counter1 = 0;
138 for (deg::Relation *tmp_rel : node->inlinks) {
139 if (tmp_rel == rel) {
140 counter1++;
141 }
142 }
143 int counter2 = 0;
144 for (deg::Relation *tmp_rel : rel->from->outlinks) {
145 if (tmp_rel == rel) {
146 counter2++;
147 }
148 }
149 if (counter1 != counter2) {
150 printf("Relation exists in incoming direction but not in outcoming (%d vs. %d).\n",
151 counter1,
152 counter2);
153 }
154 }
155 }
156
157 /* Validate node valency calculated in both directions. */
158 for (deg::OperationNode *node : deg_graph->operations) {
159 node->num_links_pending = 0;
160 node->custom_flags = 0;
161 }
162
163 for (deg::OperationNode *node : deg_graph->operations) {
164 if (node->custom_flags) {
165 printf("Node %s is twice in the operations!\n", node->identifier().c_str());
166 return false;
167 }
168 for (deg::Relation *rel : node->outlinks) {
169 if (rel->to->type == deg::NodeType::OPERATION) {
170 deg::OperationNode *to = (deg::OperationNode *)rel->to;
171 BLI_assert(to->num_links_pending < to->inlinks.size());
172 ++to->num_links_pending;
173 }
174 }
175 node->custom_flags = 1;
176 }
177
178 for (deg::OperationNode *node : deg_graph->operations) {
179 int num_links_pending = 0;
180 for (deg::Relation *rel : node->inlinks) {
181 if (rel->from->type == deg::NodeType::OPERATION) {
182 num_links_pending++;
183 }
184 }
185 if (node->num_links_pending != num_links_pending) {
186 printf("Valency mismatch: %s, %u != %d\n",
187 node->identifier().c_str(),
188 node->num_links_pending,
189 num_links_pending);
190 printf("Number of inlinks: %d\n", (int)node->inlinks.size());
191 return false;
192 }
193 }
194 return true;
195 }
196
197 /* ------------------------------------------------ */
198
199 /**
200 * Obtain simple statistics about the complexity of the depsgraph.
201 * \param[out] r_outer: The number of outer nodes in the graph
202 * \param[out] r_operations: The number of operation nodes in the graph
203 * \param[out] r_relations: The number of relations between (executable) nodes in the graph
204 */
DEG_stats_simple(const Depsgraph * graph,size_t * r_outer,size_t * r_operations,size_t * r_relations)205 void DEG_stats_simple(const Depsgraph *graph,
206 size_t *r_outer,
207 size_t *r_operations,
208 size_t *r_relations)
209 {
210 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
211
212 /* number of operations */
213 if (r_operations) {
214 /* All operations should be in this list, allowing us to count the total
215 * number of nodes. */
216 *r_operations = deg_graph->operations.size();
217 }
218
219 /* Count number of outer nodes and/or relations between these. */
220 if (r_outer || r_relations) {
221 size_t tot_outer = 0;
222 size_t tot_rels = 0;
223
224 for (deg::IDNode *id_node : deg_graph->id_nodes) {
225 tot_outer++;
226 for (deg::ComponentNode *comp_node : id_node->components.values()) {
227 tot_outer++;
228 for (deg::OperationNode *op_node : comp_node->operations) {
229 tot_rels += op_node->inlinks.size();
230 }
231 }
232 }
233
234 deg::TimeSourceNode *time_source = deg_graph->find_time_source();
235 if (time_source != nullptr) {
236 tot_rels += time_source->inlinks.size();
237 }
238
239 if (r_relations) {
240 *r_relations = tot_rels;
241 }
242 if (r_outer) {
243 *r_outer = tot_outer;
244 }
245 }
246 }
247
depsgraph_name_for_logging(struct Depsgraph * depsgraph)248 static deg::string depsgraph_name_for_logging(struct Depsgraph *depsgraph)
249 {
250 const char *name = DEG_debug_name_get(depsgraph);
251 if (name[0] == '\0') {
252 return "";
253 }
254 return "[" + deg::string(name) + "]: ";
255 }
256
DEG_debug_print_begin(struct Depsgraph * depsgraph)257 void DEG_debug_print_begin(struct Depsgraph *depsgraph)
258 {
259 fprintf(stdout, "%s", depsgraph_name_for_logging(depsgraph).c_str());
260 }
261
DEG_debug_print_eval(struct Depsgraph * depsgraph,const char * function_name,const char * object_name,const void * object_address)262 void DEG_debug_print_eval(struct Depsgraph *depsgraph,
263 const char *function_name,
264 const char *object_name,
265 const void *object_address)
266 {
267 if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
268 return;
269 }
270 fprintf(stdout,
271 "%s%s on %s %s(%p)%s\n",
272 depsgraph_name_for_logging(depsgraph).c_str(),
273 function_name,
274 object_name,
275 deg::color_for_pointer(object_address).c_str(),
276 object_address,
277 deg::color_end().c_str());
278 fflush(stdout);
279 }
280
DEG_debug_print_eval_subdata(struct Depsgraph * depsgraph,const char * function_name,const char * object_name,const void * object_address,const char * subdata_comment,const char * subdata_name,const void * subdata_address)281 void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph,
282 const char *function_name,
283 const char *object_name,
284 const void *object_address,
285 const char *subdata_comment,
286 const char *subdata_name,
287 const void *subdata_address)
288 {
289 if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
290 return;
291 }
292 fprintf(stdout,
293 "%s%s on %s %s(%p)%s %s %s %s(%p)%s\n",
294 depsgraph_name_for_logging(depsgraph).c_str(),
295 function_name,
296 object_name,
297 deg::color_for_pointer(object_address).c_str(),
298 object_address,
299 deg::color_end().c_str(),
300 subdata_comment,
301 subdata_name,
302 deg::color_for_pointer(subdata_address).c_str(),
303 subdata_address,
304 deg::color_end().c_str());
305 fflush(stdout);
306 }
307
DEG_debug_print_eval_subdata_index(struct Depsgraph * depsgraph,const char * function_name,const char * object_name,const void * object_address,const char * subdata_comment,const char * subdata_name,const void * subdata_address,const int subdata_index)308 void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph,
309 const char *function_name,
310 const char *object_name,
311 const void *object_address,
312 const char *subdata_comment,
313 const char *subdata_name,
314 const void *subdata_address,
315 const int subdata_index)
316 {
317 if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
318 return;
319 }
320 fprintf(stdout,
321 "%s%s on %s %s(%p)%s %s %s[%d] %s(%p)%s\n",
322 depsgraph_name_for_logging(depsgraph).c_str(),
323 function_name,
324 object_name,
325 deg::color_for_pointer(object_address).c_str(),
326 object_address,
327 deg::color_end().c_str(),
328 subdata_comment,
329 subdata_name,
330 subdata_index,
331 deg::color_for_pointer(subdata_address).c_str(),
332 subdata_address,
333 deg::color_end().c_str());
334 fflush(stdout);
335 }
336
DEG_debug_print_eval_parent_typed(struct Depsgraph * depsgraph,const char * function_name,const char * object_name,const void * object_address,const char * parent_comment,const char * parent_name,const void * parent_address)337 void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph,
338 const char *function_name,
339 const char *object_name,
340 const void *object_address,
341 const char *parent_comment,
342 const char *parent_name,
343 const void *parent_address)
344 {
345 if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
346 return;
347 }
348 fprintf(stdout,
349 "%s%s on %s %s(%p) [%s] %s %s %s(%p)%s\n",
350 depsgraph_name_for_logging(depsgraph).c_str(),
351 function_name,
352 object_name,
353 deg::color_for_pointer(object_address).c_str(),
354 object_address,
355 deg::color_end().c_str(),
356 parent_comment,
357 parent_name,
358 deg::color_for_pointer(parent_address).c_str(),
359 parent_address,
360 deg::color_end().c_str());
361 fflush(stdout);
362 }
363
DEG_debug_print_eval_time(struct Depsgraph * depsgraph,const char * function_name,const char * object_name,const void * object_address,float time)364 void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
365 const char *function_name,
366 const char *object_name,
367 const void *object_address,
368 float time)
369 {
370 if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
371 return;
372 }
373 fprintf(stdout,
374 "%s%s on %s %s(%p)%s at time %f\n",
375 depsgraph_name_for_logging(depsgraph).c_str(),
376 function_name,
377 object_name,
378 deg::color_for_pointer(object_address).c_str(),
379 object_address,
380 deg::color_end().c_str(),
381 time);
382 fflush(stdout);
383 }
384