0
0
mirror of https://github.com/yse/easy_profiler.git synced 2025-01-14 00:27:55 +08:00

(profiler reader) Added calculation of maximum depth of the BlocksTree;

* Also added header into reader.cpp and added comments.
This commit is contained in:
Victor Zarubkin 2016-07-10 01:21:11 +03:00
parent 2939f07c2a
commit 8b4bd91147
2 changed files with 98 additions and 13 deletions

View File

@ -97,8 +97,9 @@ struct BlocksTree
::profiler::BlockStatistics* frame_statistics; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
::profiler::BlockStatistics* total_statistics; ///< Pointer to statistics for this block within the bounds of all frames per current thread
unsigned int total_children_number; ///< Number of all children including number of grandchildren (and so on)
unsigned short sublevels; ///< Maximum number of sublevels (maximum children depth)
BlocksTree() : node(nullptr), frame_statistics(nullptr), total_statistics(nullptr), total_children_number(0)
BlocksTree() : node(nullptr), frame_statistics(nullptr), total_statistics(nullptr), total_children_number(0), sublevels(0)
{
}
@ -158,6 +159,7 @@ private:
frame_statistics = that.frame_statistics;
total_statistics = that.total_statistics;
total_children_number = that.total_children_number;
sublevels = that.sublevels;
that.node = nullptr;
that.frame_statistics = nullptr;

View File

@ -1,3 +1,34 @@
/************************************************************************
* file name : reader.cpp
* ----------------- :
* creation time : 2016/06/19
* copyright : (c) 2016 Sergey Yagovtsev, Victor Zarubkin
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of fillTreesFromFile function
* : which reads profiler file and fill profiler blocks tree.
* ----------------- :
* change log : * 2016/06/19 Sergey Yagovtsev: First fillTreesFromFile implementation.
* :
* : * 2016/06/25 Victor Zarubkin: Removed unnecessary memory allocation and copy
* : when creating and inserting blocks into the tree.
* :
* : * 2016/06/26 Victor Zarubkin: Added statistics gathering (min, max, average duration,
* : number of block calls).
* : * 2016/06/26 Victor Zarubkin, Sergey Yagovtsev: Added statistics gathering for root
* : blocks in the tree.
* :
* : * 2016/06/29 Victor Zarubkin: Added calculaton of total children number for blocks.
* :
* : * 2016/06/30 Victor Zarubkin: Added this header.
* : Added tree depth calculation.
* :
* : *
* ----------------- :
* license : TODO: add license text
************************************************************************/
#include "profiler/reader.h"
#include <fstream>
#include <iterator>
@ -8,6 +39,17 @@
#ifdef _WIN32
/** \brief Simple C-string pointer with length.
It is used as base class for a key in std::unordered_map.
It is used to get better performance than std::string.
It simply stores a pointer and a length, there is no
any memory allocation and copy.
\note It is absolutely safe to store pointer because std::unordered_map,
which uses it as a key, exists only inside fillTreesFromFile function.
*/
class cstring
{
protected:
@ -46,6 +88,14 @@ public:
}
};
/** \brief cstring with precalculated hash.
This is used to calculate hash for C-string and to cache it
to be used in the future without recurring hash calculatoin.
\note This class is used as a key in std::unordered_map.
*/
class hashed_cstr : public cstring
{
typedef cstring Parent;
@ -76,6 +126,7 @@ public:
namespace std {
/** \brief Simply returns precalculated hash of a C-string. */
template <>
struct hash<hashed_cstr>
{
@ -99,6 +150,18 @@ typedef ::std::unordered_map<::std::string, ::profiler::BlockStatistics*> StatsM
//////////////////////////////////////////////////////////////////////////
/** \brief Updates statistics for a profiler block.
\param _stats_map Storage of statistics for blocks.
\param _current Pointer to the current block.
\param _stats Reference to the variable where pointer to the block statistics must be written.
\note All blocks with similar name have the same pointer to statistics information.
\note As all profiler block keeps a pointer to it's statistics, all similar blocks
automatically receive statistics update.
*/
void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _current, ::profiler::BlockStatistics*& _stats)
{
auto duration = _current->block()->duration();
@ -106,14 +169,17 @@ void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _curren
auto it = _stats_map.find(key);
if (it != _stats_map.end())
{
_stats = it->second;
// Update already existing statistics
++_stats->calls_number;
_stats->total_duration += duration;
_stats = it->second; // write pointer to statistics into output (this is BlocksTree::total_statistics or BlocksTree::frame_statistics)
++_stats->calls_number; // update calls number of this block
_stats->total_duration += duration; // update summary duration of all block calls
//if (duration > _stats->max_duration_block->block()->duration())
if (duration > _stats->max_duration)
{
// update max duration
_stats->max_duration_block = _current;
_stats->max_duration = duration;
}
@ -121,12 +187,17 @@ void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _curren
//if (duration < _stats->min_duration_block->block()->duration())
if (duration < _stats->min_duration)
{
// update min duraton
_stats->min_duration_block = _current;
_stats->min_duration = duration;
}
// average duration is calculated inside average_duration() method by dividing total_duration to the calls_number
}
else
{
// This is first time the block appear in the file.
// Create new statistics.
_stats = new ::profiler::BlockStatistics(duration, _current);
_stats_map.insert(::std::make_pair(key, _stats));
}
@ -192,9 +263,12 @@ extern "C"{
{
tree.total_children_number += child.total_children_number;
update_statistics(frame_statistics, child.node, child.frame_statistics);
if (tree.sublevels < child.sublevels)
tree.sublevels = child.sublevels;
}
tree.total_children_number += static_cast<unsigned int>(tree.children.size());
++tree.sublevels;
}
}
}
@ -216,30 +290,39 @@ extern "C"{
if (gather_statistics)
{
for (auto& root : threaded_trees)
for (auto& root_value : threaded_trees)
{
auto& root = root_value.second;
frame_statistics.clear();
for (auto& frame : root.second.children)
for (auto& frame : root.children)
{
root.second.total_children_number += frame.total_children_number;
root.total_children_number += frame.total_children_number;
update_statistics(frame_statistics, frame.node, frame.frame_statistics);
if (root.sublevels < frame.sublevels)
root.sublevels = frame.sublevels;
}
root.second.total_children_number += static_cast<unsigned int>(root.second.children.size());
root.total_children_number += static_cast<unsigned int>(root.children.size());
++root.sublevels;
}
}
else
{
for (auto& root : threaded_trees)
for (auto& root_value : threaded_trees)
{
for (auto& frame : root.second.children)
auto& root = root_value.second;
for (auto& frame : root.children)
{
root.second.total_children_number += frame.total_children_number;
root.total_children_number += frame.total_children_number;
if (root.sublevels < frame.sublevels)
root.sublevels = frame.sublevels;
}
root.second.total_children_number += static_cast<unsigned int>(root.second.children.size());
root.total_children_number += static_cast<unsigned int>(root.children.size());
++root.sublevels;
}
}
// No need to delete BlockStatistics instances - they will be deleted on BlocksTree destructors
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
return blocks_counter;
}