0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 08:41: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:
Victor Zarubkin 2016-12-18 17:59:41 +03:00
parent e5dccfb8be
commit 0a57ff381c
8 changed files with 294 additions and 76 deletions

View File

@ -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)

View File

@ -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())
{

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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))

View File

@ -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.