Blender  V2.93
stats.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2018 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "render/stats.h"
18 #include "render/object.h"
19 #include "util/util_algorithm.h"
20 #include "util/util_foreach.h"
21 #include "util/util_string.h"
22 
24 
25 static int kIndentNumSpaces = 2;
26 
27 /* Named size entry. */
28 
29 namespace {
30 
31 bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
32 {
33  /* We sort in descending order. */
34  return a.size > b.size;
35 }
36 
37 bool namedTimeEntryComparator(const NamedTimeEntry &a, const NamedTimeEntry &b)
38 {
39  /* We sort in descending order. */
40  return a.time > b.time;
41 }
42 
43 bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a,
44  const NamedNestedSampleStats &b)
45 {
46  return a.sum_samples > b.sum_samples;
47 }
48 
49 bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b)
50 {
51  return a.samples > b.samples;
52 }
53 
54 } // namespace
55 
57 {
58 }
59 
60 NamedSizeEntry::NamedSizeEntry(const string &name, size_t size) : name(name), size(size)
61 {
62 }
63 
65 {
66 }
67 
68 NamedTimeEntry::NamedTimeEntry(const string &name, double time) : name(name), time(time)
69 {
70 }
71 
72 /* Named size statistics. */
73 
75 {
76 }
77 
79 {
80  total_size += entry.size;
81  entries.push_back(entry);
82 }
83 
84 string NamedSizeStats::full_report(int indent_level)
85 {
86  const string indent(indent_level * kIndentNumSpaces, ' ');
87  const string double_indent = indent + indent;
88  string result = "";
89  result += string_printf("%sTotal memory: %s (%s)\n",
90  indent.c_str(),
93  sort(entries.begin(), entries.end(), namedSizeEntryComparator);
94  foreach (const NamedSizeEntry &entry, entries) {
95  result += string_printf("%s%-32s %s (%s)\n",
96  double_indent.c_str(),
97  entry.name.c_str(),
98  string_human_readable_size(entry.size).c_str(),
99  string_human_readable_number(entry.size).c_str());
100  }
101  return result;
102 }
103 
104 string NamedTimeStats::full_report(int indent_level)
105 {
106  const string indent(indent_level * kIndentNumSpaces, ' ');
107  const string double_indent = indent + indent;
108  string result = "";
109  result += string_printf("%sTotal time: %fs\n", indent.c_str(), total_time);
110  sort(entries.begin(), entries.end(), namedTimeEntryComparator);
111  foreach (const NamedTimeEntry &entry, entries) {
113  "%s%-40s %fs\n", double_indent.c_str(), entry.name.c_str(), entry.time);
114  }
115  return result;
116 }
117 
118 /* Named time sample statistics. */
119 
120 NamedNestedSampleStats::NamedNestedSampleStats() : name(""), self_samples(0), sum_samples(0)
121 {
122 }
123 
125  : name(name), self_samples(samples), sum_samples(samples)
126 {
127 }
128 
130 {
131  entries.push_back(NamedNestedSampleStats(name_, samples_));
132  return entries[entries.size() - 1];
133 }
134 
136 {
138  foreach (NamedNestedSampleStats &entry, entries) {
139  entry.update_sum();
140  sum_samples += entry.sum_samples;
141  }
142 }
143 
144 string NamedNestedSampleStats::full_report(int indent_level, uint64_t total_samples)
145 {
146  update_sum();
147 
148  if (total_samples == 0) {
149  total_samples = sum_samples;
150  }
151 
152  const string indent(indent_level * kIndentNumSpaces, ' ');
153 
154  const double sum_percent = 100 * ((double)sum_samples) / total_samples;
155  const double sum_seconds = sum_samples * 0.001;
156  const double self_percent = 100 * ((double)self_samples) / total_samples;
157  const double self_seconds = self_samples * 0.001;
158  string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n",
159  name.c_str(),
160  sum_percent,
161  sum_seconds,
162  self_percent,
163  self_seconds);
164  string result = indent + info;
165 
166  sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator);
167  foreach (NamedNestedSampleStats &entry, entries) {
168  result += entry.full_report(indent_level + 1, total_samples);
169  }
170  return result;
171 }
172 
173 /* Named sample count pairs. */
174 
176  : name(name), samples(samples), hits(hits)
177 {
178 }
179 
181 {
182 }
183 
184 void NamedSampleCountStats::add(const ustring &name, uint64_t samples, uint64_t hits)
185 {
186  entry_map::iterator entry = entries.find(name);
187  if (entry != entries.end()) {
188  entry->second.samples += samples;
189  entry->second.hits += hits;
190  return;
191  }
192  entries.emplace(name, NamedSampleCountPair(name, samples, hits));
193 }
194 
195 string NamedSampleCountStats::full_report(int indent_level)
196 {
197  const string indent(indent_level * kIndentNumSpaces, ' ');
198 
199  vector<NamedSampleCountPair> sorted_entries;
200  sorted_entries.reserve(entries.size());
201 
202  uint64_t total_hits = 0, total_samples = 0;
203  foreach (entry_map::const_reference entry, entries) {
204  const NamedSampleCountPair &pair = entry.second;
205 
206  total_hits += pair.hits;
207  total_samples += pair.samples;
208 
209  sorted_entries.push_back(pair);
210  }
211  const double avg_samples_per_hit = ((double)total_samples) / total_hits;
212 
213  sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator);
214 
215  string result = "";
216  foreach (const NamedSampleCountPair &entry, sorted_entries) {
217  const double seconds = entry.samples * 0.001;
218  const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit);
219 
220  result += indent +
222  "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative);
223  }
224  return result;
225 }
226 
227 /* Mesh statistics. */
228 
230 {
231 }
232 
233 string MeshStats::full_report(int indent_level)
234 {
235  const string indent(indent_level * kIndentNumSpaces, ' ');
236  string result = "";
237  result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
238  return result;
239 }
240 
241 /* Image statistics. */
242 
244 {
245 }
246 
247 string ImageStats::full_report(int indent_level)
248 {
249  const string indent(indent_level * kIndentNumSpaces, ' ');
250  string result = "";
251  result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
252  return result;
253 }
254 
255 /* Overall statistics. */
256 
258 {
259  has_profiling = false;
260 }
261 
263 {
264  has_profiling = true;
265 
266  kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN));
267 
268  kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP));
269  kernel.add_entry("Result writing", prof.get_event(PROFILING_WRITE_RESULT));
270 
271  NamedNestedSampleStats &integrator = kernel.add_entry("Path integration",
273  integrator.add_entry("Scene intersection", prof.get_event(PROFILING_SCENE_INTERSECT));
274  integrator.add_entry("Indirect emission", prof.get_event(PROFILING_INDIRECT_EMISSION));
275  integrator.add_entry("Volumes", prof.get_event(PROFILING_VOLUME));
276 
277  NamedNestedSampleStats &shading = integrator.add_entry("Shading", 0);
278  shading.add_entry("Shader Setup", prof.get_event(PROFILING_SHADER_SETUP));
279  shading.add_entry("Shader Eval", prof.get_event(PROFILING_SHADER_EVAL));
280  shading.add_entry("Shader Apply", prof.get_event(PROFILING_SHADER_APPLY));
281  shading.add_entry("Ambient Occlusion", prof.get_event(PROFILING_AO));
282  shading.add_entry("Subsurface", prof.get_event(PROFILING_SUBSURFACE));
283 
284  integrator.add_entry("Connect Light", prof.get_event(PROFILING_CONNECT_LIGHT));
285  integrator.add_entry("Surface Bounce", prof.get_event(PROFILING_SURFACE_BOUNCE));
286 
287  NamedNestedSampleStats &intersection = kernel.add_entry("Intersection", 0);
288  intersection.add_entry("Full Intersection", prof.get_event(PROFILING_INTERSECT));
289  intersection.add_entry("Local Intersection", prof.get_event(PROFILING_INTERSECT_LOCAL));
290  intersection.add_entry("Shadow All Intersection",
292  intersection.add_entry("Volume Intersection", prof.get_event(PROFILING_INTERSECT_VOLUME));
293  intersection.add_entry("Volume All Intersection",
295 
296  NamedNestedSampleStats &closure = kernel.add_entry("Closures", 0);
297  closure.add_entry("Surface Closure Evaluation", prof.get_event(PROFILING_CLOSURE_EVAL));
298  closure.add_entry("Surface Closure Sampling", prof.get_event(PROFILING_CLOSURE_SAMPLE));
299  closure.add_entry("Volume Closure Evaluation", prof.get_event(PROFILING_CLOSURE_VOLUME_EVAL));
300  closure.add_entry("Volume Closure Sampling", prof.get_event(PROFILING_CLOSURE_VOLUME_SAMPLE));
301 
302  NamedNestedSampleStats &denoising = kernel.add_entry("Denoising",
304  denoising.add_entry("Construct Transform",
306  denoising.add_entry("Reconstruct", prof.get_event(PROFILING_DENOISING_RECONSTRUCT));
307 
308  NamedNestedSampleStats &prefilter = denoising.add_entry("Prefiltering", 0);
309  prefilter.add_entry("Divide Shadow", prof.get_event(PROFILING_DENOISING_DIVIDE_SHADOW));
310  prefilter.add_entry("Non-Local means", prof.get_event(PROFILING_DENOISING_NON_LOCAL_MEANS));
311  prefilter.add_entry("Get Feature", prof.get_event(PROFILING_DENOISING_GET_FEATURE));
312  prefilter.add_entry("Detect Outliers", prof.get_event(PROFILING_DENOISING_DETECT_OUTLIERS));
313  prefilter.add_entry("Combine Halves", prof.get_event(PROFILING_DENOISING_COMBINE_HALVES));
314 
315  shaders.entries.clear();
316  foreach (Shader *shader, scene->shaders) {
317  uint64_t samples, hits;
318  if (prof.get_shader(shader->id, samples, hits)) {
319  shaders.add(shader->name, samples, hits);
320  }
321  }
322 
323  objects.entries.clear();
324  foreach (Object *object, scene->objects) {
325  uint64_t samples, hits;
326  if (prof.get_object(object->get_device_index(), samples, hits)) {
327  objects.add(object->name, samples, hits);
328  }
329  }
330 }
331 
333 {
334  string result = "";
335  result += "Mesh statistics:\n" + mesh.full_report(1);
336  result += "Image statistics:\n" + image.full_report(1);
337  if (has_profiling) {
338  result += "Kernel statistics:\n" + kernel.full_report(1);
339  result += "Shader statistics:\n" + shaders.full_report(1);
340  result += "Object statistics:\n" + objects.full_report(1);
341  }
342  else {
343  result += "Profiling information not available (only works with CPU rendering)";
344  }
345  return result;
346 }
347 
349 {
350 }
351 
352 string UpdateTimeStats::full_report(int indent_level)
353 {
354  return times.full_report(indent_level + 1);
355 }
356 
358 {
359 }
360 
362 {
363  string result = "";
364  result += "Scene:\n" + scene.full_report(1);
365  result += "Geometry:\n" + geometry.full_report(1);
366  result += "Light:\n" + light.full_report(1);
367  result += "Object:\n" + object.full_report(1);
368  result += "Image:\n" + image.full_report(1);
369  result += "Background:\n" + background.full_report(1);
370  result += "Bake:\n" + bake.full_report(1);
371  result += "Camera:\n" + camera.full_report(1);
372  result += "Film:\n" + film.full_report(1);
373  result += "Integrator:\n" + integrator.full_report(1);
374  result += "OSL:\n" + osl.full_report(1);
375  result += "Particles:\n" + particles.full_report(1);
376  result += "SVM:\n" + svm.full_report(1);
377  result += "Tables:\n" + tables.full_report(1);
378  result += "Procedurals:\n" + procedurals.full_report(1);
379  return result;
380 }
381 
383 {
384  geometry.times.clear();
385  image.times.clear();
386  light.times.clear();
387  object.times.clear();
389  bake.times.clear();
390  camera.times.clear();
391  film.times.clear();
393  osl.times.clear();
395  scene.times.clear();
396  svm.times.clear();
397  tables.times.clear();
399 }
400 
typedef double(DMatrix)[4][4]
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
string full_report(int indent_level=0)
Definition: stats.cpp:247
NamedSizeStats textures
Definition: stats.h:173
ImageStats()
Definition: stats.cpp:243
NamedSizeStats geometry
Definition: stats.h:162
MeshStats()
Definition: stats.cpp:229
string full_report(int indent_level=0)
Definition: stats.cpp:233
string full_report(int indent_level=0, uint64_t total_samples=0)
Definition: stats.cpp:144
uint64_t self_samples
Definition: stats.h:121
vector< NamedNestedSampleStats > entries
Definition: stats.h:123
uint64_t sum_samples
Definition: stats.h:121
NamedNestedSampleStats & add_entry(const string &name, uint64_t samples)
Definition: stats.cpp:129
uint64_t samples
Definition: stats.h:134
uint64_t hits
Definition: stats.h:135
NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits)
Definition: stats.cpp:175
entry_map entries
Definition: stats.h:147
string full_report(int indent_level=0)
Definition: stats.cpp:195
void add(const ustring &name, uint64_t samples, uint64_t hits)
Definition: stats.cpp:184
NamedSizeEntry()
Definition: stats.cpp:56
size_t size
Definition: stats.h:41
string name
Definition: stats.h:40
void add_entry(const NamedSizeEntry &entry)
Definition: stats.cpp:78
size_t total_size
Definition: stats.h:68
string full_report(int indent_level=0)
Definition: stats.cpp:84
NamedSizeStats()
Definition: stats.cpp:74
vector< NamedSizeEntry > entries
Definition: stats.h:73
double time
Definition: stats.h:50
NamedTimeEntry()
Definition: stats.cpp:64
string name
Definition: stats.h:49
double total_time
Definition: stats.h:91
void clear()
Definition: stats.h:98
string full_report(int indent_level=0)
Definition: stats.cpp:104
vector< NamedTimeEntry > entries
Definition: stats.h:96
uint64_t get_event(ProfilingEvent event)
bool get_shader(int shader, uint64_t &samples, uint64_t &hits)
bool get_object(int object, uint64_t &samples, uint64_t &hits)
UpdateTimeStats tables
Definition: stats.h:221
UpdateTimeStats image
Definition: stats.h:209
UpdateTimeStats background
Definition: stats.h:212
UpdateTimeStats light
Definition: stats.h:210
UpdateTimeStats bake
Definition: stats.h:213
UpdateTimeStats film
Definition: stats.h:215
UpdateTimeStats camera
Definition: stats.h:214
UpdateTimeStats geometry
Definition: stats.h:208
string full_report()
Definition: stats.cpp:361
UpdateTimeStats particles
Definition: stats.h:218
UpdateTimeStats procedurals
Definition: stats.h:222
UpdateTimeStats integrator
Definition: stats.h:216
UpdateTimeStats osl
Definition: stats.h:217
void clear()
Definition: stats.cpp:382
UpdateTimeStats scene
Definition: stats.h:219
UpdateTimeStats svm
Definition: stats.h:220
Definition: shader.h:80
NamedTimeStats times
Definition: stats.h:201
string full_report(int indent_level=0)
Definition: stats.cpp:352
double time
Scene scene
#define CCL_NAMESPACE_END
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
Intersection< segment > intersection
static unsigned a[3]
Definition: RandGen.cpp:92
static CCL_NAMESPACE_BEGIN int kIndentNumSpaces
Definition: stats.cpp:25
unsigned __int64 uint64_t
Definition: stdint.h:93
ustring name
Definition: node.h:174
int get_device_index() const
Definition: object.cpp:369
void collect_profiling(Scene *scene, Profiler &prof)
Definition: stats.cpp:262
bool has_profiling
Definition: stats.h:187
string full_report()
Definition: stats.cpp:332
NamedSampleCountStats shaders
Definition: stats.h:192
NamedNestedSampleStats kernel
Definition: stats.h:191
MeshStats mesh
Definition: stats.h:189
RenderStats()
Definition: stats.cpp:257
ImageStats image
Definition: stats.h:190
NamedSampleCountStats objects
Definition: stats.h:193
vector< Shader * > shaders
Definition: scene.h:236
vector< Object * > objects
Definition: scene.h:234
@ PROFILING_CLOSURE_EVAL
@ PROFILING_PATH_INTEGRATE
@ PROFILING_SURFACE_BOUNCE
@ PROFILING_DENOISING
@ PROFILING_AO
@ PROFILING_SHADER_SETUP
@ PROFILING_SHADER_EVAL
@ PROFILING_DENOISING_COMBINE_HALVES
@ PROFILING_SHADER_APPLY
@ PROFILING_INTERSECT_LOCAL
@ PROFILING_CLOSURE_SAMPLE
@ PROFILING_INTERSECT_VOLUME_ALL
@ PROFILING_INTERSECT_SHADOW_ALL
@ PROFILING_CLOSURE_VOLUME_SAMPLE
@ PROFILING_VOLUME
@ PROFILING_DENOISING_RECONSTRUCT
@ PROFILING_DENOISING_GET_FEATURE
@ PROFILING_DENOISING_DIVIDE_SHADOW
@ PROFILING_CONNECT_LIGHT
@ PROFILING_INTERSECT
@ PROFILING_SCENE_INTERSECT
@ PROFILING_CLOSURE_VOLUME_EVAL
@ PROFILING_RAY_SETUP
@ PROFILING_INTERSECT_VOLUME
@ PROFILING_SUBSURFACE
@ PROFILING_DENOISING_DETECT_OUTLIERS
@ PROFILING_UNKNOWN
@ PROFILING_DENOISING_CONSTRUCT_TRANSFORM
@ PROFILING_INDIRECT_EMISSION
@ PROFILING_WRITE_RESULT
@ PROFILING_DENOISING_NON_LOCAL_MEANS
string string_human_readable_size(size_t size)
string string_human_readable_number(size_t num)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: util_string.cpp:32