mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
(GUI) Added hierarchy window mode: full hierarchy, plain mode (only functions list)
This commit is contained in:
parent
1ac9c5c2a0
commit
e5dccfb8be
@ -52,18 +52,20 @@ namespace profiler {
|
||||
#pragma pack(push, 1)
|
||||
struct BlockStatistics EASY_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
|
||||
::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)
|
||||
explicit BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index, ::profiler::block_index_t _parent_index, ::profiler::timestamp_t _children_duration = 0)
|
||||
: total_duration(_duration)
|
||||
, min_duration(_duration)
|
||||
, max_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,6 +199,8 @@ typedef ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::BlockStat
|
||||
|
||||
#endif
|
||||
|
||||
typedef ::std::vector<::profiler::timestamp_t> ChildrenDurations;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief Updates statistics for a profiler block.
|
||||
@ -213,7 +215,7 @@ typedef ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::BlockStat
|
||||
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)
|
||||
::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)
|
||||
{
|
||||
auto duration = _current.node->duration();
|
||||
//StatsMap::key_type key(_current.node->name());
|
||||
@ -228,20 +230,22 @@ automatically receive statistics update.
|
||||
++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)
|
||||
if (duration > _blocks[stats->max_duration_block].node->duration())
|
||||
{
|
||||
// update max duration
|
||||
stats->max_duration_block = _current_index;
|
||||
stats->max_duration = duration;
|
||||
//stats->max_duration = duration;
|
||||
}
|
||||
|
||||
if (duration < stats->min_duration)
|
||||
if (duration < _blocks[stats->min_duration_block].node->duration())
|
||||
{
|
||||
// update min duraton
|
||||
stats->min_duration_block = _current_index;
|
||||
stats->min_duration = duration;
|
||||
//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;
|
||||
@ -249,14 +253,14 @@ 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);
|
||||
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index, _children_dutaions[_current_index]);
|
||||
//_stats_map.emplace(key, stats);
|
||||
_stats_map.emplace(_current.node->id(), stats);
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index)
|
||||
::profiler::BlockStatistics* update_statistics(CsStatsMap& _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();
|
||||
CsStatsMap::key_type key(_current.node->name());
|
||||
@ -270,18 +274,18 @@ automatically receive statistics update.
|
||||
++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)
|
||||
if (duration > _blocks[stats->max_duration_block].node->duration())
|
||||
{
|
||||
// update max duration
|
||||
stats->max_duration_block = _current_index;
|
||||
stats->max_duration = duration;
|
||||
//stats->max_duration = duration;
|
||||
}
|
||||
|
||||
if (duration < stats->min_duration)
|
||||
if (duration < _blocks[stats->min_duration_block].node->duration())
|
||||
{
|
||||
// update min duraton
|
||||
stats->min_duration_block = _current_index;
|
||||
stats->min_duration = duration;
|
||||
//stats->min_duration = duration;
|
||||
}
|
||||
|
||||
// average duration is calculated inside average_duration() method by dividing total_duration to the calls_number
|
||||
@ -299,11 +303,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)
|
||||
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)
|
||||
{
|
||||
_current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index);
|
||||
_current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks, _children_dutaions);
|
||||
for (auto i : _current.children)
|
||||
update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks);
|
||||
update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks, _children_dutaions);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -509,6 +513,7 @@ 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);
|
||||
@ -584,7 +589,7 @@ extern "C" {
|
||||
if (gather_statistics)
|
||||
{
|
||||
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics_cs, tree, block_index, thread_id);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics_cs, tree, block_index, thread_id, blocks);
|
||||
}
|
||||
}
|
||||
|
||||
@ -710,8 +715,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);
|
||||
|
||||
child.per_parent_stats = update_statistics(per_parent_statistics, child, i, block_index, blocks, durations);
|
||||
children_duration += child.node->duration();
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
@ -728,6 +732,7 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
durations[block_index] = children_duration;
|
||||
++tree.depth;
|
||||
}
|
||||
}
|
||||
@ -741,7 +746,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);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id, blocks, durations);
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,7 +781,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](::profiler::BlocksTreeRoot& root)
|
||||
statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks, &durations](::profiler::BlocksTreeRoot& root)
|
||||
{
|
||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
||||
//{
|
||||
@ -787,10 +792,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);
|
||||
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i, root.thread_id, blocks, durations);
|
||||
|
||||
per_frame_statistics.clear();
|
||||
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks);
|
||||
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks, durations);
|
||||
|
||||
if (cs_index < root.sync.size())
|
||||
{
|
||||
@ -803,7 +808,7 @@ extern "C" {
|
||||
continue;
|
||||
if (cs.node->begin() > frame.node->end())
|
||||
break;
|
||||
cs.per_frame_stats = update_statistics(frame_stats_cs, cs, cs_index, i);
|
||||
cs.per_frame_stats = update_statistics(frame_stats_cs, cs, cs_index, i, blocks);
|
||||
|
||||
} while (++cs_index < root.sync.size());
|
||||
}
|
||||
|
@ -1288,6 +1288,12 @@ void EasyGraphicsView::initMode()
|
||||
|
||||
repaintScene();
|
||||
});
|
||||
|
||||
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::blocksTreeModeChanged, [this]()
|
||||
{
|
||||
if (!m_selectedBlocks.empty())
|
||||
emit intervalChanged(m_selectedBlocks, m_beginTime, position2time(m_chronometerItem->left()), position2time(m_chronometerItem->right()), m_chronometerItem->reverse());
|
||||
});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -65,9 +65,9 @@
|
||||
#include <QToolBar>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include "blocks_tree_widget.h"
|
||||
#include "tree_widget_item.h"
|
||||
#include "globals.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -86,6 +86,35 @@
|
||||
|
||||
const int HIERARCHY_BUILDER_TIMER_INTERVAL = 40;
|
||||
|
||||
const bool SIMPLIFIED_REGIME_COLUMNS[COL_COLUMNS_NUMBER] = {
|
||||
true, //COL_NAME,
|
||||
true, //COL_BEGIN,
|
||||
true, //COL_DURATION,
|
||||
true, //COL_SELF_DURATION,
|
||||
false, //COL_DURATION_SUM_PER_PARENT,
|
||||
true, //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,
|
||||
false, //COL_PERCENT_SUM_PER_PARENT,
|
||||
true, //COL_PERCENT_SUM_PER_FRAME,
|
||||
true, //COL_PERCENT_SUM_PER_THREAD,
|
||||
true, //COL_END,
|
||||
true, //COL_MIN_PER_FRAME,
|
||||
true, //COL_MAX_PER_FRAME,
|
||||
true, //COL_AVERAGE_PER_FRAME,
|
||||
true, //COL_NCALLS_PER_FRAME,
|
||||
true, //COL_MIN_PER_THREAD,
|
||||
true, //COL_MAX_PER_THREAD,
|
||||
true, //COL_AVERAGE_PER_THREAD,
|
||||
true, //COL_NCALLS_PER_THREAD,
|
||||
false, //COL_MIN_PER_PARENT,
|
||||
false, //COL_MAX_PER_PARENT,
|
||||
false, //COL_AVERAGE_PER_PARENT,
|
||||
false //COL_NCALLS_PER_PARENT,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
|
||||
@ -93,10 +122,13 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
|
||||
, m_beginTime(::std::numeric_limits<decltype(m_beginTime)>::max())
|
||||
, m_lastFound(nullptr)
|
||||
, m_progress(nullptr)
|
||||
, m_mode(EasyTreeMode_Plain)
|
||||
, m_bColorRows(true)
|
||||
, m_bLocked(false)
|
||||
, m_bSilentExpandCollapse(false)
|
||||
{
|
||||
memset(m_columnsHiddenStatus, 0, sizeof(m_columnsHiddenStatus));
|
||||
|
||||
setAutoFillBackground(false);
|
||||
setAlternatingRowColors(true);
|
||||
setItemsExpandable(true);
|
||||
@ -178,6 +210,27 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
|
||||
|
||||
loadSettings();
|
||||
|
||||
if (m_mode == EasyTreeMode_Full)
|
||||
{
|
||||
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
|
||||
m_columnsHiddenStatus[i] = isColumnHidden(i) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
|
||||
{
|
||||
if (SIMPLIFIED_REGIME_COLUMNS[i])
|
||||
{
|
||||
if (isColumnHidden(i))
|
||||
m_columnsHiddenStatus[i] = 1;
|
||||
}
|
||||
else if (!isColumnHidden(i))
|
||||
{
|
||||
setColumnHidden(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_progress = new QProgressDialog("Building blocks hierarchy...", "", 0, 100, this, Qt::FramelessWindowHint);
|
||||
m_progress->setAttribute(Qt::WA_TranslucentBackground);
|
||||
m_progress->setCancelButton(nullptr);
|
||||
@ -224,7 +277,11 @@ void EasyTreeWidget::onFillTimerTimeout()
|
||||
m_inputBlocks.clear();
|
||||
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(COL_BEGIN, Qt::AscendingOrder);
|
||||
|
||||
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);
|
||||
|
||||
//resizeColumnToContents(COL_NAME);
|
||||
resizeColumnsToContents();
|
||||
|
||||
@ -249,7 +306,7 @@ void EasyTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler:
|
||||
m_bLocked = true;
|
||||
m_progress->setValue(0);
|
||||
m_progress->show();
|
||||
m_hierarchyBuilder.fillTree(m_beginTime, _blocksNumber, _blocksTree, m_bColorRows);
|
||||
m_hierarchyBuilder.fillTree(m_beginTime, _blocksNumber, _blocksTree, m_bColorRows, m_mode);
|
||||
m_fillTimer.start(HIERARCHY_BUILDER_TIMER_INTERVAL);
|
||||
}
|
||||
|
||||
@ -282,7 +339,7 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
|
||||
m_bLocked = true;
|
||||
m_progress->setValue(0);
|
||||
m_progress->show();
|
||||
m_hierarchyBuilder.fillTreeBlocks(m_inputBlocks, _session_begin_time, _left, _right, _strict, m_bColorRows);
|
||||
m_hierarchyBuilder.fillTreeBlocks(m_inputBlocks, _session_begin_time, _left, _right, _strict, m_bColorRows, m_mode);
|
||||
m_fillTimer.start(HIERARCHY_BUILDER_TIMER_INTERVAL);
|
||||
}
|
||||
|
||||
@ -523,7 +580,24 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
menu.addSeparator();
|
||||
}
|
||||
|
||||
action = menu.addAction("Hierarchy mode");
|
||||
action->setToolTip("Display full blocks hierarchy");
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_mode == EasyTreeMode_Full);
|
||||
action->setData((quint32)EasyTreeMode_Full);
|
||||
connect(action, &QAction::triggered, this, &This::onModeChange);
|
||||
|
||||
action = menu.addAction("Plain mode");
|
||||
action->setToolTip("Display plain list of blocks per frame.\nSome columns are disabled with this mode.");
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_mode == EasyTreeMode_Plain);
|
||||
action->setData((quint32)EasyTreeMode_Plain);
|
||||
connect(action, &QAction::triggered, this, &This::onModeChange);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
action = menu.addAction("Color rows");
|
||||
action->setToolTip("Colorize rows with same colors as on diagram");
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_bColorRows);
|
||||
connect(action, &QAction::triggered, this, &This::onColorizeRowsTriggered);
|
||||
@ -610,8 +684,11 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
auto columnAction = new QAction(hdr->text(i), nullptr);
|
||||
columnAction->setData(i);
|
||||
columnAction->setCheckable(true);
|
||||
columnAction->setChecked(!isColumnHidden(i));
|
||||
connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn);
|
||||
columnAction->setChecked(m_columnsHiddenStatus[i] == 0);// !isColumnHidden(i));
|
||||
if (m_mode == EasyTreeMode_Full || SIMPLIFIED_REGIME_COLUMNS[i])
|
||||
connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn);
|
||||
else
|
||||
columnAction->setEnabled(false);
|
||||
hidemenu->addAction(columnAction);
|
||||
}
|
||||
|
||||
@ -951,11 +1028,36 @@ void EasyTreeWidget::onHideShowColumn(bool)
|
||||
if (action == nullptr)
|
||||
return;
|
||||
|
||||
auto col = action->data().toInt();
|
||||
if (isColumnHidden(col))
|
||||
showColumn(col);
|
||||
const auto col = action->data().toInt();
|
||||
const bool hideCol = m_columnsHiddenStatus[col] == 0;
|
||||
setColumnHidden(col, hideCol);
|
||||
m_columnsHiddenStatus[col] = hideCol ? 1 : 0;
|
||||
}
|
||||
|
||||
void EasyTreeWidget::onModeChange(bool)
|
||||
{
|
||||
auto action = qobject_cast<QAction*>(sender());
|
||||
if (action == nullptr)
|
||||
return;
|
||||
|
||||
const auto prev = m_mode;
|
||||
m_mode = static_cast<EasyTreeMode>(action->data().toUInt());
|
||||
|
||||
if (m_mode == prev)
|
||||
return;
|
||||
|
||||
if (m_mode == EasyTreeMode_Full)
|
||||
{
|
||||
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
|
||||
setColumnHidden(i, m_columnsHiddenStatus[i] != 0);
|
||||
}
|
||||
else
|
||||
hideColumn(col);
|
||||
{
|
||||
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
|
||||
setColumnHidden(i, m_columnsHiddenStatus[i] != 0 || !SIMPLIFIED_REGIME_COLUMNS[i]);
|
||||
}
|
||||
|
||||
emit EASY_GLOBALS.events.blocksTreeModeChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -965,9 +1067,20 @@ void EasyTreeWidget::loadSettings()
|
||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
||||
settings.beginGroup("tree_widget");
|
||||
|
||||
auto color_rows_set = settings.value("color_rows");
|
||||
if (!color_rows_set.isNull())
|
||||
m_bColorRows = color_rows_set.toBool();
|
||||
auto val = settings.value("color_rows");
|
||||
if (!val.isNull())
|
||||
m_bColorRows = val.toBool();
|
||||
|
||||
val = settings.value("regime");
|
||||
if (!val.isNull())
|
||||
m_mode = static_cast<EasyTreeMode>(val.toUInt());
|
||||
|
||||
val = settings.value("columns");
|
||||
if (!val.isNull())
|
||||
{
|
||||
auto byteArray = val.toByteArray();
|
||||
memcpy(m_columnsHiddenStatus, byteArray.constData(), sizeof(m_columnsHiddenStatus));
|
||||
}
|
||||
|
||||
auto state = settings.value("headerState").toByteArray();
|
||||
if (!state.isEmpty())
|
||||
@ -981,6 +1094,8 @@ void EasyTreeWidget::saveSettings()
|
||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
||||
settings.beginGroup("tree_widget");
|
||||
settings.setValue("color_rows", m_bColorRows);
|
||||
settings.setValue("regime", static_cast<uint8_t>(m_mode));
|
||||
settings.setValue("columns", QByteArray(m_columnsHiddenStatus, COL_COLUMNS_NUMBER));
|
||||
settings.setValue("headerState", header()->saveState());
|
||||
settings.endGroup();
|
||||
}
|
||||
@ -1085,6 +1200,15 @@ void EasyHierarchyWidget::keyPressEvent(QKeyEvent* _event)
|
||||
_event->accept();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EasyHierarchyWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
{
|
||||
m_tree->contextMenuEvent(_event);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EasyTreeWidget* EasyHierarchyWidget::tree()
|
||||
{
|
||||
return m_tree;
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include <QTreeWidget>
|
||||
#include <QTimer>
|
||||
#include "tree_widget_loader.h"
|
||||
#include "tree_widget_item.h"
|
||||
#include "easy/reader.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -78,15 +79,19 @@ protected:
|
||||
QTreeWidgetItem* m_lastFound;
|
||||
::profiler::timestamp_t m_beginTime;
|
||||
class QProgressDialog* m_progress;
|
||||
EasyTreeMode m_mode;
|
||||
bool m_bColorRows;
|
||||
bool m_bLocked;
|
||||
bool m_bSilentExpandCollapse;
|
||||
char m_columnsHiddenStatus[COL_COLUMNS_NUMBER];
|
||||
|
||||
public:
|
||||
|
||||
explicit EasyTreeWidget(QWidget* _parent = nullptr);
|
||||
virtual ~EasyTreeWidget();
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent* _event) override;
|
||||
|
||||
void clearSilent(bool _global = false);
|
||||
int findNext(const QString& _str, Qt::MatchFlags _flags);
|
||||
int findPrev(const QString& _str, Qt::MatchFlags _flags);
|
||||
@ -99,7 +104,6 @@ public slots:
|
||||
|
||||
protected:
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent* _event) override;
|
||||
void resizeEvent(QResizeEvent* _event) override;
|
||||
void moveEvent(QMoveEvent* _event) override;
|
||||
|
||||
@ -130,6 +134,7 @@ private slots:
|
||||
void resizeColumnsToContents();
|
||||
|
||||
void onHideShowColumn(bool);
|
||||
void onModeChange(bool);
|
||||
|
||||
void onFillTimerTimeout();
|
||||
|
||||
@ -165,6 +170,7 @@ public:
|
||||
explicit EasyHierarchyWidget(QWidget* _parent = nullptr);
|
||||
virtual ~EasyHierarchyWidget();
|
||||
void keyPressEvent(QKeyEvent* _event) override;
|
||||
void contextMenuEvent(QContextMenuEvent* _event) override;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -58,6 +58,7 @@ namespace profiler_gui {
|
||||
void hierarchyFlagChanged(bool);
|
||||
void threadNameDecorationChanged();
|
||||
void refreshRequired();
|
||||
void blocksTreeModeChanged();
|
||||
|
||||
}; // END of class EasyGlobalSignals.
|
||||
|
||||
|
@ -62,7 +62,11 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EasyTreeWidgetLoader::EasyTreeWidgetLoader() : m_bDone(ATOMIC_VAR_INIT(false)), m_bInterrupt(ATOMIC_VAR_INIT(false)), m_progress(ATOMIC_VAR_INIT(0))
|
||||
EasyTreeWidgetLoader::EasyTreeWidgetLoader()
|
||||
: m_bDone(ATOMIC_VAR_INIT(false))
|
||||
, m_bInterrupt(ATOMIC_VAR_INIT(false))
|
||||
, m_progress(ATOMIC_VAR_INIT(0))
|
||||
, m_mode(EasyTreeMode_Full)
|
||||
{
|
||||
}
|
||||
|
||||
@ -146,30 +150,32 @@ void EasyTreeWidgetLoader::interrupt(bool _wait)
|
||||
|
||||
m_items.clear();
|
||||
m_topLevelItems.clear();
|
||||
m_iditems.clear();
|
||||
}
|
||||
|
||||
void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows)
|
||||
void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, EasyTreeMode _mode)
|
||||
{
|
||||
interrupt();
|
||||
m_thread = ::std::move(::std::thread(&FillTreeClass<EasyTreeWidgetLoader>::setTreeInternal1,
|
||||
::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), ::std::ref(_beginTime),
|
||||
_blocksNumber, ::std::ref(_blocksTree), _colorizeRows, EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.time_units));
|
||||
m_mode = _mode;
|
||||
m_thread = ::std::move(::std::thread(&EasyTreeWidgetLoader::setTreeInternal1, this,
|
||||
::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows,
|
||||
EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.time_units));
|
||||
}
|
||||
|
||||
void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows)
|
||||
void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, EasyTreeMode _mode)
|
||||
{
|
||||
interrupt();
|
||||
m_thread = ::std::move(::std::thread(&FillTreeClass<EasyTreeWidgetLoader>::setTreeInternal2,
|
||||
::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), _beginTime, ::std::ref(_blocks),
|
||||
_left, _right, _strict, _colorizeRows, EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.time_units));
|
||||
m_mode = _mode;
|
||||
m_thread = ::std::move(::std::thread(&EasyTreeWidgetLoader::setTreeInternal2, this,
|
||||
_beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows,
|
||||
EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.time_units));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
void FillTreeClass<T>::setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
|
||||
void EasyTreeWidgetLoader::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)
|
||||
{
|
||||
_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks
|
||||
m_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks
|
||||
|
||||
::profiler::timestamp_t finishtime = 0;
|
||||
for (const auto& threadTree : _blocksTree)
|
||||
@ -191,12 +197,12 @@ void FillTreeClass<T>::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI
|
||||
const int total = static_cast<int>(_blocksTree.size());
|
||||
for (const auto& threadTree : _blocksTree)
|
||||
{
|
||||
if (_safelocker.interrupted())
|
||||
if (interrupted())
|
||||
break;
|
||||
|
||||
const auto& root = threadTree.second;
|
||||
auto item = new EasyTreeWidgetItem();
|
||||
item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root, u_thread));
|
||||
item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, root, u_thread));
|
||||
|
||||
::profiler::timestamp_t duration = 0;
|
||||
if (!root.children.empty())
|
||||
@ -211,14 +217,14 @@ void FillTreeClass<T>::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI
|
||||
item->setTimeSmart(COL_SELF_DURATION, _units, root.profiled_time);
|
||||
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
const auto children_items_number = FillTreeClass<T>::setTreeInternal(_safelocker, _items, _beginTime, root.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
const auto children_items_number = setTreeInternal(_beginTime, root.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
|
||||
if (children_items_number > 0)
|
||||
{
|
||||
//total_items += children_items_number + 1;
|
||||
//addTopLevelItem(item);
|
||||
//m_roots[threadTree.first] = item;
|
||||
_topLevelItems.emplace_back(root.thread_id, item);
|
||||
m_topLevelItems.emplace_back(root.thread_id, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -226,25 +232,24 @@ void FillTreeClass<T>::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI
|
||||
delete item;
|
||||
}
|
||||
|
||||
_safelocker.setProgress((100 * ++i) / total);
|
||||
setProgress((100 * ++i) / total);
|
||||
}
|
||||
|
||||
_safelocker.setDone();
|
||||
setDone();
|
||||
//return total_items;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto calculateTotalChildrenNumber(const ::profiler::BlocksTree& _tree) -> decltype(_tree.children.size())
|
||||
{
|
||||
auto children_number = _tree.children.size();
|
||||
for (auto i : _tree.children)
|
||||
children_number += calculateTotalChildrenNumber(blocksTree(i));
|
||||
return children_number;
|
||||
}
|
||||
// auto calculateTotalChildrenNumber(const ::profiler::BlocksTree& _tree) -> decltype(_tree.children.size())
|
||||
// {
|
||||
// auto children_number = _tree.children.size();
|
||||
// for (auto i : _tree.children)
|
||||
// children_number += calculateTotalChildrenNumber(blocksTree(i));
|
||||
// return children_number;
|
||||
// }
|
||||
|
||||
template <class T>
|
||||
void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
|
||||
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;
|
||||
//for (const auto& block : _blocks)
|
||||
@ -254,12 +259,14 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
|
||||
RootsMap threadsMap;
|
||||
|
||||
auto const setTree = (m_mode == EasyTreeMode_Full) ? &EasyTreeWidgetLoader::setTreeInternal : &EasyTreeWidgetLoader::setTreeInternalPlain;
|
||||
|
||||
const auto u_thread = ::profiler_gui::toUnicode("thread");
|
||||
int i = 0, total = static_cast<int>(_blocks.size());
|
||||
//const QSignalBlocker b(this);
|
||||
for (const auto& block : _blocks)
|
||||
{
|
||||
if (_safelocker.interrupted())
|
||||
if (interrupted())
|
||||
break;
|
||||
|
||||
auto& gui_block = easyBlock(block.tree);
|
||||
@ -267,7 +274,7 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
const auto endTime = gui_block.tree.node->end();
|
||||
if (startTime > _right || endTime < _left)
|
||||
{
|
||||
_safelocker.setProgress((90 * ++i) / total);
|
||||
setProgress((90 * ++i) / total);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -281,7 +288,7 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
else
|
||||
{
|
||||
thread_item = new EasyTreeWidgetItem();
|
||||
thread_item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, *block.root, u_thread));
|
||||
thread_item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, *block.root, u_thread));
|
||||
|
||||
if (!block.root->children.empty())
|
||||
duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin();
|
||||
@ -313,15 +320,15 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
|
||||
if (gui_block.tree.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
|
||||
{
|
||||
const auto& per_thread_stats = gui_block.tree.per_thread_stats;
|
||||
const auto& per_parent_stats = gui_block.tree.per_parent_stats;
|
||||
const auto& per_frame_stats = gui_block.tree.per_frame_stats;
|
||||
const ::profiler::BlockStatistics* per_thread_stats = gui_block.tree.per_thread_stats;
|
||||
const ::profiler::BlockStatistics* per_parent_stats = gui_block.tree.per_parent_stats;
|
||||
const ::profiler::BlockStatistics* per_frame_stats = gui_block.tree.per_frame_stats;
|
||||
|
||||
|
||||
if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_THREAD, _units, per_thread_stats->min_duration, "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_THREAD, _units, per_thread_stats->max_duration, "max ");
|
||||
item->setTimeSmart(COL_MIN_PER_THREAD, _units, easyBlock(per_thread_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_THREAD, _units, easyBlock(per_thread_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
item->setTimeSmart(COL_AVERAGE_PER_THREAD, _units, per_thread_stats->average_duration());
|
||||
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, _units, per_thread_stats->total_duration);
|
||||
}
|
||||
@ -336,8 +343,8 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
|
||||
if (per_parent_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_PARENT, _units, per_parent_stats->min_duration, "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_PARENT, _units, per_parent_stats->max_duration, "max ");
|
||||
item->setTimeSmart(COL_MIN_PER_PARENT, _units, easyBlock(per_parent_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_PARENT, _units, easyBlock(per_parent_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
item->setTimeSmart(COL_AVERAGE_PER_PARENT, _units, per_parent_stats->average_duration());
|
||||
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, _units, per_parent_stats->total_duration);
|
||||
}
|
||||
@ -348,8 +355,8 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
|
||||
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_FRAME, _units, per_frame_stats->min_duration, "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_FRAME, _units, per_frame_stats->max_duration, "max ");
|
||||
item->setTimeSmart(COL_MIN_PER_FRAME, _units, easyBlock(per_frame_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_FRAME, _units, easyBlock(per_frame_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
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);
|
||||
}
|
||||
@ -370,16 +377,17 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
item->setTextColor(fgColor);
|
||||
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
auto item_index = static_cast<unsigned int>(_items.size());
|
||||
_items.push_back(item);
|
||||
auto item_index = static_cast<unsigned int>(m_items.size());
|
||||
m_items.push_back(item);
|
||||
#endif
|
||||
|
||||
size_t children_items_number = 0;
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
if (!gui_block.tree.children.empty())
|
||||
{
|
||||
children_items_number = FillTreeClass<T>::setTreeInternal(_safelocker, _items, _beginTime, gui_block.tree.children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
if (_safelocker.interrupted())
|
||||
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);
|
||||
if (interrupted())
|
||||
break;
|
||||
}
|
||||
|
||||
@ -408,18 +416,18 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
item->setExpanded(true);
|
||||
|
||||
#ifndef EASY_TREE_WIDGET__USE_VECTOR
|
||||
_items.insert(::std::make_pair(block.tree, item));
|
||||
m_items.insert(::std::make_pair(block.tree, item));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
_items.pop_back();
|
||||
m_items.pop_back();
|
||||
#endif
|
||||
delete item;
|
||||
}
|
||||
|
||||
_safelocker.setProgress((90 * ++i) / total);
|
||||
setProgress((90 * ++i) / total);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
@ -434,7 +442,7 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
//m_roots[it.first] = item;
|
||||
|
||||
//_items.push_back(item);
|
||||
_topLevelItems.emplace_back(it.first, item);
|
||||
m_topLevelItems.emplace_back(it.first, item);
|
||||
|
||||
//++total_items;
|
||||
}
|
||||
@ -443,20 +451,23 @@ void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI
|
||||
delete item;
|
||||
}
|
||||
|
||||
_safelocker.setProgress(90 + (10 * ++i) / total);
|
||||
setProgress(90 + (10 * ++i) / total);
|
||||
}
|
||||
|
||||
_safelocker.setDone();
|
||||
setDone();
|
||||
//return total_items;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, 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::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)
|
||||
{
|
||||
auto const setTree = m_mode == EasyTreeMode_Full ? &EasyTreeWidgetLoader::setTreeInternal : &EasyTreeWidgetLoader::setTreeInternalPlain;
|
||||
|
||||
size_t total_items = 0;
|
||||
for (auto child_index : _children)
|
||||
{
|
||||
if (_safelocker.interrupted())
|
||||
if (interrupted())
|
||||
break;
|
||||
|
||||
auto& gui_block = easyBlock(child_index);
|
||||
@ -484,9 +495,9 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
|
||||
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;
|
||||
const ::profiler::BlockStatistics* per_thread_stats = child.per_thread_stats;
|
||||
const ::profiler::BlockStatistics* per_parent_stats = child.per_parent_stats;
|
||||
const ::profiler::BlockStatistics* per_frame_stats = child.per_frame_stats;
|
||||
|
||||
auto parent_duration = _parent->duration();
|
||||
auto percentage = duration == 0 ? 0 : ::profiler_gui::percent(duration, parent_duration);
|
||||
@ -530,8 +541,8 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
|
||||
if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_THREAD, _units, per_thread_stats->min_duration, "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_THREAD, _units, per_thread_stats->max_duration, "max ");
|
||||
item->setTimeSmart(COL_MIN_PER_THREAD, _units, easyBlock(per_thread_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_THREAD, _units, easyBlock(per_thread_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
item->setTimeSmart(COL_AVERAGE_PER_THREAD, _units, per_thread_stats->average_duration());
|
||||
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, _units, per_thread_stats->total_duration);
|
||||
}
|
||||
@ -549,8 +560,8 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
|
||||
if (per_parent_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_PARENT, _units, per_parent_stats->min_duration, "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_PARENT, _units, per_parent_stats->max_duration, "max ");
|
||||
item->setTimeSmart(COL_MIN_PER_PARENT, _units, easyBlock(per_parent_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_PARENT, _units, easyBlock(per_parent_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
item->setTimeSmart(COL_AVERAGE_PER_PARENT, _units, per_parent_stats->average_duration());
|
||||
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, _units, per_parent_stats->total_duration);
|
||||
}
|
||||
@ -561,8 +572,8 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
|
||||
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_FRAME, _units, per_frame_stats->min_duration, "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_FRAME, _units, per_frame_stats->max_duration, "max ");
|
||||
item->setTimeSmart(COL_MIN_PER_FRAME, _units, easyBlock(per_frame_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_FRAME, _units, easyBlock(per_frame_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
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);
|
||||
}
|
||||
@ -594,16 +605,17 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
item->setTextColor(fgColor);
|
||||
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
auto item_index = static_cast<uint32_t>(_items.size());
|
||||
_items.push_back(item);
|
||||
auto item_index = static_cast<uint32_t>(m_items.size());
|
||||
m_items.push_back(item);
|
||||
#endif
|
||||
|
||||
size_t children_items_number = 0;
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
if (!child.children.empty())
|
||||
{
|
||||
children_items_number = FillTreeClass<T>::setTreeInternal(_safelocker, _items, _beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
if (_safelocker.interrupted())
|
||||
m_iditems.clear();
|
||||
children_items_number = (this->*setTree)(_beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
|
||||
if (interrupted())
|
||||
break;
|
||||
}
|
||||
|
||||
@ -632,13 +644,13 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
item->setExpanded(true);
|
||||
|
||||
#ifndef EASY_TREE_WIDGET__USE_VECTOR
|
||||
_items.insert(::std::make_pair(child_index, item));
|
||||
m_items.insert(::std::make_pair(child_index, item));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
_items.pop_back();
|
||||
m_items.pop_back();
|
||||
#endif
|
||||
delete item;
|
||||
}
|
||||
@ -649,7 +661,139 @@ size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template struct FillTreeClass<EasyTreeWidgetLoader>;
|
||||
template struct FillTreeClass<StubLocker>;
|
||||
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)
|
||||
{
|
||||
size_t total_items = 0;
|
||||
for (auto child_index : _children)
|
||||
{
|
||||
if (interrupted())
|
||||
break;
|
||||
|
||||
auto& gui_block = easyBlock(child_index);
|
||||
const auto& child = gui_block.tree;
|
||||
const auto startTime = child.node->begin();
|
||||
const auto endTime = child.node->end();
|
||||
const auto duration = endTime - startTime;
|
||||
|
||||
_duration += duration;
|
||||
|
||||
if (startTime > _right || endTime < _left)
|
||||
continue;
|
||||
|
||||
if (m_iditems.find(gui_block.tree.node->id()) != m_iditems.end())
|
||||
{
|
||||
++total_items;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto item = new EasyTreeWidgetItem(child_index, _frame);
|
||||
|
||||
auto name = *child.node->name() != 0 ? child.node->name() : easyDescriptor(child.node->id()).name();
|
||||
item->setText(COL_NAME, ::profiler_gui::toUnicode(name));
|
||||
|
||||
if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
|
||||
{
|
||||
const ::profiler::BlockStatistics* per_thread_stats = child.per_thread_stats;
|
||||
if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_THREAD, _units, easyBlock(per_thread_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_THREAD, _units, easyBlock(per_thread_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
item->setTimeSmart(COL_AVERAGE_PER_THREAD, _units, per_thread_stats->average_duration());
|
||||
}
|
||||
|
||||
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, _units, per_thread_stats->total_duration);
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
|
||||
{
|
||||
item->setTimeSmart(COL_MIN_PER_FRAME, _units, easyBlock(per_frame_stats->min_duration_block).tree.node->duration(), "min ");
|
||||
item->setTimeSmart(COL_MAX_PER_FRAME, _units, easyBlock(per_frame_stats->max_duration_block).tree.node->duration(), "max ");
|
||||
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->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);
|
||||
}
|
||||
|
||||
const auto color = easyDescriptor(child.node->id()).color();
|
||||
const auto fgColor = ::profiler_gui::textColorForRgb(color);// 0x00ffffff - bgColor;
|
||||
item->setBackgroundColor(color);
|
||||
item->setTextColor(fgColor);
|
||||
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
auto item_index = static_cast<uint32_t>(m_items.size());
|
||||
m_items.push_back(item);
|
||||
#endif
|
||||
m_iditems.insert(gui_block.tree.node->id());
|
||||
|
||||
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);
|
||||
if (interrupted())
|
||||
break;
|
||||
}
|
||||
|
||||
if (child.per_frame_stats != nullptr)
|
||||
{
|
||||
int percentage = 100;
|
||||
auto self_duration = child.per_frame_stats->total_duration - child.per_frame_stats->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));
|
||||
}
|
||||
|
||||
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
|
||||
{
|
||||
total_items += children_items_number + 1;
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
gui_block.tree_item = item_index;
|
||||
#endif
|
||||
|
||||
if (_colorizeRows)
|
||||
item->colorize(_colorizeRows);
|
||||
|
||||
if (gui_block.expanded)
|
||||
item->setExpanded(true);
|
||||
|
||||
#ifndef EASY_TREE_WIDGET__USE_VECTOR
|
||||
m_items.insert(::std::make_pair(child_index, item));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||
m_items.pop_back();
|
||||
#endif
|
||||
delete item;
|
||||
m_iditems.erase(gui_block.tree.node->id());
|
||||
}
|
||||
}
|
||||
|
||||
return total_items;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include "easy/reader.h"
|
||||
@ -66,6 +67,15 @@ 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;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum EasyTreeMode : uint8_t
|
||||
{
|
||||
EasyTreeMode_Full,
|
||||
EasyTreeMode_Plain
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -73,17 +83,18 @@ class EasyTreeWidgetLoader Q_DECL_FINAL
|
||||
{
|
||||
ThreadedItems m_topLevelItems; ///<
|
||||
Items m_items; ///<
|
||||
IdItems m_iditems; ///<
|
||||
::std::thread m_thread; ///<
|
||||
::std::atomic_bool m_bDone; ///<
|
||||
::std::atomic_bool m_bInterrupt; ///<
|
||||
::std::atomic<int> m_progress; ///<
|
||||
EasyTreeMode m_mode; ///<
|
||||
|
||||
public:
|
||||
|
||||
EasyTreeWidgetLoader();
|
||||
~EasyTreeWidgetLoader();
|
||||
|
||||
bool interrupted() const;
|
||||
int progress() const;
|
||||
bool done() const;
|
||||
|
||||
@ -91,33 +102,22 @@ public:
|
||||
void takeItems(Items& _output);
|
||||
|
||||
void interrupt(bool _wait = false);
|
||||
void fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows);
|
||||
void fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows);
|
||||
void fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, EasyTreeMode _mode);
|
||||
void fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, EasyTreeMode _mode);
|
||||
|
||||
private:
|
||||
|
||||
bool interrupted() const;
|
||||
void setDone();
|
||||
void setProgress(int _progress);
|
||||
|
||||
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);
|
||||
|
||||
}; // END of class EasyTreeWidgetLoader.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
struct FillTreeClass Q_DECL_FINAL
|
||||
{
|
||||
static void setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
|
||||
static void setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
|
||||
static size_t setTreeInternal(T& _safelocker, Items& _items, 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);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct StubLocker Q_DECL_FINAL
|
||||
{
|
||||
void setDone() {}
|
||||
bool interrupted() const { return false; }
|
||||
void setProgress(int) {}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY__TREE_WIDGET_LOADER__H_
|
||||
|
Loading…
x
Reference in New Issue
Block a user