0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 00:31:02 +08:00

Memory consumtion optimization (almost 2 times less memory used on Windows)

This commit is contained in:
Victor Zarubkin 2016-08-14 16:05:10 +03:00
parent 3fd0b77d16
commit d38c869330
5 changed files with 216 additions and 195 deletions

View File

@ -346,10 +346,12 @@ namespace profiler
class PROFILER_API SerializedBlock final
{
uint16_t m_size;
char* m_data;
char* m_data;
uint16_t m_size;
public:
SerializedBlock(profiler::Block* block);
SerializedBlock(const profiler::Block* block);
SerializedBlock(uint16_t _size, char* _data);
SerializedBlock(SerializedBlock&& that);
SerializedBlock(const SerializedBlock& other);

View File

@ -21,8 +21,8 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <list>
#include <map>
#include <vector>
#include "profiler/profiler.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -30,29 +30,19 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
namespace profiler {
typedef uint32_t calls_number_t;
typedef uint32_t block_index_t;
#pragma pack(push, 1)
struct BlockStatistics final
{
::profiler::timestamp_t total_duration; ///< Summary duration of all block calls
::profiler::timestamp_t min_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high
::profiler::timestamp_t max_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high
unsigned int min_duration_block; ///< Will be used in GUI to jump to the block with min duration
unsigned int max_duration_block; ///< Will be used in GUI to jump to the block with max duration
::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::calls_number_t calls_number; ///< Block calls number
// TODO: It is better to replace SerilizedBlock* with BlocksTree*, but this requires to store pointers in children list.
BlockStatistics()
: total_duration(0)
, min_duration(0)
, max_duration(0)
, min_duration_block(0)
, max_duration_block(0)
, calls_number(1)
{
}
BlockStatistics(::profiler::timestamp_t _duration, unsigned int _block_index)
BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index)
: total_duration(_duration)
, min_duration(_duration)
, max_duration(_duration)
@ -68,6 +58,7 @@ namespace profiler {
}
}; // END of struct BlockStatistics.
#pragma pack(pop)
inline void release(BlockStatistics*& _stats)
{
@ -92,16 +83,15 @@ namespace profiler {
public:
typedef ::std::list<BlocksTree> children_t;
typedef ::std::vector<BlocksTree> children_t;
children_t children; ///< List of children blocks. May be empty.
::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
::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
unsigned int block_index; ///< Index of this block
unsigned int total_children_number; ///< Number of all children including number of grandchildren (and so on)
::profiler::block_index_t block_index; ///< Index of this block
unsigned short depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree()
@ -110,7 +100,6 @@ namespace profiler {
, per_frame_stats(nullptr)
, per_thread_stats(nullptr)
, block_index(0)
, total_children_number(0)
, depth(0)
{
@ -148,6 +137,21 @@ namespace profiler {
return node->block()->getBegin() < other.node->block()->getBegin();
}
void shrink_to_fit()
{
//for (auto& child : children)
// child.shrink_to_fit();
// shrink version 1:
//children.shrink_to_fit();
// shrink version 2:
//children_t new_children;
//new_children.reserve(children.size());
//::std::move(children.begin(), children.end(), ::std::back_inserter(new_children));
//new_children.swap(children);
}
private:
BlocksTree(const This&) = delete;
@ -182,7 +186,6 @@ namespace profiler {
per_thread_stats = that.per_thread_stats;
block_index = that.block_index;
total_children_number = that.total_children_number;
depth = that.depth;
that.node = nullptr;
@ -217,6 +220,7 @@ namespace profiler {
{
tree = ::std::move(that.tree);
thread_name = that.thread_name;
thread_id = that.thread_id;
return *this;
}

View File

@ -33,6 +33,15 @@
#include "blocks_tree_widget.h"
#include "globals.h"
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
//////////////////////////////////////////////////////////////////////////
enum ColumnsIndexes
@ -325,6 +334,7 @@ void ProfTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
m_beginTime = _session_begin_time;
_left += m_beginTime;// - ::std::min(m_beginTime, 1000ULL);
_right += m_beginTime;// + 1000;
setTreeInternal(_blocks, _left, _right, _strict);
setSortingEnabled(true);
@ -441,6 +451,14 @@ size_t ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const :
return total_items;
}
auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size())
{
auto children_number = _tree->children.size();
for (const auto& child : _tree->children)
children_number += calculateTotalChildrenNumber(&child);
return children_number;
}
size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict)
{
if (_blocks.empty())
@ -448,13 +466,11 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
return 0;
}
size_t blocksNumber = 0;
for (const auto& block : _blocks)
{
blocksNumber += block.tree->total_children_number;
}
m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks
//size_t blocksNumber = 0;
//for (const auto& block : _blocks)
// blocksNumber += calculateTotalChildrenNumber(block.tree);
// //blocksNumber += block.tree->total_children_number;
//m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks
typedef ::std::unordered_map<::profiler::thread_id_t, ProfTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> ThreadsMap;
ThreadsMap threadsMap;
@ -522,22 +538,51 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_FRAME, "");
if (block.tree->per_thread_stats)
if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
if (block.tree->per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
const auto& per_thread_stats = block.tree->per_thread_stats;
const auto& per_parent_stats = block.tree->per_parent_stats;
const auto& per_frame_stats = block.tree->per_frame_stats;
if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, block.tree->per_thread_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, block.tree->per_thread_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, block.tree->per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, block.tree->per_thread_stats->total_duration);
item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration);
}
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, block.tree->per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(block.tree->per_thread_stats->calls_number));
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(block.tree->per_thread_stats->total_duration) / static_cast<double>(thread_item->selfDuration()));
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(per_thread_stats->total_duration) / static_cast<double>(thread_item->selfDuration()));
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number));
if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
@ -545,34 +590,6 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
item->setText(COL_PERCENT_SUM_PER_THREAD, "");
}
if (block.tree->per_parent_stats)
{
if (block.tree->per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, block.tree->per_parent_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, block.tree->per_parent_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, block.tree->per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, block.tree->per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, block.tree->per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(block.tree->per_parent_stats->calls_number));
}
if (block.tree->per_frame_stats)
{
if (block.tree->per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, block.tree->per_frame_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, block.tree->per_frame_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, block.tree->per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, block.tree->per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, block.tree->per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(block.tree->per_frame_stats->calls_number));
}
const auto color = block.tree->node->block()->getColor();
const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto fgColor = 0x00ffffff - bgColor;
@ -664,81 +681,91 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
item->setTimeMs(COL_END, endTime - m_beginTime);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
auto percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_parent->duration()));
auto percentage_sum = child.per_parent_stats ? static_cast<int>(0.5 + 100. * static_cast<double>(child.per_parent_stats->total_duration) / static_cast<double>(_parent->duration())) : 0;
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum));
if (_frame != nullptr)
if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
if (_parent != _frame)
const auto& per_thread_stats = child.per_thread_stats;
const auto& per_parent_stats = child.per_parent_stats;
const auto& per_frame_stats = child.per_frame_stats;
auto percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_parent->duration()));
auto percentage_sum = static_cast<int>(0.5 + 100. * static_cast<double>(per_parent_stats->total_duration) / static_cast<double>(_parent->duration()));
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum));
if (_frame != nullptr)
{
percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_frame->duration()));
percentage_sum = child.per_frame_stats ? static_cast<int>(0.5 + 100. * static_cast<double>(child.per_frame_stats->total_duration) / static_cast<double>(_frame->duration())) : 0;
if (_parent != _frame)
{
percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_frame->duration()));
percentage_sum = static_cast<int>(0.5 + 100. * static_cast<double>(per_frame_stats->total_duration) / static_cast<double>(_frame->duration()));
}
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum));
}
else
{
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_FRAME, "");
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_FRAME, "");
}
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum));
}
else
{
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_FRAME, "");
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_FRAME, "");
}
if (child.per_thread_stats)
{
if (child.per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, child.per_thread_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, child.per_thread_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, child.per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, child.per_thread_stats->total_duration);
item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration);
}
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, child.per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(child.per_thread_stats->calls_number));
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
if (_thread)
{
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(child.per_thread_stats->total_duration) / static_cast<double>(_thread->selfDuration()));
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(per_thread_stats->total_duration) / static_cast<double>(_thread->selfDuration()));
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
}
}
if (child.per_parent_stats)
{
if (child.per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, child.per_parent_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, child.per_parent_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, child.per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, child.per_parent_stats->total_duration);
item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, child.per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(child.per_parent_stats->calls_number));
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number));
if (child.per_frame_stats)
{
if (child.per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, child.per_frame_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, child.per_frame_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, child.per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, child.per_frame_stats->total_duration);
item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, child.per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(child.per_frame_stats->calls_number));
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_PARENT, "");
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_PARENT, "");
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_THREAD, "");
}
const auto color = child.node->block()->getColor();
@ -756,7 +783,7 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
children_items_number = setTreeInternal(child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration);
}
percentage = 100;
int percentage = 100;
auto self_duration = duration - children_duration;
if (children_duration > 0 && duration > 0)
{
@ -842,15 +869,16 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
case COL_MAX_PER_PARENT:
case COL_MAX_PER_FRAME:
{
auto block = item->block();
auto i = ::profiler_gui::numeric_max<unsigned int>();
switch (col)
{
case COL_MIN_PER_THREAD: i = item->block()->per_thread_stats->min_duration_block; break;
case COL_MIN_PER_PARENT: i = item->block()->per_parent_stats->min_duration_block; break;
case COL_MIN_PER_FRAME: i = item->block()->per_frame_stats->min_duration_block; break;
case COL_MAX_PER_THREAD: i = item->block()->per_thread_stats->max_duration_block; break;
case COL_MAX_PER_PARENT: i = item->block()->per_parent_stats->max_duration_block; break;
case COL_MAX_PER_FRAME: i = item->block()->per_frame_stats->max_duration_block; break;
case COL_MIN_PER_THREAD: i = block->per_thread_stats->min_duration_block; break;
case COL_MIN_PER_PARENT: i = block->per_parent_stats->min_duration_block; break;
case COL_MIN_PER_FRAME: i = block->per_frame_stats->min_duration_block; break;
case COL_MAX_PER_THREAD: i = block->per_thread_stats->max_duration_block; break;
case COL_MAX_PER_PARENT: i = block->per_parent_stats->max_duration_block; break;
case COL_MAX_PER_FRAME: i = block->per_frame_stats->max_duration_block; break;
}
if (i != ::profiler_gui::numeric_max(i))

View File

@ -34,58 +34,53 @@ extern "C"{
}
}
SerializedBlock::SerializedBlock(Block* block):
m_size(0),
m_data(nullptr)
SerializedBlock::SerializedBlock(const Block* block)
: m_size(sizeof(BaseBlockData))
, m_data(nullptr)
{
m_size += sizeof(BaseBlockData);
uint16_t name_len = (uint16_t)strlen(block->getName()) + 1;
m_size += name_len;
uint16_t name_len = static_cast<uint16_t>(strlen(block->getName()) + 1);
m_size += name_len;
m_data = new char[m_size];
memcpy(&m_data[0], block, sizeof(BaseBlockData));
strncpy(&m_data[sizeof(BaseBlockData)], block->getName(), name_len);
m_data = new char[m_size];
memcpy(m_data, block, sizeof(BaseBlockData));
strncpy(m_data + sizeof(BaseBlockData), block->getName(), name_len);
}
SerializedBlock::SerializedBlock(uint16_t _size, char* _data) :
m_size(_size),
m_data(_data)
SerializedBlock::SerializedBlock(uint16_t _size, char* _data)
: m_size(_size)
, m_data(_data)
{
//m_data = new char[m_size];
//memcpy(&m_data[0], _data, m_size);
}
SerializedBlock::~SerializedBlock()
{
if (m_data){
delete[] m_data;
m_data = nullptr;
}
if (m_data != nullptr)
delete[] m_data;
}
SerializedBlock::SerializedBlock(const SerializedBlock& other)
: m_size(other.m_size)
, m_data(new char[other.m_size])
{
m_size = other.m_size;
m_data = new char[m_size];
memcpy(&m_data[0], other.m_data, m_size);
memcpy(m_data, other.m_data, m_size);
}
SerializedBlock::SerializedBlock(SerializedBlock&& that)
: m_size(that.m_size)
, m_data(that.m_data)
{
m_size = that.m_size;
m_data = that.m_data;
that.m_size = 0;
that.m_data = nullptr;
that.m_size = 0;
that.m_data = nullptr;
}
const BaseBlockData * SerializedBlock::block() const
{
return (const BaseBlockData*)m_data;
return reinterpret_cast<const BaseBlockData*>(m_data);
}
const char* SerializedBlock::getBlockName() const
{
return (const char*)&m_data[sizeof(profiler::BaseBlockData)];
return m_data + sizeof(BaseBlockData);
}
//////////////////////////////////////////////////////////////////////////

View File

@ -162,7 +162,7 @@ typedef ::std::unordered_map<::std::string, ::profiler::BlockStatistics*> StatsM
automatically receive statistics update.
*/
void update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::BlockStatistics*& _stats)
::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current)
{
auto duration = _current.node->block()->duration();
StatsMap::key_type key(_current.node->getBlockName());
@ -171,44 +171,43 @@ void update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _curr
{
// Update already existing statistics
_stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats)
auto stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats)
++_stats->calls_number; // update calls number of this block
_stats->total_duration += duration; // update summary duration of all block calls
++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)
if (duration > stats->max_duration)
{
// update max duration
_stats->max_duration_block = _current.block_index;
_stats->max_duration = duration;
stats->max_duration_block = _current.block_index;
stats->max_duration = duration;
}
//if (duration < _stats->min_duration_block->block()->duration())
if (duration < _stats->min_duration)
if (duration < stats->min_duration)
{
// update min duraton
_stats->min_duration_block = _current.block_index;
_stats->min_duration = duration;
stats->min_duration_block = _current.block_index;
stats->min_duration = duration;
}
// average duration is calculated inside average_duration() method by dividing total_duration to the calls_number
return stats;
}
else
{
// This is first time the block appear in the file.
// Create new statistics.
_stats = new ::profiler::BlockStatistics(duration, _current.block_index);
_stats_map.insert(::std::make_pair(key, _stats));
}
// This is first time the block appear in the file.
// Create new statistics.
auto stats = new ::profiler::BlockStatistics(duration, _current.block_index);
_stats_map.insert(::std::make_pair(key, stats));
return stats;
}
//////////////////////////////////////////////////////////////////////////
void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current)
{
update_statistics(_stats_map, _current, _current.per_frame_stats);
_current.per_frame_stats = update_statistics(_stats_map, _current);
for (auto& child : _current.children)
{
update_statistics_recursive(_stats_map, child);
@ -231,9 +230,7 @@ extern "C"{
return 0;
}
//StatsMap overall_statistics;
PerThreadStats thread_statistics, parent_statistics, frame_statistics;
unsigned int blocks_counter = 0;
while (!inFile.eof()){
@ -249,17 +246,17 @@ extern "C"{
// TODO: use salloc::shared_allocator for allocation/deallocation safety
char* data = new char[sz];
inFile.read((char*)&data[0], sz);
::profiler::BaseBlockData* baseData = (::profiler::BaseBlockData*)data;
auto baseData = reinterpret_cast<::profiler::BaseBlockData*>(data);
::profiler::BlocksTree tree;
tree.node = new ::profiler::SerializedBlock(sz, data);
tree.block_index = blocks_counter++;
auto block_thread_id = baseData->getThreadId();
auto& root = threaded_trees[block_thread_id];
auto& per_parent_statistics = parent_statistics[block_thread_id];
auto& per_thread_statistics = thread_statistics[block_thread_id];
::profiler::BlocksTree tree;
tree.node = new ::profiler::SerializedBlock(sz, data);
tree.block_index = blocks_counter++;
if (::profiler::BLOCK_TYPE_THREAD_SIGN == baseData->getType())
{
root.thread_name = tree.node->getBlockName();
@ -299,10 +296,9 @@ extern "C"{
for (auto& child : tree.children)
{
update_statistics(per_parent_statistics, child, child.per_parent_stats);
child.per_parent_stats = update_statistics(per_parent_statistics, child);
children_duration += child.node->block()->duration();
tree.total_children_number += child.total_children_number;
if (tree.depth < child.depth)
tree.depth = child.depth;
}
@ -312,13 +308,11 @@ extern "C"{
for (const auto& child : tree.children)
{
children_duration += child.node->block()->duration();
tree.total_children_number += child.total_children_number;
if (tree.depth < child.depth)
tree.depth = child.depth;
}
}
tree.total_children_number += static_cast<unsigned int>(tree.children.size());
++tree.depth;
}
}
@ -334,13 +328,13 @@ extern "C"{
{
PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral)
auto& current = root.tree.children.back();
update_statistics(per_thread_statistics, current, current.per_thread_stats);
current.per_thread_stats = update_statistics(per_thread_statistics, current);
}
}
PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple)
if (gather_statistics)
if (gather_statistics)
{
for (auto& it : threaded_trees)
{
@ -351,20 +345,19 @@ extern "C"{
auto& per_frame_statistics = frame_statistics[it.first];
per_parent_statistics.clear();
root.tree.shrink_to_fit();
for (auto& frame : root.tree.children)
{
update_statistics(per_parent_statistics, frame, frame.per_parent_stats);
frame.per_parent_stats = update_statistics(per_parent_statistics, frame);
// TODO: Optimize per frame stats gathering
per_frame_statistics.clear();
update_statistics_recursive(per_frame_statistics, frame);
root.tree.total_children_number += frame.total_children_number;
if (root.tree.depth < frame.depth)
root.tree.depth = frame.depth;
}
root.tree.total_children_number += static_cast<unsigned int>(root.tree.children.size());
++root.tree.depth;
}
}
@ -375,14 +368,13 @@ extern "C"{
auto& root = it.second;
root.thread_id = it.first;
root.tree.shrink_to_fit();
for (auto& frame : root.tree.children)
{
root.tree.total_children_number += frame.total_children_number;
if (root.tree.depth < frame.depth)
root.tree.depth = frame.depth;
}
root.tree.total_children_number += static_cast<unsigned int>(root.tree.children.size());
++root.tree.depth;
}
}