ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / render / stats.cpp
index 101d33f..0937b95 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "render/stats.h"
+#include "render/object.h"
 #include "util/util_algorithm.h"
 #include "util/util_foreach.h"
 #include "util/util_string.h"
@@ -27,93 +28,293 @@ static int kIndentNumSpaces = 2;
 
 namespace {
 
-bool namedSizeEntryComparator(const NamedSizeEntry& a, const NamedSizeEntry& b)
+bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
 {
-       /* We sort in descending order. */
-       return a.size > b.size;
+  /* We sort in descending order. */
+  return a.size > b.size;
+}
+
+bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a,
+                                    const NamedNestedSampleStats &b)
+{
+  return a.sum_samples > b.sum_samples;
+}
+
+bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b)
+{
+  return a.samples > b.samples;
 }
 
 }  // namespace
 
-NamedSizeEntry::NamedSizeEntry()
-    : name(""),
-      size(0) {
+NamedSizeEntry::NamedSizeEntry() : name(""), size(0)
+{
 }
 
-NamedSizeEntry::NamedSizeEntry(const string& name, size_t size)
-    : name(name),
-      size(size) {
+NamedSizeEntry::NamedSizeEntry(const string &name, size_t size) : name(name), size(size)
+{
 }
 
 /* Named size statistics. */
 
-NamedSizeStats::NamedSizeStats()
-    : total_size(0) {
+NamedSizeStats::NamedSizeStats() : total_size(0)
+{
 }
 
-void NamedSizeStats::add_entry(const NamedSizeEntry& entry) {
-       total_size += entry.size;
-       entries.push_back(entry);
+void NamedSizeStats::add_entry(const NamedSizeEntry &entry)
+{
+  total_size += entry.size;
+  entries.push_back(entry);
 }
 
 string NamedSizeStats::full_report(int indent_level)
 {
-       const string indent(indent_level * kIndentNumSpaces, ' ');
-       const string double_indent = indent + indent;
-       string result = "";
-       result += string_printf("%sTotal memory: %s (%s)\n",
-                               indent.c_str(),
-                               string_human_readable_size(total_size).c_str(),
-                               string_human_readable_number(total_size).c_str());
-       sort(entries.begin(), entries.end(), namedSizeEntryComparator);
-       foreach(const NamedSizeEntry& entry, entries) {
-               result += string_printf(
-                       "%s%-32s %s (%s)\n",
-                       double_indent.c_str(),
-                       entry.name.c_str(),
-                       string_human_readable_size(entry.size).c_str(),
-                       string_human_readable_number(entry.size).c_str());
-       }
-       return result;
+  const string indent(indent_level * kIndentNumSpaces, ' ');
+  const string double_indent = indent + indent;
+  string result = "";
+  result += string_printf("%sTotal memory: %s (%s)\n",
+                          indent.c_str(),
+                          string_human_readable_size(total_size).c_str(),
+                          string_human_readable_number(total_size).c_str());
+  sort(entries.begin(), entries.end(), namedSizeEntryComparator);
+  foreach (const NamedSizeEntry &entry, entries) {
+    result += string_printf("%s%-32s %s (%s)\n",
+                            double_indent.c_str(),
+                            entry.name.c_str(),
+                            string_human_readable_size(entry.size).c_str(),
+                            string_human_readable_number(entry.size).c_str());
+  }
+  return result;
+}
+
+/* Named time sample statistics. */
+
+NamedNestedSampleStats::NamedNestedSampleStats() : name(""), self_samples(0), sum_samples(0)
+{
+}
+
+NamedNestedSampleStats::NamedNestedSampleStats(const string &name, uint64_t samples)
+    : name(name), self_samples(samples), sum_samples(samples)
+{
+}
+
+NamedNestedSampleStats &NamedNestedSampleStats::add_entry(const string &name_, uint64_t samples_)
+{
+  entries.push_back(NamedNestedSampleStats(name_, samples_));
+  return entries[entries.size() - 1];
+}
+
+void NamedNestedSampleStats::update_sum()
+{
+  sum_samples = self_samples;
+  foreach (NamedNestedSampleStats &entry, entries) {
+    entry.update_sum();
+    sum_samples += entry.sum_samples;
+  }
+}
+
+string NamedNestedSampleStats::full_report(int indent_level, uint64_t total_samples)
+{
+  update_sum();
+
+  if (total_samples == 0) {
+    total_samples = sum_samples;
+  }
+
+  const string indent(indent_level * kIndentNumSpaces, ' ');
+
+  const double sum_percent = 100 * ((double)sum_samples) / total_samples;
+  const double sum_seconds = sum_samples * 0.001;
+  const double self_percent = 100 * ((double)self_samples) / total_samples;
+  const double self_seconds = self_samples * 0.001;
+  string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n",
+                              name.c_str(),
+                              sum_percent,
+                              sum_seconds,
+                              self_percent,
+                              self_seconds);
+  string result = indent + info;
+
+  sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator);
+  foreach (NamedNestedSampleStats &entry, entries) {
+    result += entry.full_report(indent_level + 1, total_samples);
+  }
+  return result;
+}
+
+/* Named sample count pairs. */
+
+NamedSampleCountPair::NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits)
+    : name(name), samples(samples), hits(hits)
+{
+}
+
+NamedSampleCountStats::NamedSampleCountStats()
+{
+}
+
+void NamedSampleCountStats::add(const ustring &name, uint64_t samples, uint64_t hits)
+{
+  entry_map::iterator entry = entries.find(name);
+  if (entry != entries.end()) {
+    entry->second.samples += samples;
+    entry->second.hits += hits;
+    return;
+  }
+  entries.emplace(name, NamedSampleCountPair(name, samples, hits));
+}
+
+string NamedSampleCountStats::full_report(int indent_level)
+{
+  const string indent(indent_level * kIndentNumSpaces, ' ');
+
+  vector<NamedSampleCountPair> sorted_entries;
+  sorted_entries.reserve(entries.size());
+
+  uint64_t total_hits = 0, total_samples = 0;
+  foreach (entry_map::const_reference entry, entries) {
+    const NamedSampleCountPair &pair = entry.second;
+
+    total_hits += pair.hits;
+    total_samples += pair.samples;
+
+    sorted_entries.push_back(pair);
+  }
+  const double avg_samples_per_hit = ((double)total_samples) / total_hits;
+
+  sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator);
+
+  string result = "";
+  foreach (const NamedSampleCountPair &entry, sorted_entries) {
+    const double seconds = entry.samples * 0.001;
+    const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit);
+
+    result += indent +
+              string_printf(
+                  "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative);
+  }
+  return result;
 }
 
 /* Mesh statistics. */
 
