diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index 536819d..b9dc6eb 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -11,9 +11,13 @@ * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: Moved sources from graphics_view.h * : and renamed classes from My* to Prof*. +* : * : * 2016/06/27 Victor Zarubkin: Added text shifting relatively to it's parent item. * : Disabled border lines painting because of vertical lines painting bug. * : Changed height of blocks. Variable thread-block height. +* : +* : * 2016/06/29 Victor Zarubkin: Highly optimized painting performance and memory consumption. +* : * : * * ----------------- : * license : TODO: add license text @@ -23,225 +27,458 @@ #include #include #include +#include #include "blocks_graphics_view.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const qreal BASE_TEXT_SHIFT = 5; ///< Text position relatively to parent polygon item -const qreal GRAPHICS_ROW_SIZE = 15; +const qreal GRAPHICS_ROW_SIZE = 16; const qreal GRAPHICS_ROW_SIZE_FULL = GRAPHICS_ROW_SIZE + 1; -const qreal ROW_SPACING = 5; +const qreal ROW_SPACING = 10; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -ProfGraphicsPolygonItem::ProfGraphicsPolygonItem(bool _drawBorders, QGraphicsItem* _parent) - : QGraphicsPolygonItem(_parent) - , m_bDrawBorders(_drawBorders) +ProfGraphicsItem::ProfGraphicsItem() : QGraphicsItem(nullptr), m_bTest(false) { - if (!_drawBorders) +} + +ProfGraphicsItem::ProfGraphicsItem(bool _test) : QGraphicsItem(nullptr), m_bTest(_test) +{ +} + +ProfGraphicsItem::~ProfGraphicsItem() +{ +} + +QRectF ProfGraphicsItem::boundingRect() const +{ + return m_rect; +} + +void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +{ + const auto nitems = m_items.size(); + if (nitems == 0) { - setPen(QPen(Qt::NoPen)); + return; } -} -ProfGraphicsPolygonItem::~ProfGraphicsPolygonItem() -{ -} - -//void ProfGraphicsPolygonItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) -//{ -// if (m_bDrawBorders) -// { -// const auto currentScale = static_cast(scene()->parent())->currentScale(); -//// if (boundingRect().width() * currentScale < 5) -//// { -//// auto linePen = pen(); -//// if (linePen.style() != Qt::NoPen) -//// { -//// linePen.setStyle(Qt::NoPen); -//// setPen(linePen); -//// } -//// } -//// else -//// { -//// auto linePen = pen(); -//// //linePen.setWidthF(1.25 / currentScale); -//// -//// if (linePen.style() != Qt::SolidLine) -//// { -//// linePen.setStyle(Qt::SolidLine); -//// setPen(linePen); -//// } -//// } -// } -// -// QGraphicsPolygonItem::paint(painter, option, widget); -//} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -ProfGraphicsTextItem::ProfGraphicsTextItem(const char* _text, QGraphicsItem* _parent) - : QGraphicsSimpleTextItem(_text, _parent) -{ -} - -ProfGraphicsTextItem::~ProfGraphicsTextItem() -{ -} - -void ProfGraphicsTextItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) -{ - const auto currentScale = static_cast(parentItem()->scene()->parent())->currentScale(); - const auto scaleRevert = 1. / currentScale; - const auto dx = BASE_TEXT_SHIFT * scaleRevert; - if ((boundingRect().width() + dx) < parentItem()->boundingRect().width() * currentScale) + const auto view = static_cast(scene()->parent()); + const auto visibleSceneRect = view->visibleSceneRect(); // Current visible scene rect + const auto sceneLeft = visibleSceneRect.left() - x(), sceneRight = visibleSceneRect.right() - x(); + if (m_rect.left() > sceneRight || m_rect.right() < sceneLeft) { - painter->setTransform(QTransform::fromScale(scaleRevert, 1), true); - //setScale(scaleRevert); - setX(dx); - QGraphicsSimpleTextItem::paint(painter, option, widget); + // this frame is not visible at all + return; } + + const auto currentScale = view->currentScale(); // Current GraphicsView scale + const auto scaleRevert = 1.0 / currentScale; // Multiplier for reverting current GraphicsView scale + const auto screenWidth = m_rect.width() * currentScale; // Screen width of the top block + + QRectF rect; + QBrush brush; + QPen pen = _painter->pen(); + brush.setStyle(Qt::SolidPattern); + + _painter->save(); + + _painter->setPen(Qt::NoPen); + if (screenWidth > 20) + { + // TODO: Test performance for drawText inside one loop with drawRect, but with _painter->save() and restore() + // and drawText in separate loop. + + QRgb previousColor = 0; + for (auto& item : m_items) + { + item.draw = !(item.rect.left() > sceneRight || item.rect.right() < sceneLeft); + if (!item.draw) + { + // this item is fully out of scene visible rect + continue; + } + + if (previousColor != item.color) + { + previousColor = item.color; + brush.setColor(previousColor); + _painter->setBrush(brush); + } + + _painter->drawRect(item.rect); + } + + _painter->setPen(Qt::SolidLine); + //_painter->setBrush(Qt::NoBrush); + _painter->setTransform(QTransform::fromScale(scaleRevert, 1), true); + if (m_bTest) + { + for (auto& item : m_items) + { + if (!item.draw) + continue; + + auto w = item.rect.width() * currentScale; + if (w < 20) + continue; + + rect.setRect(item.rect.left() * currentScale, item.rect.top(), w, item.rect.height()); + + _painter->drawText(rect, 0, "NOT VERY LONG TEST TEXT"); + } + } + else + { + previousColor = 0; + for (auto& item : m_items) + { + if (!item.draw) + continue; + + auto w = item.rect.width() * currentScale; + if (w < 20) + continue; + + rect.setRect(item.rect.left() * currentScale, item.rect.top(), w, item.rect.height()); + + if (previousColor != item.color) + { + previousColor = item.color; + pen.setColor(0x00ffffff - previousColor); + _painter->setPen(pen); + } + + //_painter->drawRect(rect); + _painter->drawText(rect, 0, item.block->node->getBlockName()); + } + } + } + else + { + const auto& item = m_items.front(); + brush.setColor(item.color); + _painter->setBrush(brush); + _painter->drawRect(m_rect); + + //if (screenWidth > 10) + //{ + // _painter->setTransform(QTransform::fromScale(scaleRevert, 1), true); + // //_painter->setBrush(Qt::NoBrush); + // rect.setRect(m_rect.left() * currentScale, m_rect.top(), screenWidth, m_rect.height()); + // if (m_bTest) + // { + // _painter->setPen(Qt::SolidLine); + // _painter->drawText(rect, 0, "NOT VERY LONG TEST TEXT"); + // } + // else + // { + // pen.setColor(0x00ffffff - item.color); + // _painter->setPen(pen); + // //_painter->drawRect(rect); + // _painter->drawText(rect, 0, item.block->node->getBlockName()); + // } + //} + } + + _painter->restore(); +} + +void ProfGraphicsItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h) +{ + m_rect.setRect(x, y, w, h); +} + +void ProfGraphicsItem::setBoundingRect(const QRectF& _rect) +{ + m_rect = _rect; +} + +void ProfGraphicsItem::reserve(unsigned int _items) +{ + m_items.reserve(_items); +} + +const ProfGraphicsItem::Children& ProfGraphicsItem::items() const +{ + return m_items; +} + +const ProfBlockItem& ProfGraphicsItem::getItem(size_t _index) const +{ + return m_items[_index]; +} + +ProfBlockItem& ProfGraphicsItem::getItem(size_t _index) +{ + return m_items[_index]; +} + +size_t ProfGraphicsItem::addItem() +{ + m_items.emplace_back(); + return m_items.size() - 1; +} + +size_t ProfGraphicsItem::addItem(const ProfBlockItem& _item) +{ + m_items.emplace_back(_item); + return m_items.size() - 1; +} + +size_t ProfGraphicsItem::addItem(ProfBlockItem&& _item) +{ + m_items.emplace_back(::std::forward(_item)); + return m_items.size() - 1; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const qreal LEFT = -2500000; -const qreal WIDTH = 5000000; -const int N_ITEMS = 200000; - -ProfGraphicsScene::ProfGraphicsScene(QGraphicsView* _parent, bool _test) : QGraphicsScene(_parent), m_start(-1) +ProfGraphicsScene::ProfGraphicsScene(QGraphicsView* _parent, bool _test) : QGraphicsScene(_parent), m_beginTime(-1) { if (_test) { - setSceneRect(QRectF(LEFT, -200, WIDTH, 220)); - test(); + test(10000, 20000000, 5); } } -ProfGraphicsScene::ProfGraphicsScene(const thread_blocks_tree_t& _blocksTree, QGraphicsView* _parent) : QGraphicsScene(_parent), m_start(-1) +ProfGraphicsScene::ProfGraphicsScene(const thread_blocks_tree_t& _blocksTree, QGraphicsView* _parent) : QGraphicsScene(_parent), m_beginTime(-1) { - setTreeInternal(_blocksTree); + setTree(_blocksTree); } ProfGraphicsScene::~ProfGraphicsScene() { } -void ProfGraphicsScene::test() +void fillChildren(ProfGraphicsItem* _item, qreal _x, qreal _y, size_t _childrenNumber, size_t& _total_items) { - QPolygonF poly(QRectF(-5, -180, 10, 180)); - for (int i = 0; i < N_ITEMS; ++i) + size_t nchildren = _childrenNumber; + _childrenNumber >>= 1; + + for (size_t i = 0; i < nchildren; ++i) { - ProfGraphicsPolygonItem* item = new ProfGraphicsPolygonItem(true); - int h = 50 + rand() % 131; - item->setPolygon(QRectF(-5, -h, 10, h)); - item->setPos(LEFT + i * 10, 0); - item->setBrush(QBrush(QColor(30 + rand() % 225, 30 + rand() % 225, 30 + rand() % 225))); + size_t j = _item->addItem(); + + if (_childrenNumber > 0) + { + fillChildren(_item, _x, _y + 18, _childrenNumber, _total_items); + + auto& last = _item->items().back(); + auto& b = _item->getItem(j); + b.color = ((30 + rand() % 225) << 16) + ((30 + rand() % 225) << 8) + (30 + rand() % 225); + b.rect.setRect(_x, _y, last.rect.right() - _x, 15); + b.totalHeight = last.rect.bottom() - _y; + _x = b.rect.right(); + } + else + { + auto& b = _item->getItem(j); + b.color = ((30 + rand() % 225) << 16) + ((30 + rand() % 225) << 8) + (30 + rand() % 225); + b.rect.setRect(_x, _y, 10 + rand() % 40, 15); + b.totalHeight = 15; + _x = b.rect.right(); + } + + ++_total_items; + } +} + +void ProfGraphicsScene::test(size_t _frames_number, size_t _total_items_number_estimate, int _depth) +{ + const auto children_per_frame = _total_items_number_estimate / _frames_number; + const size_t first_level_children_count = sqrt(pow(2, _depth - 1)) * pow(children_per_frame, 1.0 / double(_depth)) + 0.5; + + size_t total_items = 0; + qreal x = 0, y = 0, h = 0; + for (unsigned int i = 0; i < _frames_number; ++i) + { + auto item = new ProfGraphicsItem(true); + item->setPos(x, 0); + + size_t j = item->addItem(); + fillChildren(item, 0, y + 18, first_level_children_count, total_items); + + auto& last = item->items().back(); + auto& b = item->getItem(j); + b.color = ((30 + rand() % 225) << 16) + ((30 + rand() % 225) << 8) + (30 + rand() % 225); + b.rect.setRect(0, 0, last.rect.right(), 15); + b.totalHeight = last.rect.bottom() - y; + item->setBoundingRect(0, 0, b.rect.width(), b.totalHeight); + x += b.rect.width() + 500; + + if (last.rect.bottom() > h) + { + h = last.rect.bottom(); + } + + item->addItem(b); + ++total_items; + addItem(item); } + + setSceneRect(0, 0, x, h); } void ProfGraphicsScene::clearSilent() { const QSignalBlocker b(this); // block all scene signals (otherwise clear() would be extremely slow!) clear(); // clear would be VERY SLOW if signals would not be blocked! + m_beginTime = -1; } void ProfGraphicsScene::setTree(const thread_blocks_tree_t& _blocksTree) { - // delete all items created for previous session - clearSilent(); - - // fill scene with new items - m_start = -1; - setTreeInternal(_blocksTree); -} - -void ProfGraphicsScene::setTreeInternal(const thread_blocks_tree_t& _blocksTree) -{ - // calculate scene size + // calculate scene size and fill it with items ::profiler::timestamp_t finish = 0; qreal y = ROW_SPACING; for (const auto& threadTree : _blocksTree) { const auto timestart = threadTree.second.children.front().node->block()->getBegin(); const auto timefinish = threadTree.second.children.back().node->block()->getEnd(); - if (m_start > timestart) m_start = timestart; + if (m_beginTime > timestart) m_beginTime = timestart; if (finish < timefinish) finish = timefinish; - unsigned short depth = 0; - setTreeInternal(threadTree.second.children, depth, y, 0); - y += static_cast(depth) * GRAPHICS_ROW_SIZE_FULL + ROW_SPACING; + // fill scene with new items + qreal h = 0; + setTreeInternal(threadTree.second.children, h, y); + y += h + ROW_SPACING; } const qreal endX = time2position(finish + 1000000); - setSceneRect(QRectF(0, 0, endX, y)); + setSceneRect(QRectF(0, 0, endX, y + ROW_SPACING)); } -qreal ProfGraphicsScene::setTreeInternal(const BlocksTree::children_t& _children, unsigned short& _depth, qreal _y, unsigned short _level) +qreal ProfGraphicsScene::setTreeInternal(const BlocksTree::children_t& _children, qreal& _height, qreal _y) { - if (_depth < _level) - { - _depth = _level; - } - - qreal total_duration = 0; + qreal total_duration = 0, prev_end = 0, maxh = 0; for (const auto& child : _children) { - const qreal xbegin = time2position(child.node->block()->getBegin()); + qreal xbegin = time2position(child.node->block()->getBegin()); qreal duration = time2position(child.node->block()->getEnd()) - xbegin; - const bool drawBorders = duration > 1; - if (!drawBorders) + const qreal dt = xbegin - prev_end; + if (dt < 0) { - duration = 1; + duration += dt; + xbegin -= dt; } - ProfGraphicsPolygonItem* item = new ProfGraphicsPolygonItem(drawBorders); + if (duration < 0.1) + { + duration = 0.1; + } + + auto item = new ProfGraphicsItem(); item->setPos(xbegin, _y); - item->setZValue(_level); + item->reserve(child.total_children_number + 1); + auto i = item->addItem(); - const auto color = child.node->block()->getColor(); - const auto itemBrush = QBrush(QColor(profiler::colors::get_red(color), profiler::colors::get_green(color), profiler::colors::get_blue(color))); - item->setBrush(itemBrush); - item->setPen(QPen(Qt::NoPen)); // Don't paint lines! There are display bugs if bounding lines are painted: vertical lines are very thick. - - ProfGraphicsTextItem* text = new ProfGraphicsTextItem(child.node->getBlockName(), item); - text->setPos(BASE_TEXT_SHIFT, 1); - - auto textBrush = text->brush(); - textBrush.setColor(QRgb(0x00ffffff - itemBrush.color().rgb())); - text->setBrush(textBrush); - - const auto children_duration = setTreeInternal(child.children, _depth, _y + GRAPHICS_ROW_SIZE_FULL, _level + 1); + qreal h = 0; + const auto children_duration = setTreeInternal(item, child.children, h, _y + GRAPHICS_ROW_SIZE_FULL); if (duration < children_duration) { duration = children_duration; } - item->setPolygon(QRectF(0, 0, duration, GRAPHICS_ROW_SIZE)); + if (h > maxh) + { + maxh = h; + } + + const auto color = child.node->block()->getColor(); + auto& b = item->getItem(i); + b.block = &child; + b.color = (::profiler::colors::get_red(color) << 16) + (::profiler::colors::get_green(color) << 8) + ::profiler::colors::get_blue(color); + b.rect.setRect(0, 0, duration, GRAPHICS_ROW_SIZE); + b.totalHeight = GRAPHICS_ROW_SIZE + h; + + item->setBoundingRect(0, 0, duration, b.totalHeight); addItem(item); total_duration += duration; + + prev_end = xbegin + duration; } + _height += GRAPHICS_ROW_SIZE + maxh; + + return total_duration; +} + +qreal ProfGraphicsScene::setTreeInternal(ProfGraphicsItem* _item, const BlocksTree::children_t& _children, qreal& _height, qreal _y) +{ + if (_children.empty()) + { + return 0; + } + + qreal total_duration = 0, prev_end = 0, maxh = 0; + for (const auto& child : _children) + { + qreal xbegin = time2position(child.node->block()->getBegin()); + qreal duration = time2position(child.node->block()->getEnd()) - xbegin; + + const qreal dt = xbegin - prev_end; + if (dt < 0) + { + duration += dt; + xbegin -= dt; + } + + if (duration < 0.1) + { + duration = 0.1; + } + + auto i = _item->addItem(); + + qreal h = 0; + const auto children_duration = setTreeInternal(_item, child.children, h, _y + GRAPHICS_ROW_SIZE_FULL); + if (duration < children_duration) + { + duration = children_duration; + } + + if (h > maxh) + { + maxh = h; + } + + const auto color = child.node->block()->getColor(); + auto& b = _item->getItem(i); + b.block = &child; + b.color = (::profiler::colors::get_red(color) << 16) + (::profiler::colors::get_green(color) << 8) + ::profiler::colors::get_blue(color); + b.rect.setRect(xbegin - _item->x(), _y - _item->y(), duration, GRAPHICS_ROW_SIZE); + b.totalHeight = GRAPHICS_ROW_SIZE + h; + + total_duration += duration; + + prev_end = xbegin + duration; + } + + _height += GRAPHICS_ROW_SIZE_FULL + maxh; + return total_duration; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -ProfGraphicsView::ProfGraphicsView(bool _test) : QGraphicsView(), m_scale(1), m_scaleCoeff(1.25), m_mouseButtons(Qt::NoButton) +ProfGraphicsView::ProfGraphicsView(bool _test) : QGraphicsView(), m_scale(1), m_scaleCoeff(1.25), m_mouseButtons(Qt::NoButton), m_bUpdatingRect(false) { initMode(); setScene(new ProfGraphicsScene(this, _test)); centerOn(0, 0); + updateVisibleSceneRect(); } -ProfGraphicsView::ProfGraphicsView(const thread_blocks_tree_t& _blocksTree) : QGraphicsView(), m_scale(1), m_scaleCoeff(1.25), m_mouseButtons(Qt::NoButton) +ProfGraphicsView::ProfGraphicsView(const thread_blocks_tree_t& _blocksTree) : QGraphicsView(), m_scale(1), m_scaleCoeff(1.25), m_mouseButtons(Qt::NoButton), m_bUpdatingRect(false) { initMode(); setScene(new ProfGraphicsScene(_blocksTree, this)); centerOn(0, 0); + updateVisibleSceneRect(); } ProfGraphicsView::~ProfGraphicsView() @@ -260,10 +497,12 @@ void ProfGraphicsView::wheelEvent(QWheelEvent* _event) scaleCoeff = 1. / m_scaleCoeff; } - scale(scaleCoeff, 1);// scaleCoeff); + m_bUpdatingRect = true; // To be sure that updateVisibleSceneRect will not be called by scrollbar change + scale(scaleCoeff, 1); // Scale scene m_scale *= scaleCoeff; + m_bUpdatingRect = false; - scene()->update(); + updateVisibleSceneRect(); // Update scene rect _event->accept(); //QGraphicsView::wheelEvent(_event); @@ -296,7 +535,17 @@ void ProfGraphicsView::mouseMoveEvent(QMouseEvent* _event) const auto pos = _event->globalPos(); const auto delta = pos - m_mousePressPos; m_mousePressPos = pos; - verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); + + auto vbar = verticalScrollBar(); + auto hbar = horizontalScrollBar(); + + m_bUpdatingRect = true; // Block scrollbars from updating scene rect to make it possible to do it only once + vbar->setValue(vbar->value() - delta.y()); hbar->setValue(hbar->value() - delta.x()); + m_bUpdatingRect = false; + // Seems like an ugly stub, but QSignalBlocker is also a bad decision + // because if scrollbar does not emit valueChanged signal then viewport does not move + + updateVisibleSceneRect(); // Update scene visible rect only once } //_event->accept(); @@ -308,29 +557,55 @@ void ProfGraphicsView::initMode() // TODO: find mode with least number of bugs :) // There are always some display bugs... - //setCacheMode(QGraphicsView::CacheBackground); setCacheMode(QGraphicsView::CacheNone); - setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); - setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); - //setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange); + connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange); +} + +void ProfGraphicsView::updateVisibleSceneRect() +{ + m_visibleSceneRect = mapToScene(rect()).boundingRect(); } void ProfGraphicsView::setTree(const thread_blocks_tree_t& _blocksTree) { - // block all signals for faster scene recreation - const QSignalBlocker b(this); - - // scale back to initial 100% scale - scale(1. / m_scale, 1); - m_scale = 1; + // clear scene + clearSilent(); // set new blocks tree static_cast(scene())->setTree(_blocksTree); // center view on the beginning of the scene centerOn(0, 0); + updateVisibleSceneRect(); +} + +void ProfGraphicsView::clearSilent() +{ + // block all signals for faster scene recreation + const QSignalBlocker b(this); + + // clear scene + static_cast(scene())->clearSilent(); + + // scale back to initial 100% scale + scale(1. / m_scale, 1); + m_scale = 1; +} + +void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_estimate, int _depth) +{ + static_cast(scene())->test(_frames_number, _total_items_number_estimate, _depth); + updateVisibleSceneRect(); +} + +void ProfGraphicsView::onScrollbarValueChange(int) +{ + if (!m_bUpdatingRect) + updateVisibleSceneRect(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 190da34..d7e5aa6 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -11,6 +11,9 @@ * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: moved sources from graphics_view.h * : and renamed classes from My* to Prof*. +* : +* : * 2016/06/29 Victor Zarubkin: Highly optimized painting performance and memory consumption. +* : * : * * ----------------- : * license : TODO: add license text @@ -25,35 +28,56 @@ #include #include #include +#include #include "profiler/reader.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -class ProfGraphicsPolygonItem : public QGraphicsPolygonItem +#pragma pack(push, 1) +struct ProfBlockItem { - bool m_bDrawBorders; + QRectF rect; + qreal totalHeight; + const BlocksTree* block; + QRgb color; + bool draw; + + ProfBlockItem() : totalHeight(0), block(nullptr), color(0), draw(true) + { + } +}; +#pragma pack(pop) + +class ProfGraphicsItem : public QGraphicsItem +{ + typedef ::std::vector Children; + Children m_items; + QRectF m_rect; + const bool m_bTest; public: - ProfGraphicsPolygonItem(bool _drawBorders, QGraphicsItem* _parent = nullptr); - virtual ~ProfGraphicsPolygonItem(); + ProfGraphicsItem(); + ProfGraphicsItem(bool _test); + virtual ~ProfGraphicsItem(); - //void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = Q_NULLPTR) override; + QRectF boundingRect() const override; + void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; -}; // END of class ProfGraphicsPolygonItem. + void setBoundingRect(qreal x, qreal y, qreal w, qreal h); + void setBoundingRect(const QRectF& _rect); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void reserve(unsigned int _items); -class ProfGraphicsTextItem : public QGraphicsSimpleTextItem -{ -public: + const Children& items() const; + const ProfBlockItem& getItem(size_t _index) const; + ProfBlockItem& getItem(size_t _index); - ProfGraphicsTextItem(const char* _text, QGraphicsItem* _parent = nullptr); - virtual ~ProfGraphicsTextItem(); + size_t addItem(); + size_t addItem(const ProfBlockItem& _item); + size_t addItem(ProfBlockItem&& _item); - void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = Q_NULLPTR) override; - -}; // END of class ProfGraphicsTextItem. +}; // END of class ProfGraphicsItem. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -65,7 +89,9 @@ class ProfGraphicsScene : public QGraphicsScene private: - profiler::timestamp_t m_start; + typedef ProfGraphicsScene This; + + ::profiler::timestamp_t m_beginTime; public: @@ -75,18 +101,18 @@ public: private: - void test(); + void test(size_t _frames_number, size_t _total_items_number_estimate, int _depth); void clearSilent(); void setTree(const thread_blocks_tree_t& _blocksTree); - void setTreeInternal(const thread_blocks_tree_t& _blocksTree); - qreal setTreeInternal(const BlocksTree::children_t& _children, unsigned short& _depth, qreal _y, unsigned short _level); + qreal setTreeInternal(const BlocksTree::children_t& _children, qreal& _height, qreal _y); + qreal setTreeInternal(ProfGraphicsItem* _item, const BlocksTree::children_t& _children, qreal& _height, qreal _y); inline qreal time2position(const profiler::timestamp_t& _time) const { - return qreal(_time - m_start) * 1e-6; + return qreal(_time - m_beginTime) * 1e-6; } }; // END of class ProfGraphicsScene. @@ -99,10 +125,14 @@ class ProfGraphicsView : public QGraphicsView private: + typedef ProfGraphicsView This; + + QRectF m_visibleSceneRect; qreal m_scale; qreal m_scaleCoeff; QPoint m_mousePressPos; Qt::MouseButtons m_mouseButtons; + bool m_bUpdatingRect; public: @@ -120,9 +150,24 @@ public: return m_scale; } + inline const QRectF& visibleSceneRect() const + { + return m_visibleSceneRect; + } + void setTree(const thread_blocks_tree_t& _blocksTree); + void clearSilent(); + + void test(size_t _frames_number, size_t _total_items_number_estimate, int _depth); + +private: void initMode(); + void updateVisibleSceneRect(); + +private slots: + + void onScrollbarValueChange(int); }; // END of class ProfGraphicsView. diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 0f13eea..84a238a 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -11,10 +11,14 @@ * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: Moved sources from tree_view.h * : and renamed classes from My* to Prof*. +* : * : * 2016/06/27 Victor Zarubkin: Added possibility to colorize rows * : with profiler blocks' colors. * : Also added displaying frame statistics for blocks. * : Disabled sorting by name to save order of threads displayed on graphics view. +* : +* : * 2016/06/29 Victor Zarubkin: Added clearSilent() method. +* : * : * * ----------------- : * license : TODO: add license text @@ -188,7 +192,6 @@ ProfTreeWidget::ProfTreeWidget(const unsigned int _blocksNumber, const thread_bl setTreeInternal(_blocksNumber, _blocksTree); setSortingEnabled(true); - //sortByColumn(COL_NAME, Qt::AscendingOrder); sortByColumn(COL_BEGIN, Qt::AscendingOrder); connect(this, &Parent::itemExpanded, this, &This::onItemExpand); @@ -200,24 +203,28 @@ ProfTreeWidget::~ProfTreeWidget() void ProfTreeWidget::setTree(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree) { + clearSilent(); + + setTreeInternal(_blocksNumber, _blocksTree); + + setSortingEnabled(true); + sortByColumn(COL_BEGIN, Qt::AscendingOrder); + + connect(this, &Parent::itemExpanded, this, &This::onItemExpand); +} + +void ProfTreeWidget::clearSilent() +{ + m_beginTime = -1; + setSortingEnabled(false); disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand); m_items.clear(); m_itemblocks.clear(); - QSignalBlocker b(this); + const QSignalBlocker b(this); clear(); - b.unblock(); - - m_beginTime = -1; - setTreeInternal(_blocksNumber, _blocksTree); - - setSortingEnabled(true); - //sortByColumn(COL_NAME, Qt::AscendingOrder); - sortByColumn(COL_BEGIN, Qt::AscendingOrder); - - connect(this, &Parent::itemExpanded, this, &This::onItemExpand); } void ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree) @@ -233,6 +240,7 @@ void ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const thr } } + const QSignalBlocker b(this); for (const auto& threadTree : _blocksTree) { auto item = new ProfTreeWidgetItem(&threadTree.second); diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index d12d1cd..8f0d9ec 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -11,8 +11,12 @@ * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: moved sources from tree_view.h * : and renamed classes from My* to Prof*. +* : * : * 2016/06/27 Victor Zarubkin: Added possibility to colorize rows * : with profiler blocks' colors. +* : +* : * 2016/06/29 Victor Zarubkin: Added clearSilent() method. +* : * : * * ----------------- : * license : TODO: add license text @@ -166,6 +170,7 @@ public: virtual ~ProfTreeWidget(); void setTree(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree); + void clearSilent(); protected: diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 11c42df..25f69b5 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -9,7 +9,11 @@ * description : The file contains implementation of MainWindow for easy_profiler GUI. * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: Initial commit. +* : * : * 2016/06/27 Victor Zarubkin: Passing blocks number to ProfTreeWidget::setTree(). +* : +* : * 2016/06/29 Victor Zarubkin: Added menu with tests. +* : * : * * ----------------- : * license : TODO: add license text @@ -27,18 +31,6 @@ ////////////////////////////////////////////////////////////////////////// -void graphicsViewDeleterThread(ProfGraphicsView* _widget) -{ - delete _widget; -} - -void treeDeleterThread(ProfTreeWidget* _widget) -{ - delete _widget; -} - -////////////////////////////////////////////////////////////////////////// - ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graphicsView(nullptr) { setObjectName("ProfilerGUI_MainWindow"); @@ -48,7 +40,7 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph setStatusBar(new QStatusBar()); - auto graphicsView = new ProfGraphicsView(); + auto graphicsView = new ProfGraphicsView(false); m_graphicsView = new QDockWidget("Blocks diagram"); m_graphicsView->setMinimumHeight(50); m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas); @@ -64,21 +56,27 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph addDockWidget(Qt::BottomDockWidgetArea, m_treeWidget); auto actionOpen = new QAction("Open", nullptr); - connect(actionOpen, &QAction::triggered, this, &ProfMainWindow::onOpenFileClicked); + connect(actionOpen, &QAction::triggered, this, &This::onOpenFileClicked); auto actionReload = new QAction("Reload", nullptr); - connect(actionReload, &QAction::triggered, this, &ProfMainWindow::onReloadFileClicked); + connect(actionReload, &QAction::triggered, this, &This::onReloadFileClicked); auto actionExit = new QAction("Exit", nullptr); - connect(actionExit, &QAction::triggered, this, &ProfMainWindow::onExitClicked); + connect(actionExit, &QAction::triggered, this, &This::onExitClicked); - auto menuFile = new QMenu("File"); - menuFile->addAction(actionOpen); - menuFile->addAction(actionReload); - menuFile->addSeparator(); - menuFile->addAction(actionExit); + auto actionTestView = new QAction("Test viewport", nullptr); + connect(actionTestView, &QAction::triggered, this, &This::onTestViewportClicked); - menuBar()->addMenu(menuFile); + auto menu = new QMenu("File"); + menu->addAction(actionOpen); + menu->addAction(actionReload); + menu->addSeparator(); + menu->addAction(actionExit); + menuBar()->addMenu(menu); + + menu = new QMenu("Tests"); + menu->addAction(actionTestView); + menuBar()->addMenu(menu); } ProfMainWindow::~ProfMainWindow() @@ -133,6 +131,20 @@ void ProfMainWindow::onExitClicked(bool) ////////////////////////////////////////////////////////////////////////// +void ProfMainWindow::onTestViewportClicked(bool) +{ + static_cast(m_treeWidget->widget())->clearSilent(); + + auto view = static_cast(m_graphicsView->widget()); + view->clearSilent(); + m_currentProf.clear(); + + view->test(18000, 40000000, 5); + //view->test(3, 300, 4); +} + +////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 1214726..249e0e3 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -33,6 +33,8 @@ class ProfMainWindow : public QMainWindow protected: + typedef ProfMainWindow This; + ::std::string m_lastFile; thread_blocks_tree_t m_currentProf; QDockWidget* m_treeWidget; @@ -48,6 +50,7 @@ protected slots: void onOpenFileClicked(bool); void onReloadFileClicked(bool); void onExitClicked(bool); + void onTestViewportClicked(bool); }; // END of class ProfMainWindow.