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