mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
Memory consumtion optimization (almost 2 times less memory used on Windows)
This commit is contained in:
parent
3fd0b77d16
commit
d38c869330
@ -346,10 +346,12 @@ namespace profiler
|
||||
|
||||
class PROFILER_API SerializedBlock final
|
||||
{
|
||||
uint16_t m_size;
|
||||
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);
|
||||
|
@ -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,7 +83,7 @@ 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.)
|
||||
@ -100,8 +91,7 @@ namespace profiler {
|
||||
::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;
|
||||
}
|
||||
|
||||
|
@ -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,8 +681,14 @@ 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);
|
||||
|
||||
if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
|
||||
{
|
||||
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 = 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;
|
||||
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);
|
||||
@ -676,7 +699,7 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
|
||||
if (_parent != _frame)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
@ -692,53 +715,57 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
|
||||
item->setText(COL_PERCENT_SUM_PER_FRAME, "");
|
||||
}
|
||||
|
||||
if (child.per_thread_stats)
|
||||
|
||||
if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
if (child.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 (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);
|
||||
}
|
||||
|
||||
if (child.per_parent_stats)
|
||||
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)
|
||||
{
|
||||
if (child.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_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_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_FRAME, Qt::UserRole, per_frame_stats->calls_number);
|
||||
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
|
||||
}
|
||||
|
||||
if (child.per_frame_stats)
|
||||
else
|
||||
{
|
||||
if (child.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->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_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))
|
||||
|
@ -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;
|
||||
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);
|
||||
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){
|
||||
if (m_data != nullptr)
|
||||
delete[] m_data;
|
||||
m_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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));
|
||||
}
|
||||
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,7 +328,7 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user