stats.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. #include "render/stats.h"
  17. #include "render/object.h"
  18. #include "util/util_algorithm.h"
  19. #include "util/util_foreach.h"
  20. #include "util/util_string.h"
  21. CCL_NAMESPACE_BEGIN
  22. static int kIndentNumSpaces = 2;
  23. /* Named size entry. */
  24. namespace {
  25. bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b)
  26. {
  27. /* We sort in descending order. */
  28. return a.size > b.size;
  29. }
  30. bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a,
  31. const NamedNestedSampleStats &b)
  32. {
  33. return a.sum_samples > b.sum_samples;
  34. }
  35. bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b)
  36. {
  37. return a.samples > b.samples;
  38. }
  39. } // namespace
  40. NamedSizeEntry::NamedSizeEntry() : name(""), size(0)
  41. {
  42. }
  43. NamedSizeEntry::NamedSizeEntry(const string &name, size_t size) : name(name), size(size)
  44. {
  45. }
  46. /* Named size statistics. */
  47. NamedSizeStats::NamedSizeStats() : total_size(0)
  48. {
  49. }
  50. void NamedSizeStats::add_entry(const NamedSizeEntry &entry)
  51. {
  52. total_size += entry.size;
  53. entries.push_back(entry);
  54. }
  55. string NamedSizeStats::full_report(int indent_level)
  56. {
  57. const string indent(indent_level * kIndentNumSpaces, ' ');
  58. const string double_indent = indent + indent;
  59. string result = "";
  60. result += string_printf("%sTotal memory: %s (%s)\n",
  61. indent.c_str(),
  62. string_human_readable_size(total_size).c_str(),
  63. string_human_readable_number(total_size).c_str());
  64. sort(entries.begin(), entries.end(), namedSizeEntryComparator);
  65. foreach (const NamedSizeEntry &entry, entries) {
  66. result += string_printf("%s%-32s %s (%s)\n",
  67. double_indent.c_str(),
  68. entry.name.c_str(),
  69. string_human_readable_size(entry.size).c_str(),
  70. string_human_readable_number(entry.size).c_str());
  71. }
  72. return result;
  73. }
  74. /* Named time sample statistics. */
  75. NamedNestedSampleStats::NamedNestedSampleStats() : name(""), self_samples(0), sum_samples(0)
  76. {
  77. }
  78. NamedNestedSampleStats::NamedNestedSampleStats(const string &name, uint64_t samples)
  79. : name(name), self_samples(samples), sum_samples(samples)
  80. {
  81. }
  82. NamedNestedSampleStats &NamedNestedSampleStats::add_entry(const string &name_, uint64_t samples_)
  83. {
  84. entries.push_back(NamedNestedSampleStats(name_, samples_));
  85. return entries[entries.size() - 1];
  86. }
  87. void NamedNestedSampleStats::update_sum()
  88. {
  89. sum_samples = self_samples;
  90. foreach (NamedNestedSampleStats &entry, entries) {
  91. entry.update_sum();
  92. sum_samples += entry.sum_samples;
  93. }
  94. }
  95. string NamedNestedSampleStats::full_report(int indent_level, uint64_t total_samples)
  96. {
  97. update_sum();
  98. if (total_samples == 0) {
  99. total_samples = sum_samples;
  100. }
  101. const string indent(indent_level * kIndentNumSpaces, ' ');
  102. const double sum_percent = 100 * ((double)sum_samples) / total_samples;
  103. const double sum_seconds = sum_samples * 0.001;
  104. const double self_percent = 100 * ((double)self_samples) / total_samples;
  105. const double self_seconds = self_samples * 0.001;
  106. string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n",
  107. name.c_str(),
  108. sum_percent,
  109. sum_seconds,
  110. self_percent,
  111. self_seconds);
  112. string result = indent + info;
  113. sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator);
  114. foreach (NamedNestedSampleStats &entry, entries) {
  115. result += entry.full_report(indent_level + 1, total_samples);
  116. }
  117. return result;
  118. }
  119. /* Named sample count pairs. */
  120. NamedSampleCountPair::NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits)
  121. : name(name), samples(samples), hits(hits)
  122. {
  123. }
  124. NamedSampleCountStats::NamedSampleCountStats()
  125. {
  126. }
  127. void NamedSampleCountStats::add(const ustring &name, uint64_t samples, uint64_t hits)
  128. {
  129. entry_map::iterator entry = entries.find(name);
  130. if (entry != entries.end()) {
  131. entry->second.samples += samples;
  132. entry->second.hits += hits;
  133. return;
  134. }
  135. entries.emplace(name, NamedSampleCountPair(name, samples, hits));
  136. }
  137. string NamedSampleCountStats::full_report(int indent_level)
  138. {
  139. const string indent(indent_level * kIndentNumSpaces, ' ');
  140. vector<NamedSampleCountPair> sorted_entries;
  141. sorted_entries.reserve(entries.size());
  142. uint64_t total_hits = 0, total_samples = 0;
  143. foreach (entry_map::const_reference entry, entries) {
  144. const NamedSampleCountPair &pair = entry.second;
  145. total_hits += pair.hits;
  146. total_samples += pair.samples;
  147. sorted_entries.push_back(pair);
  148. }
  149. const double avg_samples_per_hit = ((double)total_samples) / total_hits;
  150. sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator);
  151. string result = "";
  152. foreach (const NamedSampleCountPair &entry, sorted_entries) {
  153. const double seconds = entry.samples * 0.001;
  154. const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit);
  155. result += indent +
  156. string_printf(
  157. "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative);
  158. }
  159. return result;
  160. }
  161. /* Mesh statistics. */
  162. MeshStats::MeshStats()
  163. {
  164. }
  165. string MeshStats::full_report(int indent_level)
  166. {
  167. const string indent(indent_level * kIndentNumSpaces, ' ');
  168. string result = "";
  169. result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
  170. return result;
  171. }
  172. /* Image statistics. */
  173. ImageStats::ImageStats()
  174. {
  175. }
  176. string ImageStats::full_report(int indent_level)
  177. {
  178. const string indent(indent_level * kIndentNumSpaces, ' ');
  179. string result = "";
  180. result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
  181. return result;
  182. }
  183. /* Overall statistics. */
  184. RenderStats::RenderStats()
  185. {
  186. has_profiling = false;
  187. }
  188. void RenderStats::collect_profiling(Scene *scene, Profiler &prof)
  189. {
  190. has_profiling = true;
  191. kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN));
  192. kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP));
  193. kernel.add_entry("Result writing", prof.get_event(PROFILING_WRITE_RESULT));
  194. NamedNestedSampleStats &integrator = kernel.add_entry("Path integration",
  195. prof.get_event(PROFILING_PATH_INTEGRATE));
  196. integrator.add_entry("Scene intersection", prof.get_event(PROFILING_SCENE_INTERSECT));
  197. integrator.add_entry("Indirect emission", prof.get_event(PROFILING_INDIRECT_EMISSION));
  198. integrator.add_entry("Volumes", prof.get_event(PROFILING_VOLUME));
  199. NamedNestedSampleStats &shading = integrator.add_entry("Shading", 0);
  200. shading.add_entry("Shader Setup", prof.get_event(PROFILING_SHADER_SETUP));
  201. shading.add_entry("Shader Eval", prof.get_event(PROFILING_SHADER_EVAL));
  202. shading.add_entry("Shader Apply", prof.get_event(PROFILING_SHADER_APPLY));
  203. shading.add_entry("Ambient Occlusion", prof.get_event(PROFILING_AO));
  204. shading.add_entry("Subsurface", prof.get_event(PROFILING_SUBSURFACE));
  205. integrator.add_entry("Connect Light", prof.get_event(PROFILING_CONNECT_LIGHT));
  206. integrator.add_entry("Surface Bounce", prof.get_event(PROFILING_SURFACE_BOUNCE));
  207. NamedNestedSampleStats &intersection = kernel.add_entry("Intersection", 0);
  208. intersection.add_entry("Full Intersection", prof.get_event(PROFILING_INTERSECT));
  209. intersection.add_entry("Local Intersection", prof.get_event(PROFILING_INTERSECT_LOCAL));
  210. intersection.add_entry("Shadow All Intersection",
  211. prof.get_event(PROFILING_INTERSECT_SHADOW_ALL));
  212. intersection.add_entry("Volume Intersection", prof.get_event(PROFILING_INTERSECT_VOLUME));
  213. intersection.add_entry("Volume All Intersection",
  214. prof.get_event(PROFILING_INTERSECT_VOLUME_ALL));
  215. NamedNestedSampleStats &closure = kernel.add_entry("Closures", 0);
  216. closure.add_entry("Surface Closure Evaluation", prof.get_event(PROFILING_CLOSURE_EVAL));
  217. closure.add_entry("Surface Closure Sampling", prof.get_event(PROFILING_CLOSURE_SAMPLE));
  218. closure.add_entry("Volume Closure Evaluation", prof.get_event(PROFILING_CLOSURE_VOLUME_EVAL));
  219. closure.add_entry("Volume Closure Sampling", prof.get_event(PROFILING_CLOSURE_VOLUME_SAMPLE));
  220. NamedNestedSampleStats &denoising = kernel.add_entry("Denoising",
  221. prof.get_event(PROFILING_DENOISING));
  222. denoising.add_entry("Construct Transform",
  223. prof.get_event(PROFILING_DENOISING_CONSTRUCT_TRANSFORM));
  224. denoising.add_entry("Reconstruct", prof.get_event(PROFILING_DENOISING_RECONSTRUCT));
  225. NamedNestedSampleStats &prefilter = denoising.add_entry("Prefiltering", 0);
  226. prefilter.add_entry("Divide Shadow", prof.get_event(PROFILING_DENOISING_DIVIDE_SHADOW));
  227. prefilter.add_entry("Non-Local means", prof.get_event(PROFILING_DENOISING_NON_LOCAL_MEANS));
  228. prefilter.add_entry("Get Feature", prof.get_event(PROFILING_DENOISING_GET_FEATURE));
  229. prefilter.add_entry("Detect Outliers", prof.get_event(PROFILING_DENOISING_DETECT_OUTLIERS));
  230. prefilter.add_entry("Combine Halves", prof.get_event(PROFILING_DENOISING_COMBINE_HALVES));
  231. shaders.entries.clear();
  232. foreach (Shader *shader, scene->shaders) {
  233. uint64_t samples, hits;
  234. if (prof.get_shader(shader->id, samples, hits)) {
  235. shaders.add(shader->name, samples, hits);
  236. }
  237. }
  238. objects.entries.clear();
  239. foreach (Object *object, scene->objects) {
  240. uint64_t samples, hits;
  241. if (prof.get_object(object->get_device_index(), samples, hits)) {
  242. objects.add(object->name, samples, hits);
  243. }
  244. }
  245. }
  246. string RenderStats::full_report()
  247. {
  248. string result = "";
  249. result += "Mesh statistics:\n" + mesh.full_report(1);
  250. result += "Image statistics:\n" + image.full_report(1);
  251. if (has_profiling) {
  252. result += "Kernel statistics:\n" + kernel.full_report(1);
  253. result += "Shader statistics:\n" + shaders.full_report(1);
  254. result += "Object statistics:\n" + objects.full_report(1);
  255. }
  256. else {
  257. result += "Profiling information not available (only works with CPU rendering)";
  258. }
  259. return result;
  260. }
  261. CCL_NAMESPACE_END