Blender V5.0
stats.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/stats.h"
6#include "scene/object.h"
7#include "util/algorithm.h"
8
9#include "util/string.h"
10
12
13static int kIndentNumSpaces = 2;
14
15/* Named size entry. */
16
17namespace {
18
19bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
20{
21 /* We sort in descending order. */
22 return a.size > b.size;
23}
24
25bool namedTimeEntryComparator(const NamedTimeEntry &a, const NamedTimeEntry &b)
26{
27 /* We sort in descending order. */
28 return a.time > b.time;
29}
30
31bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a,
33{
34 return a.sum_samples > b.sum_samples;
35}
36
37bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b)
38{
39 return a.samples > b.samples;
40}
41
42} // namespace
43
45
46NamedSizeEntry::NamedSizeEntry(const string &name, const size_t size) : name(name), size(size) {}
47
49
50NamedTimeEntry::NamedTimeEntry(const string &name, const double time) : name(name), time(time) {}
51
52/* Named size statistics. */
53
55
57{
58 total_size += entry.size;
59 entries.push_back(entry);
60}
61
62string NamedSizeStats::full_report(const int indent_level)
63{
64 const string indent(indent_level * kIndentNumSpaces, ' ');
65 const string double_indent = indent + indent;
66 string result;
67 result += string_printf("%sTotal memory: %s (%s)\n",
68 indent.c_str(),
71 sort(entries.begin(), entries.end(), namedSizeEntryComparator);
72 for (const NamedSizeEntry &entry : entries) {
73 result += string_printf("%s%-32s %s (%s)\n",
74 double_indent.c_str(),
75 entry.name.c_str(),
76 string_human_readable_size(entry.size).c_str(),
77 string_human_readable_number(entry.size).c_str());
78 }
79 return result;
80}
81
82string NamedTimeStats::full_report(const int indent_level)
83{
84 const string indent(indent_level * kIndentNumSpaces, ' ');
85 const string double_indent = indent + indent;
86 string result;
87 result += string_printf("%sTotal time: %fs\n", indent.c_str(), total_time);
88 sort(entries.begin(), entries.end(), namedTimeEntryComparator);
89 for (const NamedTimeEntry &entry : entries) {
91 "%s%-40s %fs\n", double_indent.c_str(), entry.name.c_str(), entry.time);
92 }
93 return result;
94}
95
96/* Named time sample statistics. */
97
99
101 : name(name), self_samples(samples), sum_samples(samples)
102{
103}
104
106{
107 entries.push_back(NamedNestedSampleStats(name_, samples_));
108 return entries[entries.size() - 1];
109}
110
112{
114 for (NamedNestedSampleStats &entry : entries) {
115 entry.update_sum();
116 sum_samples += entry.sum_samples;
117 }
118}
119
120string NamedNestedSampleStats::full_report(const int indent_level, uint64_t total_samples)
121{
122 update_sum();
123
124 if (total_samples == 0) {
125 total_samples = sum_samples;
126 }
127
128 const string indent(indent_level * kIndentNumSpaces, ' ');
129
130 const double sum_percent = 100 * ((double)sum_samples) / total_samples;
131 const double sum_seconds = sum_samples * 0.001;
132 const double self_percent = 100 * ((double)self_samples) / total_samples;
133 const double self_seconds = self_samples * 0.001;
134 const string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n",
135 name.c_str(),
136 sum_percent,
137 sum_seconds,
138 self_percent,
139 self_seconds);
140 string result = indent + info;
141
142 sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator);
143 for (NamedNestedSampleStats &entry : entries) {
144 result += entry.full_report(indent_level + 1, total_samples);
145 }
146 return result;
147}
148
149/* Named sample count pairs. */
150
157
159
160void NamedSampleCountStats::add(const ustring &name, const uint64_t samples, const uint64_t hits)
161{
162 const entry_map::iterator entry = entries.find(name);
163 if (entry != entries.end()) {
164 entry->second.samples += samples;
165 entry->second.hits += hits;
166 return;
167 }
168 entries.emplace(name, NamedSampleCountPair(name, samples, hits));
169}
170
171string NamedSampleCountStats::full_report(const int indent_level)
172{
173 const string indent(indent_level * kIndentNumSpaces, ' ');
174
175 vector<NamedSampleCountPair> sorted_entries;
176 sorted_entries.reserve(entries.size());
177
178 uint64_t total_hits = 0;
179 uint64_t total_samples = 0;
180 for (entry_map::const_reference entry : entries) {
181 const NamedSampleCountPair &pair = entry.second;
182
183 total_hits += pair.hits;
184 total_samples += pair.samples;
185
186 sorted_entries.push_back(pair);
187 }
188 const double avg_samples_per_hit = ((double)total_samples) / total_hits;
189
190 sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator);
191
192 string result;
193 for (const NamedSampleCountPair &entry : sorted_entries) {
194 const double seconds = entry.samples * 0.001;
195 const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit);
196
197 result += indent +
199 "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative);
200 }
201 return result;
202}
203
204/* Mesh statistics. */
205
206MeshStats::MeshStats() = default;
207
208string MeshStats::full_report(const int indent_level)
209{
210 const string indent(indent_level * kIndentNumSpaces, ' ');
211 string result;
212 result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
213 return result;
214}
215
216/* Image statistics. */
217
218ImageStats::ImageStats() = default;
219
220string ImageStats::full_report(const int indent_level)
221{
222 const string indent(indent_level * kIndentNumSpaces, ' ');
223 string result;
224 result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
225 return result;
226}
227
228/* Overall statistics. */
229
234
236{
237 has_profiling = true;
238
239 kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN));
240 kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP));
241 kernel.add_entry("Intersect Closest", prof.get_event(PROFILING_INTERSECT_CLOSEST));
242 kernel.add_entry("Intersect Shadow", prof.get_event(PROFILING_INTERSECT_SHADOW));
243 kernel.add_entry("Intersect Subsurface", prof.get_event(PROFILING_INTERSECT_SUBSURFACE));
244 kernel.add_entry("Intersect Volume Stack", prof.get_event(PROFILING_INTERSECT_VOLUME_STACK));
245 kernel.add_entry("Intersect Blocked Light", prof.get_event(PROFILING_INTERSECT_DEDICATED_LIGHT));
246
247 NamedNestedSampleStats &surface = kernel.add_entry("Shade Surface", 0);
248 surface.add_entry("Setup", prof.get_event(PROFILING_SHADE_SURFACE_SETUP));
249 surface.add_entry("Shader Evaluation", prof.get_event(PROFILING_SHADE_SURFACE_EVAL));
250 surface.add_entry("Render Passes", prof.get_event(PROFILING_SHADE_SURFACE_PASSES));
251 surface.add_entry("Direct Light", prof.get_event(PROFILING_SHADE_SURFACE_DIRECT_LIGHT));
252 surface.add_entry("Indirect Light", prof.get_event(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT));
253 surface.add_entry("Ambient Occlusion", prof.get_event(PROFILING_SHADE_SURFACE_AO));
254
255 NamedNestedSampleStats &volume = kernel.add_entry("Shade Volume", 0);
256 volume.add_entry("Setup", prof.get_event(PROFILING_SHADE_VOLUME_SETUP));
257 volume.add_entry("Integrate", prof.get_event(PROFILING_SHADE_VOLUME_INTEGRATE));
258 volume.add_entry("Direct Light", prof.get_event(PROFILING_SHADE_VOLUME_DIRECT_LIGHT));
259 volume.add_entry("Indirect Light", prof.get_event(PROFILING_SHADE_VOLUME_INDIRECT_LIGHT));
260
261 NamedNestedSampleStats &shadow = kernel.add_entry("Shade Shadow", 0);
262 shadow.add_entry("Setup", prof.get_event(PROFILING_SHADE_SHADOW_SETUP));
263 shadow.add_entry("Surface", prof.get_event(PROFILING_SHADE_SHADOW_SURFACE));
264 shadow.add_entry("Volume", prof.get_event(PROFILING_SHADE_SHADOW_VOLUME));
265 shadow.add_entry("Blocked Light", prof.get_event(PROFILING_SHADE_DEDICATED_LIGHT));
266
267 NamedNestedSampleStats &light = kernel.add_entry("Shade Light", 0);
268 light.add_entry("Setup", prof.get_event(PROFILING_SHADE_LIGHT_SETUP));
269 light.add_entry("Shader Evaluation", prof.get_event(PROFILING_SHADE_LIGHT_EVAL));
270
271 shaders.entries.clear();
272 for (Shader *shader : scene->shaders) {
273 uint64_t samples;
274 uint64_t hits;
275 if (prof.get_shader(shader->id, samples, hits)) {
276 shaders.add(shader->name, samples, hits);
277 }
278 }
279
280 objects.entries.clear();
281 for (Object *object : scene->objects) {
282 uint64_t samples;
283 uint64_t hits;
284 if (prof.get_object(object->get_device_index(), samples, hits)) {
285 objects.add(object->name, samples, hits);
286 }
287 }
288}
289
291{
292 string result;
293 result += "Mesh statistics:\n" + mesh.full_report(1);
294 result += "Image statistics:\n" + image.full_report(1);
295 if (has_profiling) {
296 result += "Kernel statistics:\n" + kernel.full_report(1);
297 result += "Shader statistics:\n" + shaders.full_report(1);
298 result += "Object statistics:\n" + objects.full_report(1);
299 }
300 else {
301 result += "Profiling information not available (only works with CPU rendering)";
302 }
303 return result;
304}
305
307
308string UpdateTimeStats::full_report(const int indent_level)
309{
310 return times.full_report(indent_level + 1);
311}
312
314
316{
317 string result;
318 result += "Scene:\n" + scene.full_report(1);
319 result += "Geometry:\n" + geometry.full_report(1);
320 result += "Light:\n" + light.full_report(1);
321 result += "Object:\n" + object.full_report(1);
322 result += "Image:\n" + image.full_report(1);
323 result += "Background:\n" + background.full_report(1);
324 result += "Bake:\n" + bake.full_report(1);
325 result += "Camera:\n" + camera.full_report(1);
326 result += "Film:\n" + film.full_report(1);
327 result += "Integrator:\n" + integrator.full_report(1);
328 result += "OSL:\n" + osl.full_report(1);
329 result += "Particles:\n" + particles.full_report(1);
330 result += "SVM:\n" + svm.full_report(1);
331 result += "Tables:\n" + tables.full_report(1);
332 result += "Procedurals:\n" + procedurals.full_report(1);
333 return result;
334}
335
337{
338 geometry.times.clear();
339 image.times.clear();
340 light.times.clear();
341 object.times.clear();
342 background.times.clear();
343 bake.times.clear();
344 camera.times.clear();
345 film.times.clear();
346 integrator.times.clear();
347 osl.times.clear();
348 particles.times.clear();
349 scene.times.clear();
350 svm.times.clear();
351 tables.times.clear();
352 procedurals.times.clear();
353}
354
unsigned long long int uint64_t
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
Definition btDbvt.cpp:418
NamedSizeStats textures
string full_report(const int indent_level=0)
Definition stats.cpp:220
string full_report(const int indent_level=0)
Definition stats.cpp:208
NamedSizeStats geometry
vector< NamedNestedSampleStats > entries
NamedNestedSampleStats & add_entry(const string &name, const uint64_t samples)
Definition stats.cpp:105
string full_report(const int indent_level=0, const uint64_t total_samples=0)
Definition stats.cpp:120
NamedSampleCountPair(const ustring &name, const uint64_t samples, const uint64_t hits)
Definition stats.cpp:151
string full_report(const int indent_level=0)
Definition stats.cpp:171
void add(const ustring &name, const uint64_t samples, const uint64_t hits)
Definition stats.cpp:160
void add_entry(const NamedSizeEntry &entry)
Definition stats.cpp:56
string full_report(const int indent_level=0)
Definition stats.cpp:62
size_t total_size
Definition scene/stats.h:54
vector< NamedSizeEntry > entries
Definition scene/stats.h:59
double total_time
Definition scene/stats.h:77
string full_report(const int indent_level=0)
Definition stats.cpp:82
vector< NamedTimeEntry > entries
Definition scene/stats.h:82
bool get_shader(const int shader, uint64_t &samples, uint64_t &hits)
uint64_t get_event(ProfilingEvent event)
bool get_object(const int object, uint64_t &samples, uint64_t &hits)
UpdateTimeStats tables
UpdateTimeStats image
UpdateTimeStats background
UpdateTimeStats light
UpdateTimeStats film
UpdateTimeStats camera
UpdateTimeStats geometry
string full_report()
Definition stats.cpp:315
UpdateTimeStats particles
UpdateTimeStats procedurals
UpdateTimeStats integrator
UpdateTimeStats osl
UpdateTimeStats scene
UpdateTimeStats svm
string full_report(const int indent_level=0)
Definition stats.cpp:308
NamedTimeStats times
#define CCL_NAMESPACE_END
@ PROFILING_SHADE_SURFACE_SETUP
Definition profiling.h:25
@ PROFILING_SHADE_SHADOW_SURFACE
Definition profiling.h:39
@ PROFILING_SHADE_VOLUME_INTEGRATE
Definition profiling.h:34
@ PROFILING_SHADE_SHADOW_VOLUME
Definition profiling.h:40
@ PROFILING_INTERSECT_SUBSURFACE
Definition profiling.h:20
@ PROFILING_INTERSECT_SHADOW
Definition profiling.h:21
@ PROFILING_INTERSECT_CLOSEST
Definition profiling.h:19
@ PROFILING_INTERSECT_DEDICATED_LIGHT
Definition profiling.h:23
@ PROFILING_SHADE_VOLUME_SETUP
Definition profiling.h:33
@ PROFILING_SHADE_SURFACE_EVAL
Definition profiling.h:26
@ PROFILING_SHADE_SURFACE_INDIRECT_LIGHT
Definition profiling.h:28
@ PROFILING_SHADE_SURFACE_AO
Definition profiling.h:29
@ PROFILING_SHADE_SURFACE_DIRECT_LIGHT
Definition profiling.h:27
@ PROFILING_SHADE_LIGHT_SETUP
Definition profiling.h:42
@ PROFILING_RAY_SETUP
Definition profiling.h:17
@ PROFILING_SHADE_SHADOW_SETUP
Definition profiling.h:38
@ PROFILING_SHADE_DEDICATED_LIGHT
Definition profiling.h:31
@ PROFILING_INTERSECT_VOLUME_STACK
Definition profiling.h:22
@ PROFILING_SHADE_VOLUME_DIRECT_LIGHT
Definition profiling.h:35
@ PROFILING_UNKNOWN
Definition profiling.h:16
@ PROFILING_SHADE_SURFACE_PASSES
Definition profiling.h:30
@ PROFILING_SHADE_LIGHT_EVAL
Definition profiling.h:43
@ PROFILING_SHADE_VOLUME_INDIRECT_LIGHT
Definition profiling.h:36
const char * name
static CCL_NAMESPACE_BEGIN int kIndentNumSpaces
Definition stats.cpp:13
string string_human_readable_size(size_t size)
Definition string.cpp:257
string string_human_readable_number(size_t num)
Definition string.cpp:276
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
ustring name
Definition graph/node.h:177
int get_device_index() const
void collect_profiling(Scene *scene, Profiler &prof)
Definition stats.cpp:235
bool has_profiling
string full_report()
Definition stats.cpp:290
NamedSampleCountStats shaders
NamedNestedSampleStats kernel
MeshStats mesh
ImageStats image
NamedSampleCountStats objects
unique_ptr_vector< Shader > shaders
Definition scene.h:137
unique_ptr_vector< Object > objects
Definition scene.h:141