mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-26 16:11:02 +08:00
(GUI) Please, read NOTICE for that commit.
1) Added active time calculation (this is duration excluding context switch time). 2) Columns "Duration", "Self Dur.", "Self %", "% / Frame", "Active time", "Active %" in Plain mode shows total values per frame (sum of all values per frame).
This commit is contained in:
parent
e5dccfb8be
commit
0a57ff381c
@ -53,19 +53,13 @@ namespace profiler {
|
||||
struct BlockStatistics EASY_FINAL
|
||||
{
|
||||
::profiler::timestamp_t total_duration; ///< Total duration of all block calls
|
||||
::profiler::timestamp_t children_duration; ///< Total duration of all children block calls (which is less or equal to total_duration)
|
||||
//::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
|
||||
::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, ::profiler::timestamp_t _children_duration = 0)
|
||||
explicit BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index, ::profiler::block_index_t _parent_index)
|
||||
: total_duration(_duration)
|
||||
, children_duration(_children_duration)
|
||||
//, min_duration(_duration)
|
||||
//, max_duration(_duration)
|
||||
, min_duration_block(_block_index)
|
||||
, max_duration_block(_block_index)
|
||||
, parent_block(_parent_index)
|
||||
|
@ -199,8 +199,6 @@ typedef ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::BlockStat
|
||||
|
||||
#endif
|
||||
|
||||
typedef ::std::vector<::profiler::timestamp_t> ChildrenDurations;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief Updates statistics for a profiler block.
|
||||
@ -215,7 +213,7 @@ typedef ::std::vector<::profiler::timestamp_t> ChildrenDurations;
|
||||
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, const ChildrenDurations& _children_dutaions)
|
||||
::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)
|
||||
{
|
||||
auto duration = _current.node->duration();
|
||||
//StatsMap::key_type key(_current.node->name());
|
||||
@ -244,8 +242,6 @@ automatically receive statistics update.
|
||||
//stats->min_duration = duration;
|
||||
}
|
||||
|
||||
stats->children_duration += _children_dutaions[_current_index];
|
||||
|
||||
// average duration is calculated inside average_duration() method by dividing total_duration to the calls_number
|
||||
|
||||
return stats;
|
||||
@ -253,7 +249,7 @@ automatically receive statistics update.
|
||||
|
||||
// This is first time the block appear in the file.
|
||||
// Create new statistics.
|
||||
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index, _children_dutaions[_current_index]);
|
||||
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index);
|
||||
//_stats_map.emplace(key, stats);
|
||||
_stats_map.emplace(_current.node->id(), stats);
|
||||
|
||||
@ -303,11 +299,11 @@ 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, const ChildrenDurations& _children_dutaions)
|
||||
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, _children_dutaions);
|
||||
_current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks);
|
||||
for (auto i : _current.children)
|
||||
update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks, _children_dutaions);
|
||||
update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -513,7 +509,6 @@ extern "C" {
|
||||
PerThreadStats parent_statistics, frame_statistics;
|
||||
IdMap identification_table;
|
||||
|
||||
ChildrenDurations durations(total_blocks_number, 0ULL);
|
||||
blocks.reserve(total_blocks_number);
|
||||
//olddata = append_regime ? serialized_blocks.data() : nullptr;
|
||||
serialized_blocks.set(memory_size);
|
||||
@ -715,8 +710,7 @@ extern "C" {
|
||||
for (auto i : tree.children)
|
||||
{
|
||||
auto& child = blocks[i];
|
||||
child.per_parent_stats = update_statistics(per_parent_statistics, child, i, block_index, blocks, durations);
|
||||
children_duration += child.node->duration();
|
||||
child.per_parent_stats = update_statistics(per_parent_statistics, child, i, block_index, blocks);
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
}
|
||||
@ -726,13 +720,11 @@ extern "C" {
|
||||
for (auto i : tree.children)
|
||||
{
|
||||
const auto& child = blocks[i];
|
||||
children_duration += child.node->duration();
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
}
|
||||
}
|
||||
|
||||
durations[block_index] = children_duration;
|
||||
++tree.depth;
|
||||
}
|
||||
}
|
||||
@ -746,7 +738,7 @@ extern "C" {
|
||||
if (gather_statistics)
|
||||
{
|
||||
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id, blocks, durations);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id, blocks);
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,7 +773,7 @@ extern "C" {
|
||||
auto& per_parent_statistics = parent_statistics[it.first];
|
||||
per_parent_statistics.clear();
|
||||
|
||||
statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks, &durations](::profiler::BlocksTreeRoot& root)
|
||||
statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks](::profiler::BlocksTreeRoot& root)
|
||||
{
|
||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
||||
//{
|
||||
@ -792,10 +784,10 @@ extern "C" {
|
||||
for (auto i : root.children)
|
||||
{
|
||||
auto& frame = blocks[i];
|
||||
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i, root.thread_id, blocks, durations);
|
||||
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i, root.thread_id, blocks);
|
||||
|
||||
per_frame_statistics.clear();
|
||||
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks, durations);
|
||||
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks);
|
||||
|
||||
if (cs_index < root.sync.size())
|
||||
{
|
||||
|
@ -1440,6 +1440,47 @@ void EasyGraphicsView::onIdleTimeout()
|
||||
lay->addWidget(new QLabel(::profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, itemBlock.per_thread_stats->average_duration(), 3), widget), row, 1, 1, 3, Qt::AlignLeft);
|
||||
++row;
|
||||
|
||||
// Calculate idle/active time
|
||||
{
|
||||
auto threadRoot = item->root();
|
||||
|
||||
::profiler::block_index_t ind = 0;
|
||||
auto it = ::std::lower_bound(threadRoot->sync.begin(), threadRoot->sync.end(), itemBlock.node->begin(), [](::profiler::block_index_t _cs_index, ::profiler::timestamp_t _val)
|
||||
{
|
||||
return EASY_GLOBALS.gui_blocks[_cs_index].tree.node->begin() < _val;
|
||||
});
|
||||
|
||||
if (it != threadRoot->sync.end())
|
||||
{
|
||||
ind = it - threadRoot->sync.begin();
|
||||
if (ind > 0)
|
||||
--ind;
|
||||
}
|
||||
else
|
||||
{
|
||||
ind = static_cast<::profiler::block_index_t>(threadRoot->sync.size());
|
||||
}
|
||||
|
||||
::profiler::timestamp_t idleTime = 0;
|
||||
for (::profiler::block_index_t ncs = static_cast<::profiler::block_index_t>(threadRoot->sync.size()); ind < ncs; ++ind)
|
||||
{
|
||||
auto cs_index = threadRoot->sync[ind];
|
||||
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
|
||||
|
||||
if (cs->begin() > itemBlock.node->end())
|
||||
break;
|
||||
|
||||
if (itemBlock.node->begin() <= cs->begin() && cs->end() <= itemBlock.node->end())
|
||||
idleTime += cs->duration();
|
||||
}
|
||||
|
||||
auto active_time = duration - idleTime;
|
||||
auto active_percent = duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, duration);
|
||||
lay->addWidget(new QLabel("Active time:", widget), row, 0, Qt::AlignRight);
|
||||
lay->addWidget(new QLabel(QString("%1 (%2%)").arg(::profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, active_time, 3)).arg(QString::number(active_percent, 'g', 3)), widget), row, 1, 1, 3, Qt::AlignLeft);
|
||||
++row;
|
||||
}
|
||||
|
||||
lay->addWidget(new EasyBoldLabel("-------- Statistics --------", widget), row, 0, 1, 5, Qt::AlignHCenter);
|
||||
lay->addWidget(new QLabel("per ", widget), row + 1, 0, Qt::AlignRight);
|
||||
lay->addWidget(new QLabel("This %:", widget), row + 2, 0, Qt::AlignRight);
|
||||
|
@ -92,13 +92,13 @@ const bool SIMPLIFIED_REGIME_COLUMNS[COL_COLUMNS_NUMBER] = {
|
||||
true, //COL_DURATION,
|
||||
true, //COL_SELF_DURATION,
|
||||
false, //COL_DURATION_SUM_PER_PARENT,
|
||||
true, //COL_DURATION_SUM_PER_FRAME,
|
||||
false, //COL_DURATION_SUM_PER_FRAME,
|
||||
true, //COL_DURATION_SUM_PER_THREAD,
|
||||
true, //COL_SELF_DURATION_PERCENT,
|
||||
false, //COL_PERCENT_PER_PARENT,
|
||||
false, //COL_PERCENT_PER_FRAME,
|
||||
true, //COL_PERCENT_PER_FRAME,
|
||||
false, //COL_PERCENT_SUM_PER_PARENT,
|
||||
true, //COL_PERCENT_SUM_PER_FRAME,
|
||||
false, //COL_PERCENT_SUM_PER_FRAME,
|
||||
true, //COL_PERCENT_SUM_PER_THREAD,
|
||||
true, //COL_END,
|
||||
true, //COL_MIN_PER_FRAME,
|
||||
@ -112,7 +112,9 @@ const bool SIMPLIFIED_REGIME_COLUMNS[COL_COLUMNS_NUMBER] = {
|
||||
false, //COL_MIN_PER_PARENT,
|
||||
false, //COL_MAX_PER_PARENT,
|
||||
false, //COL_AVERAGE_PER_PARENT,
|
||||
false //COL_NCALLS_PER_PARENT,
|
||||
false, //COL_NCALLS_PER_PARENT,
|
||||
true, //COL_ACTIVE_TIME,
|
||||
true //COL_ACTIVE_PERCENT,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -176,6 +178,9 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
|
||||
header_item->setText(COL_AVERAGE_PER_THREAD, "Average dur./Thread");
|
||||
header_item->setText(COL_NCALLS_PER_THREAD, "N Calls/Thread");
|
||||
|
||||
header_item->setText(COL_ACTIVE_TIME, "Active time");
|
||||
header_item->setText(COL_ACTIVE_PERCENT, "Active %");
|
||||
|
||||
auto color = QColor::fromRgb(::profiler::colors::DeepOrange900);
|
||||
header_item->setForeground(COL_MIN_PER_THREAD, color);
|
||||
header_item->setForeground(COL_MAX_PER_THREAD, color);
|
||||
@ -280,7 +285,7 @@ void EasyTreeWidget::onFillTimerTimeout()
|
||||
|
||||
sortByColumn(COL_BEGIN, Qt::AscendingOrder); // sort by begin time
|
||||
if (m_mode == EasyTreeMode_Plain) // and after that, sort by frame %
|
||||
sortByColumn(COL_PERCENT_SUM_PER_FRAME, Qt::DescendingOrder);
|
||||
sortByColumn(COL_PERCENT_PER_FRAME, Qt::DescendingOrder);
|
||||
|
||||
//resizeColumnToContents(COL_NAME);
|
||||
resizeColumnsToContents();
|
||||
@ -1079,7 +1084,7 @@ void EasyTreeWidget::loadSettings()
|
||||
if (!val.isNull())
|
||||
{
|
||||
auto byteArray = val.toByteArray();
|
||||
memcpy(m_columnsHiddenStatus, byteArray.constData(), sizeof(m_columnsHiddenStatus));
|
||||
memcpy(m_columnsHiddenStatus, byteArray.constData(), ::std::min(sizeof(m_columnsHiddenStatus), (size_t)byteArray.size()));
|
||||
}
|
||||
|
||||
auto state = settings.value("headerState").toByteArray();
|
||||
|
@ -92,6 +92,11 @@ bool EasyTreeWidgetItem::operator < (const Parent& _other) const
|
||||
return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt();
|
||||
}
|
||||
|
||||
case COL_ACTIVE_PERCENT:
|
||||
{
|
||||
return data(col, Qt::UserRole).toDouble() < _other.data(col, Qt::UserRole).toDouble();
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// durations min, max, average
|
||||
|
@ -92,6 +92,9 @@ enum EasyColumnsIndexes
|
||||
COL_AVERAGE_PER_PARENT,
|
||||
COL_NCALLS_PER_PARENT,
|
||||
|
||||
COL_ACTIVE_TIME,
|
||||
COL_ACTIVE_PERCENT,
|
||||
|
||||
COL_COLUMNS_NUMBER
|
||||
};
|
||||
|
||||
@ -111,7 +114,7 @@ public:
|
||||
using Parent::setBackgroundColor;
|
||||
using Parent::setTextColor;
|
||||
|
||||
EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock = ::profiler_gui::numeric_max<decltype(m_block)>(), Parent* _parent = nullptr);
|
||||
explicit EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock = ::profiler_gui::numeric_max<decltype(m_block)>(), Parent* _parent = nullptr);
|
||||
virtual ~EasyTreeWidgetItem();
|
||||
|
||||
bool operator < (const Parent& _other) const override;
|
||||
|
@ -217,7 +217,7 @@ void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime,
|
||||
item->setTimeSmart(COL_SELF_DURATION, _units, root.profiled_time);
|
||||
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
const auto children_items_number = setTreeInternal(_beginTime, root.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
const auto children_items_number = setTreeInternal(root, 0, _beginTime, root.children, item, nullptr, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
|
||||
if (children_items_number > 0)
|
||||
{
|
||||
@ -249,6 +249,8 @@ void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime,
|
||||
// return children_number;
|
||||
// }
|
||||
|
||||
typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::block_index_t, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> BeginEndIndicesMap;
|
||||
|
||||
void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units)
|
||||
{
|
||||
//size_t blocksNumber = 0;
|
||||
@ -257,6 +259,7 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
|
||||
// //blocksNumber += block.tree->total_children_number;
|
||||
//m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks
|
||||
|
||||
BeginEndIndicesMap beginEndMap;
|
||||
RootsMap threadsMap;
|
||||
|
||||
auto const setTree = (m_mode == EasyTreeMode_Full) ? &EasyTreeWidgetLoader::setTreeInternal : &EasyTreeWidgetLoader::setTreeInternalPlain;
|
||||
@ -280,6 +283,7 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
|
||||
|
||||
::profiler::timestamp_t duration = 0;
|
||||
EasyTreeWidgetItem* thread_item = nullptr;
|
||||
::profiler::block_index_t& firstCswitch = beginEndMap[block.root->thread_id];
|
||||
auto thread_item_it = threadsMap.find(block.root->thread_id);
|
||||
if (thread_item_it != threadsMap.end())
|
||||
{
|
||||
@ -301,6 +305,49 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
|
||||
thread_item->setTimeSmart(COL_SELF_DURATION, _units, block.root->profiled_time);
|
||||
|
||||
threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item));
|
||||
|
||||
firstCswitch = 0;
|
||||
auto it = ::std::lower_bound(block.root->sync.begin(), block.root->sync.end(), _left, [](::profiler::block_index_t ind, decltype(_left) _val)
|
||||
{
|
||||
return EASY_GLOBALS.gui_blocks[ind].tree.node->begin() < _val;
|
||||
});
|
||||
|
||||
if (it != block.root->sync.end())
|
||||
{
|
||||
firstCswitch = it - block.root->sync.begin();
|
||||
if (firstCswitch > 0)
|
||||
--firstCswitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
firstCswitch = static_cast<::profiler::block_index_t>(block.root->sync.size());
|
||||
}
|
||||
}
|
||||
|
||||
bool hasContextSwitch = false;
|
||||
::profiler::timestamp_t idleTime = 0;
|
||||
for (::profiler::block_index_t ind = firstCswitch, ncs = static_cast<::profiler::block_index_t>(block.root->sync.size()); ind < ncs; ++ind)
|
||||
{
|
||||
auto cs_index = block.root->sync[ind];
|
||||
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
|
||||
|
||||
if (cs->begin() > endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
firstCswitch = ind;
|
||||
break;
|
||||
}
|
||||
|
||||
if (startTime <= cs->begin() && cs->end() <= endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
{
|
||||
firstCswitch = ind;
|
||||
hasContextSwitch = true;
|
||||
}
|
||||
|
||||
idleTime += cs->duration();
|
||||
}
|
||||
}
|
||||
|
||||
auto item = new EasyTreeWidgetItem(block.tree, thread_item);
|
||||
@ -309,6 +356,13 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
|
||||
auto name = *gui_block.tree.node->name() != 0 ? gui_block.tree.node->name() : easyDescriptor(gui_block.tree.node->id()).name();
|
||||
item->setText(COL_NAME, ::profiler_gui::toUnicode(name));
|
||||
item->setTimeSmart(COL_DURATION, _units, duration);
|
||||
|
||||
auto active_time = duration - idleTime;
|
||||
auto active_percent = duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, duration);
|
||||
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
|
||||
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
|
||||
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
|
||||
|
||||
item->setTimeMs(COL_BEGIN, startTime - _beginTime);
|
||||
item->setTimeMs(COL_END, endTime - _beginTime);
|
||||
|
||||
@ -386,7 +440,7 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
|
||||
if (!gui_block.tree.children.empty())
|
||||
{
|
||||
m_iditems.clear();
|
||||
children_items_number = (this->*setTree)(_beginTime, gui_block.tree.children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
children_items_number = (this->*setTree)(*block.root, firstCswitch, _beginTime, gui_block.tree.children, item, item, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
if (interrupted())
|
||||
break;
|
||||
}
|
||||
@ -460,7 +514,7 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
|
||||
size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
|
||||
{
|
||||
auto const setTree = m_mode == EasyTreeMode_Full ? &EasyTreeWidgetLoader::setTreeInternal : &EasyTreeWidgetLoader::setTreeInternalPlain;
|
||||
|
||||
@ -484,11 +538,44 @@ size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beg
|
||||
if (startTime > _right || endTime < _left)
|
||||
continue;
|
||||
|
||||
bool hasContextSwitch = false;
|
||||
::profiler::timestamp_t idleTime = 0;
|
||||
for (::profiler::block_index_t ind = _firstCswitch, ncs = static_cast<::profiler::block_index_t>(_threadRoot.sync.size()); ind < ncs; ++ind)
|
||||
{
|
||||
auto cs_index = _threadRoot.sync[ind];
|
||||
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
|
||||
|
||||
if (cs->begin() > endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
_firstCswitch = ind;
|
||||
break;
|
||||
}
|
||||
|
||||
if (startTime <= cs->begin() && cs->end() <= endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
{
|
||||
_firstCswitch = ind;
|
||||
hasContextSwitch = true;
|
||||
}
|
||||
|
||||
idleTime += cs->duration();
|
||||
}
|
||||
}
|
||||
|
||||
auto item = new EasyTreeWidgetItem(child_index, _parent);
|
||||
|
||||
auto name = *child.node->name() != 0 ? child.node->name() : easyDescriptor(child.node->id()).name();
|
||||
item->setText(COL_NAME, ::profiler_gui::toUnicode(name));
|
||||
item->setTimeSmart(COL_DURATION, _units, duration);
|
||||
|
||||
auto active_time = duration - idleTime;
|
||||
auto active_percent = duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, duration);
|
||||
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
|
||||
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
|
||||
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
|
||||
|
||||
item->setTimeMs(COL_BEGIN, startTime - _beginTime);
|
||||
item->setTimeMs(COL_END, endTime - _beginTime);
|
||||
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
|
||||
@ -526,16 +613,9 @@ size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beg
|
||||
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
|
||||
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0);
|
||||
|
||||
if (_thread)
|
||||
{
|
||||
auto percentage_per_thread = ::profiler_gui::percent(duration, _thread->selfDuration());
|
||||
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage_per_thread);
|
||||
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage_per_thread));
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0);
|
||||
}
|
||||
auto percentage_per_thread = ::profiler_gui::percent(duration, _threadRoot.profiled_time);
|
||||
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage_per_thread);
|
||||
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage_per_thread));
|
||||
}
|
||||
|
||||
|
||||
@ -550,12 +630,9 @@ size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beg
|
||||
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 = ::profiler_gui::percent(per_thread_stats->total_duration, _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));
|
||||
}
|
||||
auto percentage_per_thread = ::profiler_gui::percent(per_thread_stats->total_duration, _threadRoot.profiled_time);
|
||||
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 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
@ -583,9 +660,9 @@ size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beg
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_frame == nullptr && _thread != nullptr)
|
||||
if (_frame == nullptr)
|
||||
{
|
||||
auto percentage_per_thread = ::profiler_gui::percent(duration, _thread->selfDuration());
|
||||
auto percentage_per_thread = ::profiler_gui::percent(duration, _threadRoot.profiled_time);
|
||||
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage_per_thread);
|
||||
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage_per_thread));
|
||||
}
|
||||
@ -614,7 +691,7 @@ size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beg
|
||||
if (!child.children.empty())
|
||||
{
|
||||
m_iditems.clear();
|
||||
children_items_number = (this->*setTree)(_beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
children_items_number = (this->*setTree)(_threadRoot, _firstCswitch, _beginTime, child.children, item, _frame ? _frame : item, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
if (interrupted())
|
||||
break;
|
||||
}
|
||||
@ -661,7 +738,25 @@ size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::timestamp_t& _beg
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem*, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
|
||||
::profiler::timestamp_t EasyTreeWidgetLoader::calculateChildrenDurationRecursive(const ::profiler::BlocksTree::children_t& _children, ::profiler::block_id_t _id)
|
||||
{
|
||||
::profiler::timestamp_t total_duration = 0;
|
||||
|
||||
for (auto child_index : _children)
|
||||
{
|
||||
if (interrupted())
|
||||
break;
|
||||
|
||||
const auto& gui_block = easyBlock(child_index);
|
||||
total_duration += gui_block.tree.node->duration();
|
||||
if (gui_block.tree.node->id() == _id)
|
||||
total_duration += calculateChildrenDurationRecursive(gui_block.tree.children, _id);
|
||||
}
|
||||
|
||||
return total_duration;
|
||||
}
|
||||
|
||||
size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem*, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
|
||||
{
|
||||
size_t total_items = 0;
|
||||
for (auto child_index : _children)
|
||||
@ -669,7 +764,7 @@ size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::timestamp_t&
|
||||
if (interrupted())
|
||||
break;
|
||||
|
||||
auto& gui_block = easyBlock(child_index);
|
||||
const auto& gui_block = easyBlock(child_index);
|
||||
const auto& child = gui_block.tree;
|
||||
const auto startTime = child.node->begin();
|
||||
const auto endTime = child.node->end();
|
||||
@ -677,13 +772,89 @@ size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::timestamp_t&
|
||||
|
||||
_duration += duration;
|
||||
|
||||
auto it = m_iditems.find(child.node->id());
|
||||
if (it != m_iditems.end())
|
||||
{
|
||||
++total_items;
|
||||
|
||||
if (it->second != nullptr && child.per_frame_stats != nullptr)
|
||||
{
|
||||
auto item = it->second;
|
||||
|
||||
auto children_duration = calculateChildrenDurationRecursive(child.children, it->first);
|
||||
auto self_duration = item->data(COL_SELF_DURATION, Qt::UserRole).toULongLong() - children_duration;
|
||||
|
||||
int percentage = 100;
|
||||
if (child.per_frame_stats->total_duration > 0)
|
||||
percentage = ::profiler_gui::percent(self_duration, child.per_frame_stats->total_duration);
|
||||
|
||||
item->setTimeSmart(COL_SELF_DURATION, _units, self_duration);
|
||||
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
|
||||
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
|
||||
|
||||
bool hasContextSwitch = false;
|
||||
::profiler::timestamp_t idleTime = 0;
|
||||
for (::profiler::block_index_t ind = _firstCswitch, ncs = static_cast<::profiler::block_index_t>(_threadRoot.sync.size()); ind < ncs; ++ind)
|
||||
{
|
||||
auto cs_index = _threadRoot.sync[ind];
|
||||
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
|
||||
|
||||
if (cs->begin() > endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
_firstCswitch = ind;
|
||||
break;
|
||||
}
|
||||
|
||||
if (startTime <= cs->begin() && cs->end() <= endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
{
|
||||
_firstCswitch = ind;
|
||||
hasContextSwitch = true;
|
||||
}
|
||||
|
||||
idleTime += cs->duration();
|
||||
}
|
||||
}
|
||||
|
||||
auto active_time = item->data(COL_ACTIVE_TIME, Qt::UserRole).toULongLong() - idleTime;
|
||||
auto active_percent = child.per_frame_stats->total_duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, child.per_frame_stats->total_duration);
|
||||
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
|
||||
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
|
||||
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startTime > _right || endTime < _left)
|
||||
continue;
|
||||
|
||||
if (m_iditems.find(gui_block.tree.node->id()) != m_iditems.end())
|
||||
bool hasContextSwitch = false;
|
||||
::profiler::timestamp_t idleTime = 0;
|
||||
for (::profiler::block_index_t ind = _firstCswitch, ncs = static_cast<::profiler::block_index_t>(_threadRoot.sync.size()); ind < ncs; ++ind)
|
||||
{
|
||||
++total_items;
|
||||
continue;
|
||||
auto cs_index = _threadRoot.sync[ind];
|
||||
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
|
||||
|
||||
if (cs->begin() > endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
_firstCswitch = ind;
|
||||
break;
|
||||
}
|
||||
|
||||
if (startTime <= cs->begin() && cs->end() <= endTime)
|
||||
{
|
||||
if (!hasContextSwitch)
|
||||
{
|
||||
_firstCswitch = ind;
|
||||
hasContextSwitch = true;
|
||||
}
|
||||
|
||||
idleTime += cs->duration();
|
||||
}
|
||||
}
|
||||
|
||||
auto item = new EasyTreeWidgetItem(child_index, _frame);
|
||||
@ -705,17 +876,14 @@ size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::timestamp_t&
|
||||
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 != nullptr)
|
||||
{
|
||||
auto percentage_per_thread = ::profiler_gui::percent(per_thread_stats->total_duration, _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));
|
||||
}
|
||||
auto percentage_per_thread = ::profiler_gui::percent(per_thread_stats->total_duration, _threadRoot.profiled_time);
|
||||
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
|
||||
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
|
||||
|
||||
const ::profiler::BlockStatistics* per_frame_stats = child.per_frame_stats;
|
||||
const auto percentage_sum = ::profiler_gui::percent(per_frame_stats->total_duration, _frame->duration());
|
||||
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum);
|
||||
item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum));
|
||||
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage_sum);
|
||||
item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage_sum));
|
||||
|
||||
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
@ -724,14 +892,14 @@ size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::timestamp_t&
|
||||
item->setTimeSmart(COL_AVERAGE_PER_FRAME, _units, per_frame_stats->average_duration());
|
||||
}
|
||||
|
||||
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, _units, per_frame_stats->total_duration);
|
||||
item->setTimeSmart(COL_DURATION, _units, 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
|
||||
{
|
||||
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
|
||||
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0);
|
||||
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
|
||||
}
|
||||
|
||||
const auto color = easyDescriptor(child.node->id()).color();
|
||||
@ -743,27 +911,35 @@ size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::timestamp_t&
|
||||
auto item_index = static_cast<uint32_t>(m_items.size());
|
||||
m_items.push_back(item);
|
||||
#endif
|
||||
m_iditems.insert(gui_block.tree.node->id());
|
||||
m_iditems[child.node->id()] = nullptr;
|
||||
|
||||
size_t children_items_number = 0;
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
if (!child.children.empty())
|
||||
{
|
||||
children_items_number = setTreeInternalPlain(_beginTime, child.children, _frame, _frame, _thread, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
children_items_number = setTreeInternalPlain(_threadRoot, _firstCswitch, _beginTime, child.children, _frame, _frame, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
if (interrupted())
|
||||
break;
|
||||
}
|
||||
|
||||
m_iditems[child.node->id()] = item;
|
||||
|
||||
if (child.per_frame_stats != nullptr)
|
||||
{
|
||||
int percentage = 100;
|
||||
auto self_duration = child.per_frame_stats->total_duration - child.per_frame_stats->children_duration;
|
||||
auto self_duration = child.per_frame_stats->total_duration - children_duration;
|
||||
if (child.per_frame_stats->total_duration > 0)
|
||||
percentage = ::profiler_gui::percent(self_duration, child.per_frame_stats->total_duration);
|
||||
|
||||
item->setTimeSmart(COL_SELF_DURATION, _units, self_duration);
|
||||
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
|
||||
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
|
||||
|
||||
auto active_time = child.per_frame_stats->total_duration - idleTime;
|
||||
auto active_percent = child.per_frame_stats->total_duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, child.per_frame_stats->total_duration);
|
||||
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
|
||||
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
|
||||
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
|
||||
}
|
||||
|
||||
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
|
||||
|
@ -49,7 +49,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
//#include <unordered_set>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include "easy/reader.h"
|
||||
@ -67,7 +67,7 @@ typedef ::std::vector<EasyTreeWidgetItem*> Items;
|
||||
|
||||
typedef ::std::vector<::std::pair<::profiler::thread_id_t, EasyTreeWidgetItem*> > ThreadedItems;
|
||||
typedef ::std::unordered_map<::profiler::thread_id_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap;
|
||||
typedef ::std::unordered_set<::profiler::block_id_t, ::profiler_gui::do_no_hash<::profiler::block_index_t>::hasher_t> IdItems;
|
||||
typedef ::std::unordered_map<::profiler::block_id_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::block_index_t>::hasher_t> IdItems;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -113,8 +113,10 @@ private:
|
||||
|
||||
void setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units);
|
||||
void setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units);
|
||||
size_t setTreeInternal(const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
|
||||
size_t setTreeInternalPlain(const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
|
||||
size_t setTreeInternal(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
|
||||
size_t setTreeInternalPlain(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
|
||||
|
||||
::profiler::timestamp_t calculateChildrenDurationRecursive(const ::profiler::BlocksTree::children_t& _children, ::profiler::block_id_t _id);
|
||||
|
||||
}; // END of class EasyTreeWidgetLoader.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user