-MeshStats::MeshStats() {
+MeshStats::MeshStats()
+{
 }
 
 string MeshStats::full_report(int indent_level)
 {
-       const string indent(indent_level * kIndentNumSpaces, ' ');
-       string result = "";
-       result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
-       return result;
+  const string indent(indent_level * kIndentNumSpaces, ' ');
+  string result = "";
+  result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
+  return result;
 }
 
 /* Image statistics. */
 
-ImageStats::ImageStats() {
+ImageStats::ImageStats()
+{
 }
 
 string ImageStats::full_report(int indent_level)
 {
-       const string indent(indent_level * kIndentNumSpaces, ' ');
-       string result = "";
-       result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
-       return result;
+  const string indent(indent_level * kIndentNumSpaces, ' ');
+  string result = "";
+  result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
+  return result;
 }
 
 /* Overall statistics. */
 
-RenderStats::RenderStats() {
+RenderStats::RenderStats()
+{
+  has_profiling = false;
+}
+
+void RenderStats::collect_profiling(Scene *scene, Profiler &prof)
+{
+  has_profiling = true;
+
+  kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN));
+
+  kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP));
+  kernel.add_entry("Result writing", prof.get_event(PROFILING_WRITE_RESULT));
+
+  NamedNestedSampleStats &integrator = kernel.add_entry("Path integration",
+                                                        prof.get_event(PROFILING_PATH_INTEGRATE));
+  integrator.add_entry("Scene intersection", prof.get_event(PROFILING_SCENE_INTERSECT));
+  integrator.add_entry("Indirect emission", prof.get_event(PROFILING_INDIRECT_EMISSION));
+  integrator.add_entry("Volumes", prof.get_event(PROFILING_VOLUME));
+
+  NamedNestedSampleStats &shading = integrator.add_entry("Shading", 0);
+  shading.add_entry("Shader Setup", prof.get_event(PROFILING_SHADER_SETUP));
+  shading.add_entry("Shader Eval", prof.get_event(PROFILING_SHADER_EVAL));
+  shading.add_entry("Shader Apply", prof.get_event(PROFILING_SHADER_APPLY));
+  shading.add_entry("Ambient Occlusion", prof.get_event(PROFILING_AO));
+  shading.add_entry("Subsurface", prof.get_event(PROFILING_SUBSURFACE));
+
+  integrator.add_entry("Connect Light", prof.get_event(PROFILING_CONNECT_LIGHT));
+  integrator.add_entry("Surface Bounce", prof.get_event(PROFILING_SURFACE_BOUNCE));
+
+  NamedNestedSampleStats &intersection = kernel.add_entry("Intersection", 0);
+  intersection.add_entry("Full Intersection", prof.get_event(PROFILING_INTERSECT));
+  intersection.add_entry("Local Intersection", prof.get_event(PROFILING_INTERSECT_LOCAL));
+  intersection.add_entry("Shadow All Intersection",
+                         prof.get_event(PROFILING_INTERSECT_SHADOW_ALL));
+  intersection.add_entry("Volume Intersection", prof.get_event(PROFILING_INTERSECT_VOLUME));
+  intersection.add_entry("Volume All Intersection",
+                         prof.get_event(PROFILING_INTERSECT_VOLUME_ALL));
+
+  NamedNestedSampleStats &closure = kernel.add_entry("Closures", 0);
+  closure.add_entry("Surface Closure Evaluation", prof.get_event(PROFILING_CLOSURE_EVAL));
+  closure.add_entry("Surface Closure Sampling", prof.get_event(PROFILING_CLOSURE_SAMPLE));
+  closure.add_entry("Volume Closure Evaluation", prof.get_event(PROFILING_CLOSURE_VOLUME_EVAL));
+  closure.add_entry("Volume Closure Sampling", prof.get_event(PROFILING_CLOSURE_VOLUME_SAMPLE));
+
+  NamedNestedSampleStats &denoising = kernel.add_entry("Denoising",
+                                                       prof.get_event(PROFILING_DENOISING));
+  denoising.add_entry("Construct Transform",
+                      prof.get_event(PROFILING_DENOISING_CONSTRUCT_TRANSFORM));
+  denoising.add_entry("Reconstruct", prof.get_event(PROFILING_DENOISING_RECONSTRUCT));
+
+  NamedNestedSampleStats &prefilter = denoising.add_entry("Prefiltering", 0);
+  prefilter.add_entry("Divide Shadow", prof.get_event(PROFILING_DENOISING_DIVIDE_SHADOW));
+  prefilter.add_entry("Non-Local means", prof.get_event(PROFILING_DENOISING_NON_LOCAL_MEANS));
+  prefilter.add_entry("Get Feature", prof.get_event(PROFILING_DENOISING_GET_FEATURE));
+  prefilter.add_entry("Detect Outliers", prof.get_event(PROFILING_DENOISING_DETECT_OUTLIERS));
+  prefilter.add_entry("Combine Halves", prof.get_event(PROFILING_DENOISING_COMBINE_HALVES));
+
+  shaders.entries.clear();
+  foreach (Shader *shader, scene->shaders) {
+    uint64_t samples, hits;
+    if (prof.get_shader(shader->id, samples, hits)) {
+      shaders.add(shader->name, samples, hits);
+    }
+  }
+
+  objects.entries.clear();
+  foreach (Object *object, scene->objects) {
+    uint64_t samples, hits;
+    if (prof.get_object(object->get_device_index(), samples, hits)) {
+      objects.add(object->name, samples, hits);
+    }
+  }
 }
 
 string RenderStats::full_report()
 {
-       string result = "";
-       result += "Mesh statistics:\n" + mesh.full_report(1);
-       result += "Image statistics:\n" + image.full_report(1);
-       return result;
+  string result = "";
+  result += "Mesh statistics:\n" + mesh.full_report(1);
+  result += "Image statistics:\n" + image.full_report(1);
+  if (has_profiling) {
+    result += "Kernel statistics:\n" + kernel.full_report(1);
+    result += "Shader statistics:\n" + shaders.full_report(1);
+    result += "Object statistics:\n" + objects.full_report(1);
+  }
+  else {
+    result += "Profiling information not available (only works with CPU rendering)";
+  }
+  return result;
 }
 
 CCL_NAMESPACE_END