Cycles: Initial implementation of detailed statistics
authorSergey Sharybin <sergey.vfx@gmail.com>
Fri, 27 Jul 2018 13:46:13 +0000 (15:46 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 27 Jul 2018 15:19:54 +0000 (17:19 +0200)
Gathers information about object geometry and textures. Very basic at
this moment, but need to start somewhere.

Things which needs to be included still:

- "Runtime" information, like BVH. While it is not directly controllable
  by artists, it's still important to know.

- Device array sizes. Again, not under artists control, but is added to
  the overall size.

- Memory peak at different synchronization stages.

At this point it simply prints info to the stdout after F12 is done,
need better control over that too.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D3566

13 files changed:
intern/cycles/blender/addon/engine.py
intern/cycles/blender/blender_python.cpp
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_session.h
intern/cycles/render/CMakeLists.txt
intern/cycles/render/image.cpp
intern/cycles/render/image.h
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h
intern/cycles/render/scene.cpp
intern/cycles/render/scene.h
intern/cycles/render/stats.cpp [new file with mode: 0644]
intern/cycles/render/stats.h [new file with mode: 0644]

index 7e06b15..c30d199 100644 (file)
@@ -67,6 +67,9 @@ def _configure_argument_parser():
     parser.add_argument("--cycles-resumable-end-chunk",
                         help="End chunk to render",
                         default=None)
+    parser.add_argument("--cycles-print-stats",
+                        help="Print rendering statistics to stderr",
+                        action='store_true')
     return parser
 
 
@@ -95,6 +98,9 @@ def _parse_command_line():
                 int(args.cycles_resumable_start_chunk),
                 int(args.cycles_resumable_end_chunk),
             )
+    if args.cycles_print_stats:
+        import _cycles
+        _cycles.enable_print_stats()
 
 
 def init():
index 3eccecb..4b01eb5 100644 (file)
@@ -734,6 +734,12 @@ static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *a
        Py_RETURN_NONE;
 }
 
