0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 16:11:02 +08:00

Highly optimized painting algorithm and memory consumption for Profiler GraphicsView

This commit is contained in:
Victor Zarubkin 2016-06-30 02:57:57 +03:00
parent 4b287b31fa
commit 5ca4158abf
6 changed files with 541 additions and 193 deletions

View File

@ -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 <QMouseEvent>
#include <QSignalBlocker>
#include <QScrollBar>
#include <math.h>
#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<ProfGraphicsView*>(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<ProfGraphicsView*>(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<ProfGraphicsView*>(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<ProfBlockItem&&>(_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<qreal>(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<ProfGraphicsScene*>(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<ProfGraphicsScene*>(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<ProfGraphicsScene*>(scene())->test(_frames_number, _total_items_number_estimate, _depth);
updateVisibleSceneRect();
}
void ProfGraphicsView::onScrollbarValueChange(int)
{
if (!m_bUpdatingRect)
updateVisibleSceneRect();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -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 <QGraphicsSimpleTextItem>
#include <QPoint>
#include <stdlib.h>
#include <vector>
#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<ProfBlockItem> 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.

View File

@ -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);

View File

@ -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:

View File

@ -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<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent();
auto view = static_cast<ProfGraphicsView*>(m_graphicsView->widget());
view->clearSilent();
m_currentProf.clear();
view->test(18000, 40000000, 5);
//view->test(3, 300, 4);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

View File

@ -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.