diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index e52f8ed..2322871 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -460,7 +460,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr if (!t.children.empty()) { - children_duration = setTree(item, ~0U, t.children, h, y, 0); + children_duration = setTree(item, t.children, h, y, 0); } else { @@ -532,7 +532,7 @@ const EasyGraphicsView::Items &EasyGraphicsView::getItems() const return m_items; } -qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, ::profiler::block_index_t _parent, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level) +qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level) { if (_children.empty()) { @@ -540,7 +540,8 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, ::profiler::block_index } const auto level = static_cast(_level); - _item->reserve(level, static_cast(_children.size())); + const auto n = static_cast(_children.size()); + _item->reserve(level, n); const short next_level = _level + 1; bool warned = false; @@ -592,7 +593,7 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, ::profiler::block_index if (next_level < 256) { - children_duration = setTree(_item, child_index, child.children, h, _y + ::profiler_gui::GRAPHICS_ROW_SIZE_FULL, next_level); + children_duration = setTree(_item, child.children, h, _y + ::profiler_gui::GRAPHICS_ROW_SIZE_FULL, next_level); } else if (!child.children.empty() && !warned) { @@ -611,7 +612,7 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, ::profiler::block_index } b.block = child_index;// &child; - b.parent = _parent; + b.neighbours = n; b.setPos(xbegin, duration); //b.totalHeight = ::profiler_gui::GRAPHICS_ROW_SIZE + h; b.state = j > 0 || level == 0 ? 0 : -1; diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 014d2e5..55e40b1 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -185,7 +185,7 @@ private: void scaleTo(qreal _scale); void scrollTo(const EasyGraphicsItem* _item); void onWheel(qreal _mouseX, int _wheelDelta); - qreal setTree(EasyGraphicsItem* _item, ::profiler::block_index_t _parent, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level); + qreal setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level); private slots: diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index f7de000..52ced8c 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -116,16 +116,16 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent) header_item->setText(COL_DURATION, "Duration"); header_item->setText(COL_SELF_DURATION, "Self Dur."); //header_item->setToolTip(COL_SELF_DURATION, ""); - header_item->setText(COL_DURATION_SUM_PER_PARENT, "Tot. Dur./Parent"); - header_item->setText(COL_DURATION_SUM_PER_FRAME, "Tot. Dur./Frame"); - header_item->setText(COL_DURATION_SUM_PER_THREAD, "Tot. Dur./Thread"); + header_item->setText(COL_DURATION_SUM_PER_PARENT, "Sum Dur./Parent"); + header_item->setText(COL_DURATION_SUM_PER_FRAME, "Sum Dur./Frame"); + header_item->setText(COL_DURATION_SUM_PER_THREAD, "Sum Dur./Thread"); header_item->setText(COL_SELF_DURATION_PERCENT, "Self %"); header_item->setText(COL_PERCENT_PER_PARENT, "% / Parent"); header_item->setText(COL_PERCENT_PER_FRAME, "% / Frame"); - header_item->setText(COL_PERCENT_SUM_PER_FRAME, "Tot. % / Frame"); - header_item->setText(COL_PERCENT_SUM_PER_PARENT, "Tot. % / Parent"); - header_item->setText(COL_PERCENT_SUM_PER_THREAD, "Tot. % / Thread"); + header_item->setText(COL_PERCENT_SUM_PER_FRAME, "Sum % / Frame"); + header_item->setText(COL_PERCENT_SUM_PER_PARENT, "Sum % / Parent"); + header_item->setText(COL_PERCENT_SUM_PER_THREAD, "Sum % / Thread"); header_item->setText(COL_END, "End, ms"); @@ -335,16 +335,27 @@ void EasyTreeWidget::clearSilent(bool _global) if (!_global) { - if (EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items) + if (EASY_GLOBALS.collapse_items_on_tree_close) +#ifdef EASY_TREE_WIDGET__USE_VECTOR + for (auto item : m_items) +#else + for (auto& item : m_items) +#endif { +#ifdef EASY_TREE_WIDGET__USE_VECTOR auto& gui_block = item->guiBlock(); - ::profiler_gui::set_max(gui_block.tree_item); gui_block.expanded = false; + ::profiler_gui::set_max(gui_block.tree_item); +#else + item.second->guiBlock().expanded = false; +#endif } +#ifdef EASY_TREE_WIDGET__USE_VECTOR else for (auto item : m_items) { ::profiler_gui::set_max(item->guiBlock().tree_item); } +#endif } m_items.clear(); @@ -656,8 +667,13 @@ void EasyTreeWidget::onCollapseAllClicked(bool) if (EASY_GLOBALS.bind_scene_and_tree_expand_status) { +#ifdef EASY_TREE_WIDGET__USE_VECTOR for (auto item : m_items) item->guiBlock().expanded = false; +#else + for (auto& item : m_items) + item.second->guiBlock().expanded = false; +#endif emit EASY_GLOBALS.events.itemsExpandStateChanged(); } } @@ -673,9 +689,13 @@ void EasyTreeWidget::onExpandAllClicked(bool) if (EASY_GLOBALS.bind_scene_and_tree_expand_status) { - for (auto item : m_items) - { +#ifdef EASY_TREE_WIDGET__USE_VECTOR + for (auto item : m_items){ auto& b = item->guiBlock(); +#else + for (auto& item : m_items){ + auto& b = item.second->guiBlock(); +#endif b.expanded = !b.tree.children.empty(); } @@ -811,11 +831,19 @@ void EasyTreeWidget::onColorizeRowsTriggered(bool _colorize) collapseAll(); // Without collapseAll() changing items process is VERY VERY SLOW. // TODO: Find the reason of such behavior. QSignalBlocker(this) does not help. QSignalBlocker(item) does not work, because items are not inherited from QObject. +#ifdef EASY_TREE_WIDGET__USE_VECTOR for (auto item : m_items) { if (item->parent() != nullptr) item->colorize(m_bColorRows); } +#else + for (auto& item : m_items) + { + if (item.second->parent() != nullptr) + item.second->colorize(m_bColorRows); + } +#endif // Scroll back to previously selected item if (current) @@ -843,9 +871,15 @@ void EasyTreeWidget::onSelectedBlockChange(uint32_t _block_index) if (_block_index < EASY_GLOBALS.gui_blocks.size()) { +#ifdef EASY_TREE_WIDGET__USE_VECTOR const auto i = easyBlock(_block_index).tree_item; if (i < m_items.size()) item = m_items[i]; +#else + auto it = m_items.find(_block_index); + if (it != m_items.end()) + item = it->second; +#endif } if (item != nullptr) diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index 47a0d33..9a7b815 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -155,13 +155,12 @@ inline ::profiler::color_t textColorForRgb(::profiler::color_t _color) #pragma pack(push, 1) struct EasyBlockItem Q_DECL_FINAL { - qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene) - float w; ///< Width of the item - ::profiler::block_index_t block; ///< Index of profiler block - ::profiler::block_index_t parent; ///< Index of parent profiler block - uint32_t children_begin; ///< Index of first child item on the next sublevel - //uint16_t totalHeight; ///< Total height of the item including heights of all it's children - int8_t state; ///< 0 = no change, 1 = paint, -1 = do not paint + qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene) + float w; ///< Width of the item + ::profiler::block_index_t block; ///< Index of profiler block + ::profiler::block_index_t neighbours; ///< Number of neighbours (parent.children.size()) + uint32_t children_begin; ///< Index of first child item on the next sublevel + int8_t state; ///< 0 = no change, 1 = paint, -1 = do not paint // Possible optimizations: // 1) We can save 1 more byte per block if we will use char instead of short + real time calculations for "totalHeight" var; @@ -175,10 +174,13 @@ struct EasyBlockItem Q_DECL_FINAL }; // END of struct EasyBlockItem. +//#define EASY_TREE_WIDGET__USE_VECTOR struct EasyBlock Q_DECL_FINAL { ::profiler::BlocksTree tree; +#ifdef EASY_TREE_WIDGET__USE_VECTOR uint32_t tree_item; +#endif uint32_t graphics_item_index; uint8_t graphics_item_level; uint8_t graphics_item; @@ -188,7 +190,9 @@ struct EasyBlock Q_DECL_FINAL EasyBlock(EasyBlock&& that) : tree(::std::move(that.tree)) +#ifdef EASY_TREE_WIDGET__USE_VECTOR , tree_item(that.tree_item) +#endif , graphics_item_index(that.graphics_item_index) , graphics_item_level(that.graphics_item_level) , graphics_item(that.graphics_item) diff --git a/profiler_gui/easy_graphics_item.cpp b/profiler_gui/easy_graphics_item.cpp index 2fc8465..4d097b5 100644 --- a/profiler_gui/easy_graphics_item.cpp +++ b/profiler_gui/easy_graphics_item.cpp @@ -207,6 +207,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* if (gotItems) { static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(); + const int narrow_size_half = EASY_GLOBALS.blocks_narrow_size >> 1; + //auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::EasyBlockItem::children_begin) children_begin) //{ // // Mark that we would not paint children of current item @@ -270,30 +272,15 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* { // This item is not visible //skip_children(next_level, item.children_begin); - - if (item.parent != ~0U) - { - const auto n = static_cast(easyBlock(item.parent).tree.children.size()); - if (neighbour < n) - i += n - neighbour - 1; // Skip all neighbours - } - + if (neighbour < item.neighbours) + i += item.neighbours - neighbour - 1; // Skip all neighbours continue; } - if (state == BLOCK_ITEM_DO_PAINT_FIRST) + if (state == BLOCK_ITEM_DO_PAINT_FIRST && item.children_begin == MAX_CHILD_INDEX && next_level < levelsNumber && neighbour < (item.neighbours-1)) { // Paint only first child which has own children - - if (item.children_begin == MAX_CHILD_INDEX && next_level < levelsNumber) - continue; // This item has no children and would not be painted - - if (item.parent != ~0U) - { - const auto n = static_cast(easyBlock(item.parent).tree.children.size()); - if (neighbour < n) - i += n - neighbour - 1; // Skip all neighbours - } + continue; // This item has no children and would not be painted } const auto& itemBlock = easyBlock(item.block); @@ -324,6 +311,18 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* x = prevRight; } + if (EASY_GLOBALS.hide_minsize_blocks && w < EASY_GLOBALS.blocks_size_min && l > 0) + { + // Hide blocks (except top-level blocks) which width is less than 1 pixel + continue; + } + + if (state == BLOCK_ITEM_DO_PAINT_FIRST && neighbour < item.neighbours) + { + // Paint only first child which has own children + i += item.neighbours - neighbour - 1; // Skip all neighbours + } + const auto& itemDesc = easyDescriptor(itemBlock.tree.node->id()); int h = 0, flags = 0; @@ -450,7 +449,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* prevRight = rect.right() + EASY_GLOBALS.blocks_spacing; if (w < EASY_GLOBALS.blocks_narrow_size) { - dont_skip_children(next_level, item.children_begin, BLOCK_ITEM_DO_PAINT_FIRST); + dont_skip_children(next_level, item.children_begin, w < narrow_size_half ? BLOCK_ITEM_DO_PAINT_FIRST : BLOCK_ITEM_DO_PAINT); continue; } diff --git a/profiler_gui/globals.cpp b/profiler_gui/globals.cpp index 8e25057..f6608f9 100644 --- a/profiler_gui/globals.cpp +++ b/profiler_gui/globals.cpp @@ -75,6 +75,7 @@ namespace profiler_gui { , add_zero_blocks_to_hierarchy(false) , draw_graphics_items_borders(true) , hide_narrow_children(false) + , hide_minsize_blocks(false) , display_only_relevant_stats(true) , collapse_items_on_tree_close(false) , all_items_expanded_by_default(true) diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index 5d78210..46afbdd 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -124,7 +124,8 @@ namespace profiler_gui { bool enable_zero_length; ///< Enable zero length blocks (if true, then such blocks will have width == 1 pixel on each scale) bool add_zero_blocks_to_hierarchy; ///< Enable adding zero blocks into hierarchy tree bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not - bool hide_narrow_children; ///< Hide children for narrow graphics blocks + bool hide_narrow_children; ///< Hide children for narrow graphics blocks (See blocks_narrow_size) + bool hide_minsize_blocks; ///< Hide blocks which screen size is less than blocks_size_min bool display_only_relevant_stats; ///< Display only relevant information in ProfTreeWidget (excludes min, max, average times if there are only 1 calls number) bool collapse_items_on_tree_close; ///< Collapse all items which were displayed in the hierarchy tree after tree close/reset bool all_items_expanded_by_default; ///< Expand all items after file is opened diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index f670480..1191121 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -264,13 +264,19 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("localhost"), m_lastP action->setToolTip("Draw borders for blocks on diagram.\nThis reduces performance."); action->setCheckable(true); action->setChecked(EASY_GLOBALS.draw_graphics_items_borders); - connect(action, &QAction::triggered, this, &This::onDrawBordersChanged); + connect(action, &QAction::triggered, [this](bool _checked){ EASY_GLOBALS.draw_graphics_items_borders = _checked; refreshDiagram(); }); - action = submenu->addAction("Hide narrow children"); - action->setToolTip("Children blocks will be hidden by narrow\nparent blocks. See also \"Blocks narrow size\".\nThis improves performance."); + action = submenu->addAction("Overlap narrow children"); + action->setToolTip("Children blocks will be overlaped by narrow\nparent blocks. See also \'Blocks narrow size\'.\nThis improves performance."); action->setCheckable(true); action->setChecked(EASY_GLOBALS.hide_narrow_children); - connect(action, &QAction::triggered, this, &This::onHideNarrowChildrenChanged); + connect(action, &QAction::triggered, [this](bool _checked){ EASY_GLOBALS.hide_narrow_children = _checked; refreshDiagram(); }); + + action = submenu->addAction("Hide min-size blocks"); + action->setToolTip("Hides blocks which screen size\nis less than \'Min blocks size\'."); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.hide_minsize_blocks); + connect(action, &QAction::triggered, [this](bool _checked){ EASY_GLOBALS.hide_minsize_blocks = _checked; refreshDiagram(); }); action = submenu->addAction("Build hierarchy only for current thread"); action->setToolTip("Hierarchy tree will be built\nfor blocks from current thread only.\nThis improves performance\nand saves a lot of memory."); @@ -798,18 +804,6 @@ void EasyMainWindow::onEnableDisableStatistics(bool _checked) } } -void EasyMainWindow::onDrawBordersChanged(bool _checked) -{ - EASY_GLOBALS.draw_graphics_items_borders = _checked; - refreshDiagram(); -} - -void EasyMainWindow::onHideNarrowChildrenChanged(bool _checked) -{ - EASY_GLOBALS.hide_narrow_children = _checked; - refreshDiagram(); -} - void EasyMainWindow::onCollapseItemsAfterCloseChanged(bool _checked) { EASY_GLOBALS.collapse_items_on_tree_close = _checked; @@ -979,6 +973,10 @@ void EasyMainWindow::loadSettings() if (!flag.isNull()) EASY_GLOBALS.hide_narrow_children = flag.toBool(); + flag = settings.value("hide_minsize_blocks"); + if (!flag.isNull()) + EASY_GLOBALS.hide_minsize_blocks = flag.toBool(); + flag = settings.value("collapse_items_on_tree_close"); if (!flag.isNull()) EASY_GLOBALS.collapse_items_on_tree_close = flag.toBool(); @@ -1062,6 +1060,7 @@ void EasyMainWindow::saveSettingsAndGeometry() settings.setValue("blocks_narrow_size", EASY_GLOBALS.blocks_narrow_size); settings.setValue("draw_graphics_items_borders", EASY_GLOBALS.draw_graphics_items_borders); settings.setValue("hide_narrow_children", EASY_GLOBALS.hide_narrow_children); + settings.setValue("hide_minsize_blocks", EASY_GLOBALS.hide_minsize_blocks); settings.setValue("collapse_items_on_tree_close", EASY_GLOBALS.collapse_items_on_tree_close); settings.setValue("all_items_expanded_by_default", EASY_GLOBALS.all_items_expanded_by_default); settings.setValue("only_current_thread_hierarchy", EASY_GLOBALS.only_current_thread_hierarchy); @@ -1208,7 +1207,9 @@ void EasyMainWindow::onFileReaderTimeout() for (decltype(nblocks) i = 0; i < nblocks; ++i) { auto& guiblock = EASY_GLOBALS.gui_blocks[i]; guiblock.tree = ::std::move(blocks[i]); +#ifdef EASY_TREE_WIDGET__USE_VECTOR ::profiler_gui::set_max(guiblock.tree_item); +#endif } static_cast(m_graphicsView->widget())->view()->setTree(EASY_GLOBALS.profiler_blocks); diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 040e1e2..89c7bee 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -238,8 +238,6 @@ protected slots: void onUnitsChanged(bool); void onEventIndicatorsChange(bool); void onEnableDisableStatistics(bool); - void onDrawBordersChanged(bool); - void onHideNarrowChildrenChanged(bool); void onCollapseItemsAfterCloseChanged(bool); void onAllItemsExpandedByDefaultChange(bool); void onBindExpandStatusChange(bool); diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index 73cd0a1..390b417 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -399,8 +399,10 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI item->setBackgroundColor(color); item->setTextColor(fgColor); +#ifdef EASY_TREE_WIDGET__USE_VECTOR auto item_index = static_cast(_items.size()); _items.push_back(item); +#endif size_t children_items_number = 0; ::profiler::timestamp_t children_duration = 0; @@ -425,7 +427,9 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI 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); @@ -433,10 +437,15 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI if (gui_block.expanded) item->setExpanded(true); +#ifndef EASY_TREE_WIDGET__USE_VECTOR + _items.insert(::std::make_pair(block.tree, item)); +#endif } else { +#ifdef EASY_TREE_WIDGET__USE_VECTOR _items.pop_back(); +#endif delete item; } @@ -612,8 +621,10 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: item->setBackgroundColor(color); item->setTextColor(fgColor); +#ifdef EASY_TREE_WIDGET__USE_VECTOR auto item_index = static_cast(_items.size()); _items.push_back(item); +#endif size_t children_items_number = 0; ::profiler::timestamp_t children_duration = 0; @@ -638,17 +649,25 @@ size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const :: 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 + _items.insert(::std::make_pair(child_index, item)); +#endif } else { +#ifdef EASY_TREE_WIDGET__USE_VECTOR _items.pop_back(); +#endif delete item; } } diff --git a/profiler_gui/tree_widget_loader.h b/profiler_gui/tree_widget_loader.h index c5b9e7d..1407295 100644 --- a/profiler_gui/tree_widget_loader.h +++ b/profiler_gui/tree_widget_loader.h @@ -57,7 +57,13 @@ ////////////////////////////////////////////////////////////////////////// class EasyTreeWidgetItem; + +#ifndef EASY_TREE_WIDGET__USE_VECTOR +typedef ::std::unordered_map<::profiler::block_index_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::block_index_t>::hasher_t> Items; +#else typedef ::std::vector Items; +#endif + 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;