diff --git a/easy_profiler_core/include/easy/reader.h b/easy_profiler_core/include/easy/reader.h index 9f06469..26f85b7 100644 --- a/easy_profiler_core/include/easy/reader.h +++ b/easy_profiler_core/include/easy/reader.h @@ -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) diff --git a/easy_profiler_core/reader.cpp b/easy_profiler_core/reader.cpp index a0bf702..1486a70 100644 --- a/easy_profiler_core/reader.cpp +++ b/easy_profiler_core/reader.cpp @@ -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()); } diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index 3bcfc02..fa41185 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -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()); + }); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 52ced8c..cd14b25 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -65,9 +65,9 @@ #include #include #include +#include #include #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::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(sender()); + if (action == nullptr) + return; + + const auto prev = m_mode; + m_mode = static_cast(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(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(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; diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index 100302e..1b03698 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -56,6 +56,7 @@ #include #include #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: diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index 89f2d20..c5d3f98 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -58,6 +58,7 @@ namespace profiler_gui { void hierarchyFlagChanged(bool); void threadNameDecorationChanged(); void refreshRequired(); + void blocksTreeModeChanged(); }; // END of class EasyGlobalSignals. diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index d763857..94cd91c 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -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::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::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 -void FillTreeClass::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::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI const int total = static_cast(_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::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::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::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 -void FillTreeClass::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::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(_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::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::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::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::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::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::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setTextColor(fgColor); #ifdef EASY_TREE_WIDGET__USE_VECTOR - auto item_index = static_cast(_items.size()); - _items.push_back(item); + auto item_index = static_cast(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::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::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::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::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 -size_t FillTreeClass::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::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::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::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::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::setTreeInternal(T& _safelocker, Items& _items, const :: item->setTextColor(fgColor); #ifdef EASY_TREE_WIDGET__USE_VECTOR - auto item_index = static_cast(_items.size()); - _items.push_back(item); + auto item_index = static_cast(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::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::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::setTreeInternal(T& _safelocker, Items& _items, const :: ////////////////////////////////////////////////////////////////////////// -template struct FillTreeClass; -template struct FillTreeClass; +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(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; +} ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/tree_widget_loader.h b/profiler_gui/tree_widget_loader.h index 1407295..9cdc127 100644 --- a/profiler_gui/tree_widget_loader.h +++ b/profiler_gui/tree_widget_loader.h @@ -49,6 +49,7 @@ #include #include +#include #include #include #include "easy/reader.h" @@ -66,6 +67,15 @@ typedef ::std::vector 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 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 -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_