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