From d93f23337a799856ddb3a8f118701686fec559a2 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Sun, 5 May 2019 01:09:12 +0100 Subject: [PATCH] Added stats to VoxelLodTerrain --- terrain/voxel_lod_terrain.cpp | 36 +++++++++++++++++++++++++++++-- terrain/voxel_lod_terrain.h | 16 +++++++++++++- terrain/voxel_mesh_updater.cpp | 8 +++++++ terrain/voxel_mesh_updater.h | 2 ++ terrain/voxel_provider_thread.cpp | 8 +++++++ terrain/voxel_provider_thread.h | 2 ++ terrain/voxel_terrain.cpp | 10 ++------- util/profiling_clock.h | 21 ++++++++++++++++++ 8 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 util/profiling_clock.h diff --git a/terrain/voxel_lod_terrain.cpp b/terrain/voxel_lod_terrain.cpp index edf0140..318ac87 100644 --- a/terrain/voxel_lod_terrain.cpp +++ b/terrain/voxel_lod_terrain.cpp @@ -1,10 +1,10 @@ #include "voxel_lod_terrain.h" #include "../math/rect3i.h" +#include "../util/profiling_clock.h" #include "voxel_map.h" #include "voxel_mesh_updater.h" #include "voxel_provider_thread.h" #include -#include VoxelLodTerrain::VoxelLodTerrain() { @@ -13,7 +13,7 @@ VoxelLodTerrain::VoxelLodTerrain() { _lods[0].map.instance(); set_lod_count(8); - set_lod_split_scale(3); + set_lod_split_scale(4); reset_updater(); } @@ -382,6 +382,8 @@ void VoxelLodTerrain::_process() { Vector3 viewer_pos = get_viewer_pos(); Vector3i viewer_block_pos = _lods[0].map->voxel_to_block(viewer_pos); + ProfilingClock profiling_clock; + // Here we go... // Find out which blocks _data_ need to be loaded @@ -466,12 +468,15 @@ void VoxelLodTerrain::_process() { _provider_thread->push(input); } + _stats.time_request_blocks_to_load = profiling_clock.restart(); + // Get block loading responses // Note: if block loading is too fast, this can cause stutters. // It should only happen on first load, though. { VoxelProviderThread::OutputData output; _provider_thread->pop(output); + _stats.provider = output.stats; for (int i = 0; i < output.emerged_blocks.size(); ++i) { @@ -541,6 +546,8 @@ void VoxelLodTerrain::_process() { } } + _stats.time_process_load_responses = profiling_clock.restart(); + // Send mesh updates { VoxelMeshUpdater::Input input; @@ -587,11 +594,14 @@ void VoxelLodTerrain::_process() { _block_updater->push(input); } + _stats.time_request_blocks_to_update = profiling_clock.restart(); + // Receive mesh updates { { VoxelMeshUpdater::Output output; _block_updater->pop(output); + _stats.updater = output.stats; for (unsigned int i = 0; i < output.blocks.size(); ++i) { const VoxelMeshUpdater::OutputBlock &ob = output.blocks[i]; @@ -666,6 +676,8 @@ void VoxelLodTerrain::_process() { shift_up(_blocks_pending_main_thread_update, queue_index); } + _stats.time_process_update_responses = profiling_clock.restart(); + // Find out which blocks need to be shown { struct SubdivideAction { @@ -733,6 +745,25 @@ void VoxelLodTerrain::_process() { _lod_octree.update(viewer_pos, subdivide_action, unsubdivide_action); } + + _stats.time_process_lod = profiling_clock.restart(); +} + +Dictionary VoxelLodTerrain::get_stats() const { + + Dictionary process; + process["time_request_blocks_to_load"] = _stats.time_request_blocks_to_load; + process["time_process_load_responses"] = _stats.time_process_load_responses; + process["time_request_blocks_to_update"] = _stats.time_request_blocks_to_update; + process["time_process_update_responses"] = _stats.time_process_update_responses; + process["time_process_lod"] = _stats.time_process_lod; + + Dictionary d; + d["provider"] = VoxelProviderThread::to_dictionary(_stats.provider); + d["updater"] = VoxelMeshUpdater::to_dictionary(_stats.updater); + d["process"] = process; + + return d; } void VoxelLodTerrain::_bind_methods() { @@ -752,6 +783,7 @@ void VoxelLodTerrain::_bind_methods() { ClassDB::bind_method(D_METHOD("get_block_state", "block_pos", "lod"), &VoxelLodTerrain::get_block_state); ClassDB::bind_method(D_METHOD("is_block_meshed", "block_pos", "lod"), &VoxelLodTerrain::is_block_meshed); ClassDB::bind_method(D_METHOD("is_block_shown", "block_pos", "lod"), &VoxelLodTerrain::is_block_shown); + ClassDB::bind_method(D_METHOD("get_stats"), &VoxelLodTerrain::get_stats); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "provider", PROPERTY_HINT_RESOURCE_TYPE, "VoxelProvider"), "set_provider", "get_provider"); ADD_PROPERTY(PropertyInfo(Variant::INT, "view_distance"), "set_view_distance", "get_view_distance"); diff --git a/terrain/voxel_lod_terrain.h b/terrain/voxel_lod_terrain.h index 38c8c16..76fd28b 100644 --- a/terrain/voxel_lod_terrain.h +++ b/terrain/voxel_lod_terrain.h @@ -5,11 +5,11 @@ #include "lod_octree.h" #include "voxel_map.h" #include "voxel_mesh_updater.h" +#include "voxel_provider_thread.h" #include #include class VoxelMap; -class VoxelProviderThread; // Paged terrain made of voxel blocks of variable level of detail. // Designed for highest view distances, preferably using smooth voxels. @@ -53,6 +53,18 @@ public: bool is_block_meshed(Vector3 bpos, unsigned int lod_index) const; bool is_block_shown(Vector3 bpos, unsigned int lod_index) const; + struct Stats { + VoxelMeshUpdater::Stats updater; + VoxelProviderThread::Stats provider; + uint64_t time_request_blocks_to_load = 0; + uint64_t time_process_load_responses = 0; + uint64_t time_request_blocks_to_update = 0; + uint64_t time_process_update_responses = 0; + uint64_t time_process_lod = 0; + }; + + Dictionary get_stats() const; + protected: static void _bind_methods(); @@ -113,6 +125,8 @@ private: }; Lod _lods[MAX_LOD]; + + Stats _stats; }; VARIANT_ENUM_CAST(VoxelLodTerrain::BlockState) diff --git a/terrain/voxel_mesh_updater.cpp b/terrain/voxel_mesh_updater.cpp index 99e9427..531f918 100644 --- a/terrain/voxel_mesh_updater.cpp +++ b/terrain/voxel_mesh_updater.cpp @@ -307,3 +307,11 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) { sorter.sort(_input.blocks.ptrw(), _input.blocks.size()); } } + +Dictionary VoxelMeshUpdater::to_dictionary(const Stats &stats) { + Dictionary d; + d["min_time"] = stats.min_time; + d["max_time"] = stats.max_time; + d["remaining_blocks"] = stats.remaining_blocks; + return d; +} diff --git a/terrain/voxel_mesh_updater.h b/terrain/voxel_mesh_updater.h index 5dcf535..0dd2a47 100644 --- a/terrain/voxel_mesh_updater.h +++ b/terrain/voxel_mesh_updater.h @@ -61,6 +61,8 @@ public: int get_required_padding() const; + static Dictionary to_dictionary(const Stats &stats); + private: static void _thread_func(void *p_self); void thread_func(); diff --git a/terrain/voxel_provider_thread.cpp b/terrain/voxel_provider_thread.cpp index 3ed8a58..55d5f62 100644 --- a/terrain/voxel_provider_thread.cpp +++ b/terrain/voxel_provider_thread.cpp @@ -207,3 +207,11 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) { sorter.sort(_input.blocks_to_emerge.ptrw(), _input.blocks_to_emerge.size()); } } + +Dictionary VoxelProviderThread::to_dictionary(const Stats &stats) { + Dictionary d; + d["min_time"] = stats.min_time; + d["max_time"] = stats.max_time; + d["remaining_blocks"] = stats.remaining_blocks; + return d; +} diff --git a/terrain/voxel_provider_thread.h b/terrain/voxel_provider_thread.h index c7dadd2..5efce25 100644 --- a/terrain/voxel_provider_thread.h +++ b/terrain/voxel_provider_thread.h @@ -57,6 +57,8 @@ public: void push(const InputData &input); void pop(OutputData &out_data); + static Dictionary to_dictionary(const Stats &stats); + private: static void _thread_func(void *p_self); diff --git a/terrain/voxel_terrain.cpp b/terrain/voxel_terrain.cpp index e83bf35..b98b436 100644 --- a/terrain/voxel_terrain.cpp +++ b/terrain/voxel_terrain.cpp @@ -218,16 +218,10 @@ void VoxelTerrain::immerge_block(Vector3i bpos) { Dictionary VoxelTerrain::get_statistics() const { - Dictionary provider; - provider["min_time"] = _stats.provider.min_time; - provider["max_time"] = _stats.provider.max_time; - provider["remaining_blocks"] = _stats.provider.remaining_blocks; + Dictionary provider = VoxelProviderThread::to_dictionary(_stats.provider); provider["dropped_blocks"] = _stats.dropped_provider_blocks; - Dictionary updater; - updater["min_time"] = _stats.updater.min_time; - updater["max_time"] = _stats.updater.max_time; - updater["remaining_blocks"] = _stats.updater.remaining_blocks; + Dictionary updater = VoxelMeshUpdater::to_dictionary(_stats.updater); updater["updated_blocks"] = _stats.updated_blocks; updater["mesh_alloc_time"] = _stats.mesh_alloc_time; updater["dropped_blocks"] = _stats.dropped_updater_blocks; diff --git a/util/profiling_clock.h b/util/profiling_clock.h new file mode 100644 index 0000000..6fca8ff --- /dev/null +++ b/util/profiling_clock.h @@ -0,0 +1,21 @@ +#ifndef PROFILING_CLOCK_H +#define PROFILING_CLOCK_H + +#include + +struct ProfilingClock { + uint64_t time_before = 0; + + ProfilingClock() { + restart(); + } + + uint64_t restart() { + uint64_t now = OS::get_singleton()->get_ticks_usec(); + uint64_t time_spent = now - time_before; + time_before = OS::get_singleton()->get_ticks_usec(); + return time_spent; + } +}; + +#endif // PROFILING_CLOCK_H