Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / depsgraph / intern / debug / deg_debug_stats_gnuplot.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) 2017 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file \ingroup depsgraph
21  */
22
23 #include "DEG_depsgraph_debug.h"
24
25 #include <algorithm>
26 #include <cstdarg>
27
28 #include "BLI_compiler_attrs.h"
29 #include "BLI_math_base.h"
30
31 #include "intern/depsgraph.h"
32 #include "intern/node/deg_node_id.h"
33
34 extern "C" {
35 #include "DNA_ID.h"
36 } /* extern "C" */
37
38 #define NL "\r\n"
39
40 namespace DEG {
41 namespace {
42
43 struct DebugContext {
44         FILE *file;
45         const Depsgraph *graph;
46         const char *label;
47         const char *output_filename;
48 };
49
50 struct StatsEntry {
51         const IDNode *id_node;
52         double time;
53 };
54
55 /* TODO(sergey): De-duplicate with graphviz relation debugger. */
56 static void deg_debug_fprintf(const DebugContext &ctx,
57                               const char *fmt,
58                               ...) ATTR_PRINTF_FORMAT(2, 3);
59 static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
60 {
61         va_list args;
62         va_start(args, fmt);
63         vfprintf(ctx.file, fmt, args);
64         va_end(args);
65 }
66
67 BLI_INLINE double get_node_time(const DebugContext& /*ctx*/,
68                                 const Node *node)
69 {
70         // TODO(sergey): Figure out a nice way to define which exact time
71         // we want to show.
72         return node->stats.current_time;
73 }
74
75 bool stat_entry_comparator(const StatsEntry& a, const StatsEntry& b)
76 {
77         return a.time > b.time;
78 }
79
80 string gnuplotify_id_code(const string& name)
81 {
82         return string("") + name[0] + name[1];
83 }
84
85 string gnuplotify_name(const string& name)
86 {
87         string result = "";
88         const int length = name.length();
89         for (int i = 0; i < length; ++i) {
90                 const char ch = name[i];
91                 if (ch == '_') {
92                         result += "\\\\\\";
93                 }
94                 result += ch;
95         }
96         return result;
97 }
98
99 void write_stats_data(const DebugContext& ctx)
100 {
101         // Fill in array of all stats which are to be displayed.
102         vector<StatsEntry> stats;
103         stats.reserve(ctx.graph->id_nodes.size());
104         for (const IDNode *id_node : ctx.graph->id_nodes) {
105                 const double time = get_node_time(ctx, id_node);
106                 if (time == 0.0) {
107                         continue;
108                 }
109                 StatsEntry entry;
110                 entry.id_node = id_node;
111                 entry.time = time;
112                 stats.push_back(entry);
113         }
114         // Sort the data.
115         std::sort(stats.begin(), stats.end(), stat_entry_comparator);
116         // We limit number of entries, otherwise things become unreadable.
117         stats.resize(min_ii(stats.size(), 32));
118         std::reverse(stats.begin(), stats.end());
119         // Print data to the file stream.
120         deg_debug_fprintf(ctx, "$data << EOD" NL);
121         for (const StatsEntry& entry : stats) {
122                 deg_debug_fprintf(
123                         ctx, "\"[%s] %s\",%f" NL,
124                         gnuplotify_id_code(entry.id_node->id_orig->name).c_str(),
125                         gnuplotify_name(entry.id_node->id_orig->name + 2).c_str(),
126                         entry.time);
127         }
128         deg_debug_fprintf(ctx, "EOD" NL);
129 }
130
131 void deg_debug_stats_gnuplot(const DebugContext& ctx)
132 {
133         // Data itself.
134         write_stats_data(ctx);
135         // Optional label.
136         if (ctx.label && ctx.label[0]) {
137                 deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label);
138         }
139         // Rest of the commands.
140         // TODO(sergey): Need to decide on the resolution somehow.
141         deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL);
142         deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename);
143         deg_debug_fprintf(ctx, "set grid" NL);
144         deg_debug_fprintf(ctx, "set datafile separator ','" NL);
145         deg_debug_fprintf(ctx, "set style fill solid" NL);
146         deg_debug_fprintf(ctx, "plot \"$data\" using " \
147                                "($2*0.5):0:($2*0.5):(0.2):yticlabels(1) "
148                                "with boxxyerrorbars t '' lt rgb \"#406090\"" NL);
149
150 }
151
152 }  // namespace
153 }  // namespace DEG
154
155 void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph,
156                              FILE *f,
157                              const char *label,
158                              const char *output_filename)
159 {
160         if (depsgraph == NULL) {
161                 return;
162         }
163         DEG::DebugContext ctx;
164         ctx.file = f;
165         ctx.graph = (DEG::Depsgraph *)depsgraph;
166         ctx.label = label;
167         ctx.output_filename = output_filename;
168         DEG::deg_debug_stats_gnuplot(ctx);
169 }