diff --git a/easy_profiler_core/include/easy/reader.h b/easy_profiler_core/include/easy/reader.h index 18d03c7..1958017 100644 --- a/easy_profiler_core/include/easy/reader.h +++ b/easy_profiler_core/include/easy/reader.h @@ -63,14 +63,16 @@ namespace profiler { #pragma pack(push, 1) struct BlockStatistics EASY_FINAL { - ::profiler::timestamp_t total_duration; ///< Total duration of all block calls - ::profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration - ::profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration - ::profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats" - ::profiler::calls_number_t calls_number; ///< Block calls number + ::profiler::timestamp_t total_duration; ///< Total duration of all block calls + ::profiler::timestamp_t total_children_duration; ///< Total duration of all children of all block calls + ::profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration + ::profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration + ::profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats" + ::profiler::calls_number_t calls_number; ///< Block calls number explicit BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index, ::profiler::block_index_t _parent_index) : total_duration(_duration) + , total_children_duration(0) , min_duration_block(_block_index) , max_duration_block(_block_index) , parent_block(_parent_index) @@ -106,7 +108,7 @@ namespace profiler { ::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks) ::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) ::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread - uint16_t depth; ///< Maximum number of sublevels (maximum children depth) + uint8_t depth; ///< Maximum number of sublevels (maximum children depth) BlocksTree() : node(nullptr) @@ -205,7 +207,7 @@ namespace profiler { ::profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches) ::profiler::thread_id_t thread_id; ///< System Id of this thread ::profiler::block_index_t blocks_number; ///< Total blocks number including their children - uint16_t depth; ///< Maximum stack depth (number of levels) + uint8_t depth; ///< Maximum stack depth (number of levels) BlocksTreeRoot() : profiled_time(0), wait_time(0), thread_id(0), blocks_number(0), depth(0) { diff --git a/easy_profiler_core/reader.cpp b/easy_profiler_core/reader.cpp index 29a0e20..b56ed6c 100644 --- a/easy_profiler_core/reader.cpp +++ b/easy_profiler_core/reader.cpp @@ -216,7 +216,7 @@ typedef ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::BlockStat automatically receive statistics update. */ -::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks) +::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks, bool _calculate_children = true) { auto duration = _current.node->duration(); //StatsMap::key_type key(_current.node->name()); @@ -231,6 +231,12 @@ automatically receive statistics update. ++stats->calls_number; // update calls number of this block stats->total_duration += duration; // update summary duration of all block calls + if (_calculate_children) + { + for (auto i : _current.children) + stats->total_children_duration += _blocks[i].node->duration(); + } + if (duration > _blocks[stats->max_duration_block].node->duration()) { // update max duration @@ -256,10 +262,16 @@ automatically receive statistics update. //_stats_map.emplace(key, stats); _stats_map.emplace(_current.node->id(), stats); + if (_calculate_children) + { + for (auto i : _current.children) + stats->total_children_duration += _blocks[i].node->duration(); + } + return stats; } -::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks) +::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks, bool _calculate_children = true) { auto duration = _current.node->duration(); CsStatsMap::key_type key(_current.node->name()); @@ -273,6 +285,12 @@ automatically receive statistics update. ++stats->calls_number; // update calls number of this block stats->total_duration += duration; // update summary duration of all block calls + if (_calculate_children) + { + for (auto i : _current.children) + stats->total_children_duration += _blocks[i].node->duration(); + } + if (duration > _blocks[stats->max_duration_block].node->duration()) { // update max duration @@ -297,6 +315,12 @@ automatically receive statistics update. auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index); _stats_map.emplace(key, stats); + if (_calculate_children) + { + for (auto i : _current.children) + stats->total_children_duration += _blocks[i].node->duration(); + } + return stats; } @@ -304,9 +328,12 @@ automatically receive statistics update. void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, ::profiler::blocks_t& _blocks) { - _current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks); + _current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks, false); for (auto i : _current.children) + { + _current.per_frame_stats->total_children_duration += _blocks[i].node->duration(); update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks); + } } ////////////////////////////////////////////////////////////////////////// @@ -731,6 +758,19 @@ extern "C" { } } + if (tree.depth == 254) + { + // 254 because we need 1 additional level for root (thread). + // In other words: real stack depth = 1 root block + 254 children + + if (*tree.node->name() != 0) + _log << "Stack depth exceeded value of 254\nfor block \"" << desc->name() << "\""; + else + _log << "Stack depth exceeded value of 254\nfor block \"" << desc->name() << "\"\nfrom file \"" << desc->file() << "\":" << desc->line(); + + return 0; + } + ++tree.depth; } }