123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- /*
- * Copyright 2011-2018 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "render/stats.h"
- #include "render/object.h"
- #include "util/util_algorithm.h"
- #include "util/util_foreach.h"
- #include "util/util_string.h"
- CCL_NAMESPACE_BEGIN
- static int kIndentNumSpaces = 2;
- /* Named size entry. */
- namespace {
- bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
- {
- /* 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(const string &name, size_t size) : name(name), size(size)
- {
- }
- /* Named size statistics. */
- NamedSizeStats::NamedSizeStats() : total_size(0)
- {
- }
- 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;
- }
- /* 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()
- {
- }
- 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;
- }
- /* Image statistics. */
- 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;
- }
- /* Overall statistics. */
- 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);
- 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
|