+static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+       BlenderSession::print_render_stats = true;
+       Py_RETURN_NONE;
+}
+
 static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
 {
        vector<DeviceInfo>& devices = Device::available_devices();
@@ -772,6 +778,9 @@ static PyMethodDef methods[] = {
        {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
        {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
 
+       /* Statistics. */
+       {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
+
        /* Resumable render */
        {"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
        {"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
index 00d23b9..e11b8e0 100644 (file)
@@ -28,6 +28,7 @@
 #include "render/scene.h"
 #include "render/session.h"
 #include "render/shader.h"
+#include "render/stats.h"
 
 #include "util/util_color.h"
 #include "util/util_foreach.h"
@@ -48,6 +49,7 @@ int BlenderSession::num_resumable_chunks = 0;
 int BlenderSession::current_resumable_chunk = 0;
 int BlenderSession::start_resumable_chunk = 0;
 int BlenderSession::end_resumable_chunk = 0;
+bool BlenderSession::print_render_stats = false;
 
 BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
                                BL::UserPreferences& b_userpref,
@@ -492,6 +494,12 @@ void BlenderSession::render()
                /* free result without merging */
                end_render_result(b_engine, b_rr, true, true, false);
 
+               if(!b_engine.is_preview() && background && print_render_stats) {
+                       RenderStats stats;
+                       session->scene->collect_statistics(&stats);
+                       printf("Render statistics:\n%s\n", stats.full_report().c_str());
+               }
+
                if(session->progress.get_cancel())
                        break;
        }
index 3804e07..08f5c87 100644 (file)
@@ -143,6 +143,8 @@ public:
        static int start_resumable_chunk;
        static int end_resumable_chunk;
 
+       static bool print_render_stats;
+
 protected:
        void do_write_update_render_result(BL::RenderResult& b_rr,
                                           BL::RenderLayer& b_rlay,
index b724835..7d2220f 100644 (file)
@@ -33,6 +33,7 @@ set(SRC
        session.cpp
        shader.cpp
        sobol.cpp
+       stats.cpp
        svm.cpp
        tables.cpp
        tile.cpp
@@ -60,6 +61,7 @@ set(SRC_HEADERS
        session.h
        shader.h
        sobol.h
+       stats.h
        svm.h
        tables.h
        tile.h
index 741dfb0..e6ef19c 100644 (file)
@@ -17,6 +17,7 @@
 #include "device/device.h"
 #include "render/image.h"
 #include "render/scene.h"
+#include "render/stats.h"
 
 #include "util/util_foreach.h"
 #include "util/util_logging.h"
@@ -1042,4 +1043,15 @@ void ImageManager::device_free(Device *device)
        }
 }
 
+void ImageManager::collect_statistics(RenderStats *stats)
+{
+       for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
+               foreach(const Image *image, images[type]) {
+                       stats->image.textures.add_entry(
+                               NamedSizeEntry(path_filename(image->filename),
+                                              image->mem->memory_size()));
+               }
+       }
+}
+
 CCL_NAMESPACE_END
index 9a2b373..d94ebe5 100644 (file)
@@ -29,6 +29,7 @@ CCL_NAMESPACE_BEGIN
 
 class Device;
 class Progress;
+class RenderStats;
 class Scene;
 
 class ImageMetaData {
@@ -89,6 +90,8 @@ public:
 
        device_memory *image_memory(int flat_slot);
 
+       void collect_statistics(RenderStats *stats);
+
        bool need_update;
 
        /* NOTE: Here pixels_size is a size of storage, which equals to
index df408b4..ade575a 100644 (file)
@@ -27,6 +27,7 @@
 #include "render/nodes.h"
 #include "render/object.h"
 #include "render/scene.h"
+#include "render/stats.h"
 
 #include "kernel/osl/osl_globals.h"
 
@@ -2276,6 +2277,15 @@ void MeshManager::tag_update(Scene *scene)
        scene->object_manager->need_update = true;
 }
 
+void MeshManager::collect_statistics(const Scene *scene, RenderStats *stats)
+{
+       foreach(Mesh *mesh, scene->meshes) {
+               stats->mesh.geometry.add_entry(
+                       NamedSizeEntry(string(mesh->name.c_str()),
+                                      mesh->get_total_size_in_bytes()));
+       }
+}
+
 bool Mesh::need_attribute(Scene *scene, AttributeStandard std)
 {
        if(std == ATTR_STD_NONE)
index fc7d0b4..444f03a 100644 (file)
@@ -38,6 +38,7 @@ class Device;
 class DeviceScene;
 class Mesh;
 class Progress;
+class RenderStats;
 class Scene;
 class SceneParams;
 class AttributeRequest;
@@ -351,6 +352,8 @@ public:
 
        void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress);
 
+       void collect_statistics(const Scene *scene, RenderStats *stats);
+
 protected:
        /* Calculate verts/triangles/curves offsets in global arrays. */
        void mesh_calc_offset(Scene *scene);
index 1d65ef6..9f93fed 100644 (file)
@@ -379,4 +379,10 @@ void Scene::device_free()
        free_memory(false);
 }
 
+void Scene::collect_statistics(RenderStats *stats)
+{
+       mesh_manager->collect_statistics(this, stats);
+       image_manager->collect_statistics(stats);
+}
+
 CCL_NAMESPACE_END
index 713eba6..dd80695 100644 (file)
@@ -56,6 +56,7 @@ class ShaderManager;
 class Progress;
 class BakeManager;
 class BakeData;
+class RenderStats;
 
 /* Scene Device Data */
 
@@ -255,6 +256,8 @@ public:
        void reset();
        void device_free();
 
+       void collect_statistics(RenderStats *stats);
+
 protected:
        /* Check if some heavy data worth logging was updated.
         * Mainly used to suppress extra annoying logging.
diff --git a/intern/cycles/render/stats.cpp b/intern/cycles/render/stats.cpp
new file mode 100644 (file)
index 0000000..101d33f
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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 "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;
+}
+
+}  // 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;
+}
+
+/* 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() {
+}
+
+string RenderStats::full_report()
+{
+       string result = "";
+       result += "Mesh statistics:\n" + mesh.full_report(1);
+       result += "Image statistics:\n" + image.full_report(1);
+       return result;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/stats.h b/intern/cycles/render/stats.h
new file mode 100644 (file)
index 0000000..72d5f1d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#ifndef __RENDER_STATS_H__
+#define __RENDER_STATS_H__
+
+#include "util/util_string.h"
+#include "util/util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Named statistics entry, which corresponds to a size. There is no real
+ * semantic around the units of size, it just should be the same for all
+ * entries.
+ *
+ * This is a generic entry foi all size-related statistics, which helps
+ * avoiding duplicating code for things like sorting.
+ */
+class NamedSizeEntry {
+public:
+       NamedSizeEntry();
+       NamedSizeEntry(const string& name, size_t size);
+
+       string name;
+       size_t size;
+};
+
+/* Container of named size entries. Used, for example, to store per-mesh memory
+ * usage statistics. But also keeps track of overall memory usage of the
+ * container.
+ */
+class NamedSizeStats {
+public:
+       NamedSizeStats();
+
+       /* Add entry to the statistics. */
+       void add_entry(const NamedSizeEntry& entry);
+
+       /* Generate full human-readable report. */
+       string full_report(int indent_level = 0);
+
+       /* Total size of all entries. */
+       size_t total_size;
+
+       /* NOTE: Is fine to read directly, but for adding use add_entry(), which
+        * makes sure all accumulating  values are properly updated.
+        */
+       vector<NamedSizeEntry> entries;
+};
+
+/* Statistics about mesh in the render database. */
+class MeshStats {
+public:
+       MeshStats();
+
+       /* Generate full human-readable report. */
+       string full_report(int indent_level = 0);
+
+       /* Input geometry statistics, this is what is coming as an input to render
+        * from. say, Blender. This does not include runtime or engine specific
+        * memory like BVH.
+        */
+       NamedSizeStats geometry;
+};
+
+/* Statistics about images held in memory. */
+class ImageStats {
+public:
+       ImageStats();
+
+       /* Generate full human-readable report. */
+       string full_report(int indent_level = 0);
+
+       NamedSizeStats textures;
+};
+
+/* Render process statistics. */
+class RenderStats {
+public:
+       RenderStats();
+
+       /* Return full report as string. */
+       string full_report();
+
+       MeshStats mesh;
+       ImageStats image;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __RENDER_STATS_H__ */