diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index a53789b..0b0e4dc 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "blocks_graphics_view.h" @@ -48,8 +49,9 @@ const qreal MAX_SCALE = pow(SCALING_COEFFICIENT, 30); // ~800 const qreal BASE_SCALE = pow(SCALING_COEFFICIENT_INV, 25); // ~0.003 const unsigned short GRAPHICS_ROW_SIZE = 16; -const unsigned short GRAPHICS_ROW_SIZE_FULL = GRAPHICS_ROW_SIZE + 2; -const unsigned short ROW_SPACING = 4; +const unsigned short GRAPHICS_ROW_SPACING = 2; +const unsigned short GRAPHICS_ROW_SIZE_FULL = GRAPHICS_ROW_SIZE + GRAPHICS_ROW_SPACING; +const unsigned short THREADS_ROW_SPACING = 4; const QRgb BORDERS_COLOR = 0x00a07050; const QRgb BACKGROUND_1 = 0x00dddddd; @@ -79,15 +81,11 @@ inline T logn(T _value) ////////////////////////////////////////////////////////////////////////// -ProfGraphicsItem::ProfGraphicsItem() : ProfGraphicsItem(false) +ProfGraphicsItem::ProfGraphicsItem(unsigned char _index, bool _test) : QGraphicsItem(nullptr), m_bTest(_test), m_pRoot(nullptr), m_index(_index) { } -ProfGraphicsItem::ProfGraphicsItem(bool _test) : QGraphicsItem(nullptr), m_bTest(_test), m_pRoot(nullptr) -{ -} - -ProfGraphicsItem::ProfGraphicsItem(const ::profiler::BlocksTreeRoot* _root) : ProfGraphicsItem(false) +ProfGraphicsItem::ProfGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root) : ProfGraphicsItem(_index, false) { m_pRoot = _root; } @@ -138,8 +136,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // Reset indices of first visible item for each layer const auto levelsNumber = levels(); - for (unsigned short i = 1; i < levelsNumber; ++i) - m_levelsIndexes[i] = -1; + for (unsigned char i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]); // Search for first visible top-level item @@ -185,23 +182,25 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // Iterate through layers and draw visible items bool selectedItemsWasPainted = false; - for (unsigned short l = 0; l < levelsNumber; ++l) + for (unsigned char l = 0; l < levelsNumber; ++l) { auto& level = m_levels[l]; - const auto next_level = l + 1; + const short next_level = l + 1; char state = 1; //bool changebrush = false; + const auto top = levelY(l); for (unsigned int i = m_levelsIndexes[l], end = static_cast(level.size()); i < end; ++i) { auto& item = level[i]; + static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(item.children_begin); if (item.state != 0) { state = item.state; } - if (item.right() < sceneLeft || state == -1 || (l == 0 && (item.top() > visibleSceneRect.bottom() || (item.top() + item.totalHeight) < visibleSceneRect.top()))) + if (item.right() < sceneLeft || state == -1 || (l == 0 && (top > visibleSceneRect.bottom() || (top + item.totalHeight) < visibleSceneRect.top()))) { // This item is not visible ++m_levelsIndexes[l]; @@ -275,7 +274,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } // Draw rectangle - rect.setRect(x, item.top(), w, item.totalHeight); + rect.setRect(x, top, w, item.totalHeight); _painter->drawRect(rect); if (changepen) @@ -286,7 +285,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(BORDERS_COLOR); // restore pen for rectangle painting } - if (next_level < levelsNumber && item.children_begin != NEGATIVE_ONE) + if (next_level < levelsNumber && item.children_begin != MAX_CHILD_INDEX) { // Mark that we would not paint children of current item m_levels[next_level][item.children_begin].state = -1; @@ -295,9 +294,9 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* continue; } - if (next_level < levelsNumber && item.children_begin != NEGATIVE_ONE) + if (next_level < levelsNumber && item.children_begin != MAX_CHILD_INDEX) { - if (m_levelsIndexes[next_level] == NEGATIVE_ONE) + if (m_levelsIndexes[next_level] == MAX_CHILD_INDEX) { // Mark first potentially visible child item on next sublevel m_levelsIndexes[next_level] = item.children_begin; @@ -353,7 +352,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* // Draw rectangle const auto x = item.left() * currentScale - dx; - rect.setRect(x, item.top(), w, item.height()); + rect.setRect(x, top, w, GRAPHICS_ROW_SIZE); _painter->drawRect(rect); // Draw text----------------------------------- @@ -367,7 +366,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* xtext = sceneLeft * currentScale - dx; } - rect.setRect(xtext + 1, item.top(), w - 1, item.height()); + rect.setRect(xtext + 1, top, w - 1, GRAPHICS_ROW_SIZE); // text will be painted with inverse color auto textColor = 0x00ffffff - previousColor; @@ -399,7 +398,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* if (!selectedItemsWasPainted && !m_bTest && ::profiler_gui::EASY_GLOBALS.selected_block < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) { const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[::profiler_gui::EASY_GLOBALS.selected_block]; - if (guiblock.graphics_item == this) + if (guiblock.graphics_item == m_index) { const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index]; if (item.left() < sceneRight && item.right() > sceneLeft) @@ -412,7 +411,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* brush.setColor(previousColor); _painter->setBrush(brush); - rect.setRect(item.left() * currentScale - dx, item.top(), ::std::max(item.width() * currentScale, 1.0), item.totalHeight); + rect.setRect(item.left() * currentScale - dx, levelY(guiblock.graphics_item_level), ::std::max(item.width() * currentScale, 1.0), item.totalHeight); _painter->drawRect(rect); } } @@ -486,7 +485,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& } const auto& level0 = m_levels.front(); - const auto top = level0.front().top(); + const auto top = y(); if (top > _pos.y()) { @@ -507,7 +506,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& const auto currentScale = view()->scale(); unsigned int i = 0; - size_t itemIndex = -1; + size_t itemIndex = ::std::numeric_limits::max(); size_t firstItem = 0, lastItem = static_cast(level0.size()); while (i <= levelIndex) { @@ -533,6 +532,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& for (auto size = level.size(); itemIndex < size; ++itemIndex) { const auto& item = level[itemIndex]; + static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(item.children_begin); if (item.left() > _pos.x()) { @@ -550,7 +550,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& return &item; } - if (item.children_begin == NEGATIVE_ONE) + if (item.children_begin == MAX_CHILD_INDEX) { if (itemIndex != 0) { @@ -560,7 +560,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& --j; const auto& item2 = level[j]; - if (item2.children_begin != NEGATIVE_ONE) + if (item2.children_begin != MAX_CHILD_INDEX) { firstItem = item2.children_begin; break; @@ -582,7 +582,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& for (auto j = itemIndex + 1; j < size; ++j) { const auto& item2 = level[j]; - if (item2.children_begin != NEGATIVE_ONE) + if (item2.children_begin != MAX_CHILD_INDEX) { lastItem = item2.children_begin; break; @@ -619,40 +619,48 @@ void ProfGraphicsItem::setBoundingRect(const QRectF& _rect) ////////////////////////////////////////////////////////////////////////// -unsigned short ProfGraphicsItem::levels() const +unsigned char ProfGraphicsItem::levels() const { - return static_cast(m_levels.size()); + return static_cast(m_levels.size()); } -void ProfGraphicsItem::setLevels(unsigned short _levels) +float ProfGraphicsItem::levelY(unsigned char _level) const { + return y() + static_cast(_level) * static_cast(GRAPHICS_ROW_SIZE_FULL); +} + +void ProfGraphicsItem::setLevels(unsigned char _levels) +{ + typedef decltype(m_levelsIndexes) IndexesT; + static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(); + m_levels.resize(_levels); - m_levelsIndexes.resize(_levels, -1); + m_levelsIndexes.resize(_levels, MAX_CHILD_INDEX); } -void ProfGraphicsItem::reserve(unsigned short _level, unsigned int _items) +void ProfGraphicsItem::reserve(unsigned char _level, unsigned int _items) { m_levels[_level].reserve(_items); } ////////////////////////////////////////////////////////////////////////// -const ProfGraphicsItem::Children& ProfGraphicsItem::items(unsigned short _level) const +const ProfGraphicsItem::Children& ProfGraphicsItem::items(unsigned char _level) const { return m_levels[_level]; } -const ::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned short _level, unsigned int _index) const +const ::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned char _level, unsigned int _index) const { return m_levels[_level][_index]; } -::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned short _level, unsigned int _index) +::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned char _level, unsigned int _index) { return m_levels[_level][_index]; } -unsigned int ProfGraphicsItem::addItem(unsigned short _level) +unsigned int ProfGraphicsItem::addItem(unsigned char _level) { m_levels[_level].emplace_back(); return static_cast(m_levels[_level].size() - 1); @@ -875,7 +883,7 @@ void ProfBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte const auto& items = sceneView->getItems(); if (!items.empty()) { - static const auto OVERLAP = ROW_SPACING >> 1; + static const auto OVERLAP = THREADS_ROW_SPACING >> 1; static const QBrush brushes[2] = {QColor::fromRgb(BACKGROUND_1), QColor::fromRgb(BACKGROUND_2)}; const bool isTest = (items.front()->items(0).front().block == nullptr); int i = -1; @@ -961,7 +969,7 @@ void ProfTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap ProfGraphicsView::ProfGraphicsView(QWidget* _parent) : QGraphicsView(_parent) - , m_beginTime(-1) + , m_beginTime(::std::numeric_limits::max()) , m_scale(1) , m_offset(0) , m_mouseButtons(Qt::NoButton) @@ -999,7 +1007,7 @@ ProfChronometerItem* ProfGraphicsView::createChronometer(bool _main) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, unsigned int _childrenNumber, unsigned int& _total_items) +void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, unsigned int _childrenNumber, unsigned int& _total_items) { unsigned int nchildren = _childrenNumber; _childrenNumber = TEST_PROGRESSION_BASE; @@ -1016,17 +1024,17 @@ void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxl const auto& children = _item->items(_level + 1); b.children_begin = static_cast(children.size()); - fillTestChildren(_item, _maxlevel, _level + 1, _x, _y + GRAPHICS_ROW_SIZE_FULL, _childrenNumber, _total_items); + fillTestChildren(_item, _maxlevel, _level + 1, _x, _childrenNumber, _total_items); const auto& last = children.back(); - b.setRect(_x, _y, last.right() - _x, GRAPHICS_ROW_SIZE); + b.setPos(_x, last.right() - _x); b.totalHeight = GRAPHICS_ROW_SIZE_FULL + last.totalHeight; } else { - b.setRect(_x, _y, units2microseconds(10 + rand() % 190), GRAPHICS_ROW_SIZE); + b.setPos(_x, units2microseconds(10 + rand() % 190)); b.totalHeight = GRAPHICS_ROW_SIZE; - b.children_begin = -1; + ::profiler_gui::set_max(b.children_begin); } _x = b.right(); @@ -1034,7 +1042,7 @@ void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxl } } -void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, int _rows) +void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows) { static const qreal X_BEGIN = 50; static const qreal Y_BEGIN = 0; @@ -1042,9 +1050,9 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite clearSilent(); // Clear scene // Calculate items number for first level - _rows = ::std::max(1, _rows); + _rows = ::std::max((unsigned char)1, _rows); const auto children_per_frame = static_cast(0.5 + static_cast(_total_items_number_estimate) / static_cast(_rows * _frames_number)); - const int max_depth = logn(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1); + const unsigned char max_depth = ::std::min(254, static_cast(logn(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1))); const auto first_level_children_count = static_cast(static_cast(children_per_frame) * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5); @@ -1053,12 +1061,12 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite ::std::vector thread_items(_rows); - for (int i = 0; i < _rows; ++i) + for (unsigned char i = 0; i < _rows; ++i) { - auto item = new ProfGraphicsItem(true); + auto item = new ProfGraphicsItem(i, true); thread_items[i] = item; - item->setPos(0, Y_BEGIN + i * (max_depth * GRAPHICS_ROW_SIZE_FULL + ROW_SPACING * 5)); + item->setPos(0, Y_BEGIN + i * (max_depth * GRAPHICS_ROW_SIZE_FULL + THREADS_ROW_SPACING * 5)); item->setLevels(max_depth + 1); item->reserve(0, _frames_number); @@ -1066,11 +1074,11 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite // Calculate items number for each sublevel auto chldrn = first_level_children_count; - for (int i = 1; i <= max_depth; ++i) + for (unsigned char i = 1; i <= max_depth; ++i) { - for (int i = 0; i < _rows; ++i) + for (unsigned char j = 0; j < _rows; ++j) { - auto item = thread_items[i]; + auto item = thread_items[j]; item->reserve(i, chldrn * _frames_number); } @@ -1081,11 +1089,11 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite unsigned int total_items = 0; qreal maxX = 0; const ProfGraphicsItem* longestItem = nullptr; - for (int i = 0; i < _rows; ++i) + for (unsigned char i = 0; i < _rows; ++i) { auto item = thread_items[i]; qreal x = X_BEGIN, y = item->y(); - for (unsigned int i = 0; i < _frames_number; ++i) + for (unsigned int f = 0; f < _frames_number; ++f) { auto j = item->addItem(0); auto& b = item->getItem(0, j); @@ -1095,10 +1103,10 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite const auto& children = item->items(1); b.children_begin = static_cast(children.size()); - fillTestChildren(item, max_depth, 1, x, y + GRAPHICS_ROW_SIZE_FULL, first_level_children_count, total_items); + fillTestChildren(item, max_depth, 1, x, first_level_children_count, total_items); const auto& last = children.back(); - b.setRect(x, y, last.right() - x, GRAPHICS_ROW_SIZE); + b.setPos(x, last.right() - x); b.totalHeight = GRAPHICS_ROW_SIZE_FULL + last.totalHeight; x += b.width() * 1.2; @@ -1170,7 +1178,7 @@ void ProfGraphicsView::clearSilent() m_items.clear(); m_selectedBlocks.clear(); - m_beginTime = -1; // reset begin time + m_beginTime = ::std::numeric_limits::max(); // reset begin time m_scale = 1; // scale back to initial 100% scale m_timelineStep = 1; m_offset = 0; // scroll back to the beginning of the scene @@ -1229,7 +1237,7 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // fill scene with new items const auto& tree = threadTree.second.tree; qreal h = 0, x = time2position(tree.children.front().node->block()->getBegin()); - auto item = new ProfGraphicsItem(&threadTree.second); + auto item = new ProfGraphicsItem(static_cast(m_items.size()), &threadTree.second); item->setLevels(tree.depth); item->setPos(0, y); @@ -1239,12 +1247,18 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr m_items.push_back(item); scene()->addItem(item); - y += h + ROW_SPACING; + y += h + THREADS_ROW_SPACING; if (longestTree == &tree) { longestItem = item; } + + if (m_items.size() == 0xff) + { + qWarning() << "Maximum threads number (255 threads) exceeded! See ProfGraphicsView::setTree() : " << __LINE__ << " in file " << __FILE__; + break; + } } // Calculating scene rect @@ -1286,7 +1300,7 @@ const ProfGraphicsView::Items &ProfGraphicsView::getItems() const return m_items; } -qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, unsigned short _level) +qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level) { static const qreal MIN_DURATION = 0.25; @@ -1295,9 +1309,11 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block return 0; } - _item->reserve(_level, static_cast(_children.size())); + const auto level = static_cast(_level); + _item->reserve(level, static_cast(_children.size())); - const auto next_level = _level + 1; + const short next_level = _level + 1; + bool warned = false; qreal total_duration = 0, prev_end = 0, maxh = 0; qreal start_time = -1; for (const auto& child : _children) @@ -1322,25 +1338,36 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block duration = MIN_DURATION; } - auto i = _item->addItem(_level); - auto& b = _item->getItem(_level, i); + auto i = _item->addItem(level); + auto& b = _item->getItem(level, i); auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index]; - gui_block.graphics_item = _item; - gui_block.graphics_item_level = _level; + gui_block.graphics_item = _item->index(); + gui_block.graphics_item_level = level; gui_block.graphics_item_index = i; - if (next_level < _item->levels() && !child.children.empty()) + if (next_level < 256 && next_level < _item->levels() && !child.children.empty()) { - b.children_begin = static_cast(_item->items(next_level).size()); + b.children_begin = static_cast(_item->items(static_cast(next_level)).size()); } else { - b.children_begin = -1; + ::profiler_gui::set_max(b.children_begin); } qreal h = 0; - const auto children_duration = setTree(_item, child.children, h, _y + GRAPHICS_ROW_SIZE_FULL, next_level); + qreal children_duration = 0; + + if (next_level < 256) + { + children_duration = setTree(_item, child.children, h, _y + GRAPHICS_ROW_SIZE_FULL, next_level); + } + else if (!child.children.empty() && !warned) + { + warned = true; + qWarning() << "Maximum blocks depth (255) exceeded! See ProfGraphicsView::setTree() : " << __LINE__ << " in file " << __FILE__; + } + if (duration < children_duration) { duration = children_duration; @@ -1354,7 +1381,7 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block const auto color = child.node->block()->getColor(); b.block = &child; b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - b.setRect(xbegin, _y, duration, GRAPHICS_ROW_SIZE); + b.setPos(xbegin, duration); b.totalHeight = GRAPHICS_ROW_SIZE + h; prev_end = xbegin + duration; @@ -1411,7 +1438,7 @@ void ProfGraphicsView::updateTimelineStep(qreal _windowWidth) m_timelineStep = 1e6; auto steps = time / m_timelineStep; - while (steps > 50) { + while (steps > 60) { m_timelineStep *= 10; steps *= 0.1; } @@ -1877,12 +1904,13 @@ void ProfGraphicsView::onSelectedBlockChange(unsigned int _block_index) // Scroll to item const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index]; - const auto& item = guiblock.graphics_item->items(guiblock.graphics_item_level)[guiblock.graphics_item_index]; + const auto thread_item = m_items[guiblock.graphics_item]; + const auto& item = thread_item->items(guiblock.graphics_item_level)[guiblock.graphics_item_index]; m_flickerSpeedX = m_flickerSpeedY = 0; m_bUpdatingRect = true; - verticalScrollBar()->setValue(static_cast(item.top() - m_visibleSceneRect.height() * 0.5)); + verticalScrollBar()->setValue(static_cast(thread_item->levelY(guiblock.graphics_item_level) - m_visibleSceneRect.height() * 0.5)); m_pScrollbar->setValue(item.left() + item.width() * 0.5 - m_pScrollbar->sliderHalfWidth()); m_bUpdatingRect = false; } diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 8666bbe..d36d0b2 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -70,12 +70,12 @@ class ProfGraphicsItem : public QGraphicsItem QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem) const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy. const bool m_bTest; ///< If true then we are running test() + unsigned char m_index; ///< This item's index in the list of items of ProfGraphicsView public: - ProfGraphicsItem(); - ProfGraphicsItem(bool _test); - ProfGraphicsItem(const ::profiler::BlocksTreeRoot* _root); + ProfGraphicsItem(unsigned char _index, bool _test); + ProfGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root); virtual ~ProfGraphicsItem(); // Public virtual methods @@ -96,44 +96,46 @@ public: ::profiler::thread_id_t threadId() const; ///< Returns number of levels - unsigned short levels() const; + unsigned char levels() const; + + float levelY(unsigned char _level) const; /** \brief Sets number of levels. \note Must be set before doing anything else. \param _levels Desired number of levels */ - void setLevels(unsigned short _levels); + void setLevels(unsigned char _levels); /** \brief Reserves memory for desired number of items on specified level. \param _level Index of the level \param _items Desired number of items on this level */ - void reserve(unsigned short _level, unsigned int _items); + void reserve(unsigned char _level, unsigned int _items); /**\brief Returns reference to the array of items of specified level. \param _level Index of the level */ - const Children& items(unsigned short _level) const; + const Children& items(unsigned char _level) const; /**\brief Returns reference to the item with required index on specified level. \param _level Index of the level \param _index Index of required item */ - const ::profiler_gui::ProfBlockItem& getItem(unsigned short _level, unsigned int _index) const; + const ::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index) const; /**\brief Returns reference to the item with required index on specified level. \param _level Index of the level \param _index Index of required item */ - ::profiler_gui::ProfBlockItem& getItem(unsigned short _level, unsigned int _index); + ::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index); /** \brief Adds new item to required level. \param _level Index of the level \retval Index of the new created item */ - unsigned int addItem(unsigned short _level); + unsigned int addItem(unsigned char _level); /** \brief Finds top-level blocks which are intersects with required selection zone. @@ -151,6 +153,16 @@ private: ///< Returns pointer to the ProfGraphicsView widget. const ProfGraphicsView* view() const; +public: + + // Public inline methods + + ///< Returns this item's index in the list of graphics items of ProfGraphicsView + inline unsigned char index() const + { + return m_index; + } + }; // END of class ProfGraphicsItem. ////////////////////////////////////////////////////////////////////////// @@ -297,7 +309,7 @@ public: void setScrollbar(ProfGraphicsScrollbar* _scrollbar); void clearSilent(); - void test(unsigned int _frames_number, unsigned int _total_items_number_estimate, int _rows); + void test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows); void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree); const Items& getItems() const; @@ -319,8 +331,8 @@ private: void updateTimelineStep(qreal _windowWidth); void updateScene(); void scaleTo(qreal _scale); - qreal setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, unsigned short _level); - void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, unsigned int _childrenNumber, unsigned int& _total_items); + qreal setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level); + void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, unsigned int _childrenNumber, unsigned int& _total_items); private slots: diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index f242b76..5a87bd9 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -244,7 +244,7 @@ void ProfTreeWidgetItem::expandAll() ////////////////////////////////////////////////////////////////////////// -ProfTreeWidget::ProfTreeWidget(QWidget* _parent) : Parent(_parent), m_beginTime(-1), m_bColorRows(true) +ProfTreeWidget::ProfTreeWidget(QWidget* _parent) : Parent(_parent), m_beginTime(::std::numeric_limits::max()), m_bColorRows(true) { setAutoFillBackground(false); setAlternatingRowColors(true); @@ -339,7 +339,7 @@ void ProfTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, :: void ProfTreeWidget::clearSilent(bool _global) { - m_beginTime = -1; + m_beginTime = ::std::numeric_limits::max(); setSortingEnabled(false); disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand); @@ -348,7 +348,7 @@ void ProfTreeWidget::clearSilent(bool _global) { for (auto item : m_items) { - ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item = nullptr; + ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item); } } @@ -602,7 +602,7 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) { total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item; + ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = static_cast(m_items.size() - 1); if (m_bColorRows) { @@ -770,7 +770,7 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t& if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) { total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item; + ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = static_cast(m_items.size() - 1); if (m_bColorRows) { @@ -842,7 +842,7 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) case COL_MAX_PER_PARENT: case COL_MAX_PER_FRAME: { - unsigned int i = NEGATIVE_ONE; + auto i = ::profiler_gui::numeric_max(); switch (col) { case COL_MIN_PER_THREAD: i = item->block()->per_thread_stats->min_duration_block; break; @@ -853,7 +853,7 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) case COL_MAX_PER_FRAME: i = item->block()->per_frame_stats->max_duration_block; break; } - if (i != NEGATIVE_ONE) + if (i != ::profiler_gui::numeric_max(i)) { menu.addSeparator(); itemAction = new ProfItemAction("Jump to such item", i); @@ -973,17 +973,18 @@ void ProfTreeWidget::onSelectedThreadChange(::profiler::thread_id_t _id) void ProfTreeWidget::onSelectedBlockChange(unsigned int _block_index) { + ProfTreeWidgetItem* item = nullptr; + if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) { - auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index].tree_item; - if (item != nullptr) - scrollToItem(item, QAbstractItemView::PositionAtCenter); - setCurrentItem(item); - } - else - { - setCurrentItem(nullptr); + const auto i = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index].tree_item; + if (i < m_items.size()) + item = m_items[i]; } + + if (item != nullptr) + scrollToItem(item, QAbstractItemView::PositionAtCenter); + setCurrentItem(item); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index 8164f68..0720124 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -110,26 +110,20 @@ struct ProfBlockItem final const ::profiler::BlocksTree* block; ///< Pointer to profiler block 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 - float y; ///< y coordinate of the item - float h; ///< Height of the item QRgb color; ///< Background color of the item unsigned int children_begin; ///< Index of first child item on the next sublevel unsigned short totalHeight; ///< Total height of the item including heights of all it's children char state; ///< 0 = no change, 1 = paint, -1 = do not paint - inline void setRect(qreal _x, float _y, float _w, float _h) { - x = _x; - y = _y; - w = _w; - h = _h; - } + // 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; + // 2) We can save 12 bytes per block if "x" and "w" vars will be removed (all this information exist inside BlocksTree), + // but this will make impossible to run graphics test without loading any .prof file. + inline void setPos(qreal _x, float _w) { x = _x; w = _w; } inline qreal left() const { return x; } - inline float top() const { return y; } - inline float width() const { return w; } - inline float height() const { return h; } inline qreal right() const { return x + w; } - inline float bottom() const { return y + h; } + inline float width() const { return w; } }; // END of struct ProfBlockItem. #pragma pack(pop) @@ -191,6 +185,20 @@ inline QString timeStringInt(qreal _interval) ////////////////////////////////////////////////////////////////////////// +template inline T numeric_max() { + return ::std::numeric_limits::max(); +} + +template inline T numeric_max(T) { + return ::std::numeric_limits::max(); +} + +template inline void set_max(T& _value) { + _value = ::std::numeric_limits::max(); +} + +////////////////////////////////////////////////////////////////////////// + } // END of namespace profiler_gui. ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index df7074e..424d0e1 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -31,8 +31,6 @@ class ProfGraphicsItem; class ProfTreeWidgetItem; -const unsigned int NEGATIVE_ONE = std::numeric_limits::max(); - ////////////////////////////////////////////////////////////////////////// namespace profiler_gui { @@ -46,13 +44,15 @@ namespace profiler_gui { ////////////////////////////////////////////////////////////////////////// +#pragma pack(push, 1) struct ProfBlock final { - ProfGraphicsItem* graphics_item; - ProfTreeWidgetItem* tree_item; - unsigned short graphics_item_level; - unsigned int graphics_item_index; + unsigned int tree_item; + unsigned int graphics_item_index; + unsigned char graphics_item_level; + unsigned char graphics_item; }; +#pragma pack(pop) typedef ::std::vector ProfBlocks; diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index d94b24e..8ffdecc 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -154,9 +154,11 @@ void ProfMainWindow::loadFile(const std::string& stdfilename) m_lastFile = stdfilename; ::profiler_gui::EASY_GLOBALS.selected_thread = 0; + ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::ProfBlock) * nblocks); + for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); } @@ -179,10 +181,11 @@ void ProfMainWindow::onReloadFileClicked(bool) static_cast(m_treeWidget->widget())->clearSilent(true); ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::EASY_GLOBALS.selected_block = -1; + ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::ProfBlock) * nblocks); + for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); } @@ -207,10 +210,10 @@ void ProfMainWindow::onTestViewportClicked(bool) ::profiler_gui::EASY_GLOBALS.gui_blocks.clear(); ::profiler_gui::EASY_GLOBALS.profiler_blocks.clear(); ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::EASY_GLOBALS.selected_block = -1; + ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); - view->test(18000, 40000000, 2); - //view->test(3, 300, 1); + //view->test(18000, 40000000, 2); + view->test(100, 9000, 1); } void ProfMainWindow::onEncodingChanged(bool)