From 1d66f4f64190fe94ae98363c84dbaceba6924b72 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 26 Jun 2016 18:46:51 +0300 Subject: [PATCH] moved gui sources to .h and .cpp --- profiler_gui/CMakeLists.txt | 14 +- profiler_gui/blocks_graphics_view.cpp | 200 +++++++++++++++ profiler_gui/blocks_graphics_view.h | 119 +++++++++ profiler_gui/blocks_tree_widget.cpp | 231 +++++++++++++++++ profiler_gui/blocks_tree_widget.h | 167 ++++++++++++ profiler_gui/graphics_view.h | 254 ------------------- profiler_gui/main.cpp | 8 +- profiler_gui/tree_view.h | 348 -------------------------- 8 files changed, 734 insertions(+), 607 deletions(-) create mode 100644 profiler_gui/blocks_graphics_view.cpp create mode 100644 profiler_gui/blocks_graphics_view.h create mode 100644 profiler_gui/blocks_tree_widget.cpp create mode 100644 profiler_gui/blocks_tree_widget.h delete mode 100644 profiler_gui/graphics_view.h delete mode 100644 profiler_gui/tree_view.h diff --git a/profiler_gui/CMakeLists.txt b/profiler_gui/CMakeLists.txt index 2a524af..f553091 100644 --- a/profiler_gui/CMakeLists.txt +++ b/profiler_gui/CMakeLists.txt @@ -8,5 +8,17 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5Widgets REQUIRED) -add_executable(${PROJECT_NAME} main.cpp treemodel.h treemodel.cpp treeitem.h treeitem.cpp graphics_view.h tree_view.h)# widgets_view.h) + +add_executable(${PROJECT_NAME} + main.cpp + treemodel.h + treemodel.cpp + treeitem.h + treeitem.cpp + blocks_graphics_view.h + blocks_graphics_view.cpp + blocks_tree_widget.h + blocks_tree_widget.cpp +) + target_link_libraries(${PROJECT_NAME} Qt5::Widgets easy_profiler) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp new file mode 100644 index 0000000..0f18231 --- /dev/null +++ b/profiler_gui/blocks_graphics_view.cpp @@ -0,0 +1,200 @@ + + +#include +#include +#include +#include +#include +#include "blocks_graphics_view.h" + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const GlobalSignals GLOBALS; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +MyPolygon::MyPolygon(QGraphicsItem* _parent) : QGraphicsPolygonItem(_parent) +{ +} + +MyPolygon::~MyPolygon() +{ +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +MyText::MyText(const char* _text, QGraphicsItem* _parent) : QGraphicsSimpleTextItem(_text, _parent), QObject() +{ + connect(&GLOBALS, &GlobalSignals::scaleIncreased, this, &MyText::onScaleIncrease); + connect(&GLOBALS, &GlobalSignals::scaleDecreased, this, &MyText::onScaleDecrease); +} + +MyText::~MyText() +{ +} + +void MyText::onScaleIncrease(qreal _scale) +{ + setScale(100.0 / _scale); + + if (!isVisible()) + { + if (boundingRect().width() * 100.0 < parentItem()->boundingRect().width() * _scale) + { + show(); + } + } +} + +void MyText::onScaleDecrease(qreal _scale) +{ + setScale(100.0 / _scale); + + if (isVisible()) + { + if (boundingRect().width() * 100.0 > parentItem()->boundingRect().width() * _scale) + { + hide(); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const qreal LEFT = -2500000; +const qreal WIDTH = 5000000; +const int N_ITEMS = 200000; + +MyGraphicsScene::MyGraphicsScene(QGraphicsView* _parent) : QGraphicsScene(_parent), m_start(0) +{ + setSceneRect(QRectF(LEFT, -200, WIDTH, 220)); + test(); +} + +MyGraphicsScene::MyGraphicsScene(const thread_blocks_tree_t& _blocksTree, QGraphicsView* _parent) : QGraphicsScene(_parent), m_start(0) +{ + setTree(_blocksTree); +} + +MyGraphicsScene::~MyGraphicsScene() +{ +} + +void MyGraphicsScene::test() +{ + QPolygonF poly(QRectF(-5, -180, 10, 180)); + for (int i = 0; i < N_ITEMS; ++i) + { + MyPolygon* item = new MyPolygon(); + 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))); + addItem(item); + } +} + +void MyGraphicsScene::setTree(const thread_blocks_tree_t& _blocksTree) +{ + m_start = -1; + profiler::timestamp_t finish = 0; + for (const auto& threadTree : _blocksTree) + { + ++items_couinter; + 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 (finish < timefinish) finish = timefinish; + } + + const qreal endX = time2position(finish + 1000000); + setSceneRect(QRectF(0, 0, endX, 110 * _blocksTree.size())); + + qreal y = 0; + for (const auto& threadTree : _blocksTree) + { + setTree(threadTree.second.children, y); + y += 110; + } +} + +void MyGraphicsScene::setTree(const BlocksTree::children_t& _children, qreal _y, int _level) +{ + for (const auto& child : _children) + { + ++items_couinter; + MyPolygon* item = new MyPolygon(); + + const qreal xbegin = time2position(child.node->block()->getBegin()); + const qreal height = 100 - _level * 5; + qreal duration = time2position(child.node->block()->getEnd()) - xbegin; + if (duration < 1) + duration = 1; + + item->setPolygon(QRectF(0, _level * 5, duration, height)); + item->setPos(xbegin, _y); + item->setZValue(_level); + + const auto color = child.node->block()->getColor(); + item->setBrush(QBrush(QColor(profiler::colors::get_red(color), profiler::colors::get_green(color), profiler::colors::get_blue(color)))); + item->setPen(QPen(Qt::NoPen)); // disable borders painting + + addItem(item); + MyText* text = new MyText(child.node->getBlockName(), item); + QRectF textRect = text->boundingRect(); + text->setPos(0, _level * 5); + + QRectF itemRect = item->boundingRect(); + if (textRect.width() > itemRect.width()) + text->hide(); + + setTree(child.children, _y, _level + 1); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +MyGraphicsView::MyGraphicsView() : QGraphicsView(), m_scale(100), m_scaleCoeff(1.25) +{ + initMode(); + setScene(new MyGraphicsScene(this)); + centerOn(0, 0); +} + +MyGraphicsView::MyGraphicsView(const thread_blocks_tree_t& _blocksTree) : QGraphicsView(), m_scale(100), m_scaleCoeff(1.25) +{ + initMode(); + setScene(new MyGraphicsScene(_blocksTree, this)); + centerOn(0, 0); +} + +MyGraphicsView::~MyGraphicsView() +{ +} + +void MyGraphicsView::initMode() +{ + setCacheMode(QGraphicsView::CacheBackground); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); +} + +void MyGraphicsView::wheelEvent(QWheelEvent* _event) +{ + //MyGraphicsScene* myscene = (MyGraphicsScene*)scene(); + if (_event->delta() > 0) + { + scale(m_scaleCoeff, m_scaleCoeff); + m_scale *= m_scaleCoeff; + emit GLOBALS.scaleIncreased(m_scale); + } + else + { + const qreal scaleCoeff = 1.0 / m_scaleCoeff; + scale(scaleCoeff, scaleCoeff); + m_scale *= scaleCoeff; + emit GLOBALS.scaleDecreased(m_scale); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h new file mode 100644 index 0000000..6567669 --- /dev/null +++ b/profiler_gui/blocks_graphics_view.h @@ -0,0 +1,119 @@ + + +#ifndef MY____GRAPHICS___VIEW_H +#define MY____GRAPHICS___VIEW_H + +#include +#include +#include +#include +#include +#include "profiler/reader.h" + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class GlobalSignals : public QObject +{ + Q_OBJECT + +public: + + GlobalSignals() : QObject() {} + virtual ~GlobalSignals() {} + +signals: + + void scaleIncreased(qreal _scale) const; + void scaleDecreased(qreal _scale) const; + +}; // END of class GlobalSignals. + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class MyPolygon : public QGraphicsPolygonItem +{ +public: + + MyPolygon(QGraphicsItem* _parent = nullptr); + virtual ~MyPolygon(); + +}; // END of class MyPolygon. + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class MyText : public QObject, public QGraphicsSimpleTextItem +{ + Q_OBJECT + +public: + + MyText(const char* _text, QGraphicsItem* _parent = nullptr); + virtual ~MyText(); + +private slots: + + void onScaleIncrease(qreal _scale); + + void onScaleDecrease(qreal _scale); + +}; // END of class MyText. + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class MyGraphicsScene : public QGraphicsScene +{ + Q_OBJECT + +private: + + profiler::timestamp_t m_start; + +public: + + int items_couinter = 0; + + MyGraphicsScene(QGraphicsView* _parent); + MyGraphicsScene(const thread_blocks_tree_t& _blocksTree, QGraphicsView* _parent); + virtual ~MyGraphicsScene(); + + void test(); + + void setTree(const thread_blocks_tree_t& _blocksTree); + +private: + + inline qreal time2position(const profiler::timestamp_t& _time) const + { + return qreal(_time - m_start) * 1e-6; + } + + void setTree(const BlocksTree::children_t& _children, qreal _y, int _level = 0); + +}; // END of class MyGraphicsScene. + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class MyGraphicsView : public QGraphicsView +{ + Q_OBJECT + +private: + + qreal m_scale; + qreal m_scaleCoeff; + +public: + + MyGraphicsView(); + MyGraphicsView(const thread_blocks_tree_t& _blocksTree); + virtual ~MyGraphicsView(); + + void initMode(); + + void wheelEvent(QWheelEvent* _event); + +}; // END of class MyGraphicsView. + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // MY____GRAPHICS___VIEW_H diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp new file mode 100644 index 0000000..9d101e0 --- /dev/null +++ b/profiler_gui/blocks_tree_widget.cpp @@ -0,0 +1,231 @@ + + +#include +#include +#include "blocks_tree_widget.h" + +////////////////////////////////////////////////////////////////////////// + +MyTreeItem::MyTreeItem(const BlocksTree* _block, QTreeWidgetItem* _parent) : QTreeWidgetItem(_parent), m_block(_block) +{ +} + +const BlocksTree* MyTreeItem::block() const +{ + return m_block; +} + +void MyTreeItem::setTimeSmart(int _column, const ::profiler::timestamp_t& _time) +{ + setData(_column, Qt::UserRole, _time); + + setToolTip(_column, QString("%1 ns").arg(_time)); + + if (_time < 1e3) + { + setText(_column, QString("%1 ns").arg(_time)); + } + else if (_time < 1e6) + { + setText(_column, QString("%1 us").arg(double(_time) * 1e-3, 0, 'f', 3)); + } + else if (_time < 1e9) + { + setText(_column, QString("%1 ms").arg(double(_time) * 1e-6, 0, 'f', 3)); + } + else + { + setText(_column, QString("%1 s").arg(double(_time) * 1e-9, 0, 'f', 3)); + } +} + +void MyTreeItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time) +{ + setData(_column, Qt::UserRole, _time); + setToolTip(_column, QString("%1 ns").arg(_time)); + setText(_column, QString::number(double(_time) * 1e-6, 'g', 9)); +} + +////////////////////////////////////////////////////////////////////////// + +MyTreeWidget::MyTreeWidget(const thread_blocks_tree_t& _blocksTree, QWidget* _parent) : QTreeWidget(_parent), m_beginTime(-1) +{ + setAlternatingRowColors(true); + setItemsExpandable(true); + setAnimated(true); + setSortingEnabled(false); + setColumnCount(10); + + auto header = new QTreeWidgetItem(); + header->setText(0, "Name"); + header->setText(1, "Duration"); + header->setText(2, "Begin, ms"); + header->setText(3, "End, ms"); + header->setText(4, "Min dur."); + header->setText(5, "Max dur."); + header->setText(6, "Average dur."); + header->setText(7, "N Calls"); + setHeaderItem(header); + + setTreeInternal(_blocksTree); + + setSortingEnabled(true); + sortByColumn(0, Qt::AscendingOrder); + sortByColumn(2, Qt::AscendingOrder); + + connect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); +} + +void MyTreeWidget::setTree(const thread_blocks_tree_t& _blocksTree) +{ + m_itemblocks.clear(); + + clear(); + + disconnect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); + setSortingEnabled(false); + setTreeInternal(_blocksTree); + + setSortingEnabled(true); + sortByColumn(0, Qt::AscendingOrder); + sortByColumn(2, Qt::AscendingOrder); + + connect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); +} + +void MyTreeWidget::setTreeInternal(const thread_blocks_tree_t& _blocksTree) +{ + for (const auto& threadTree : _blocksTree) + { + const auto beginTime = threadTree.second.children.front().node->block()->getBegin(); + if (m_beginTime > beginTime) + { + m_beginTime = beginTime; + } + } + + for (const auto& threadTree : _blocksTree) + { + auto item = new MyTreeItem(&threadTree.second); + item->setText(0, QString("Thread %1").arg(threadTree.first)); + setTreeInternal(threadTree.second.children, item); + addTopLevelItem(item); + } +} + +void MyTreeWidget::setTreeInternal(const BlocksTree::children_t& _children, MyTreeItem* _parent) +{ + for (const auto& child : _children) + { + const auto duration = child.node->block()->duration(); + const auto beginTime = child.node->block()->getBegin() - m_beginTime; + const auto endTime = child.node->block()->getEnd() - m_beginTime; + + auto item = new MyTreeItem(&child, _parent); + item->setText(0, child.node->getBlockName()); + item->setTimeSmart(1, child.node->block()->duration()); + item->setTimeMs(2, child.node->block()->getBegin() - m_beginTime); + item->setTimeMs(3, child.node->block()->getEnd() - m_beginTime); + + if (child.total_statistics) + { + item->setTimeSmart(4, child.total_statistics->min_duration); + item->setTimeSmart(5, child.total_statistics->max_duration); + item->setTimeSmart(6, child.total_statistics->average_duration()); + item->setText(7, QString::number(child.total_statistics->calls_number)); + } + + m_itemblocks[child.node] = item; + + if (!child.children.empty()) + { + setTreeInternal(child.children, item); + } + } +} + +void MyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) +{ + const auto col = currentColumn(); + auto item = static_cast(currentItem()); + + if (item == nullptr || col < 0) + { + return; + } + + QMenu menu; + + auto action = new QAction("Expand all", nullptr); + connect(action, &QAction::triggered, this, &MyTreeWidget::onExpandAllClicked); + menu.addAction(action); + + action = new QAction("Collapse all", nullptr); + connect(action, &QAction::triggered, this, &MyTreeWidget::onCollapseAllClicked); + menu.addAction(action); + + switch (col) + { + case 4: + { + menu.addSeparator(); + auto itemAction = new ItemAction("Jump to such item", item); + connect(itemAction, &ItemAction::clicked, this, &MyTreeWidget::onJumpToMinItemClicked); + menu.addAction(itemAction); + break; + } + + case 5: + { + menu.addSeparator(); + auto itemAction = new ItemAction("Jump to such item", item); + connect(itemAction, &ItemAction::clicked, this, &MyTreeWidget::onJumpToMaxItemClicked); + menu.addAction(itemAction); + break; + } + } + + menu.exec(QCursor::pos()); + + _event->accept(); +} + +void MyTreeWidget::onJumpToMinItemClicked(MyTreeItem* _item) +{ + auto it = m_itemblocks.find(_item->block()->total_statistics->min_duration_block); + if (it != m_itemblocks.end()) + { + scrollToItem(it->second, QAbstractItemView::PositionAtCenter); + setCurrentItem(it->second); + } +} + +void MyTreeWidget::onJumpToMaxItemClicked(MyTreeItem* _item) +{ + auto it = m_itemblocks.find(_item->block()->total_statistics->max_duration_block); + if (it != m_itemblocks.end()) + { + scrollToItem(it->second, QAbstractItemView::PositionAtCenter); + setCurrentItem(it->second); + } +} + +void MyTreeWidget::onCollapseAllClicked(bool) +{ + collapseAll(); +} + +void MyTreeWidget::onExpandAllClicked(bool) +{ + disconnect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); + expandAll(); + resizeColumnToContents(0); + connect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); +} + +void MyTreeWidget::onItemExpand(QTreeWidgetItem*) +{ + resizeColumnToContents(0); +} + +////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h new file mode 100644 index 0000000..090acd7 --- /dev/null +++ b/profiler_gui/blocks_tree_widget.h @@ -0,0 +1,167 @@ + + +#ifndef MY____TREE___VIEW_H +#define MY____TREE___VIEW_H + +#include +#include +#include +#include +#include "profiler/reader.h" + +////////////////////////////////////////////////////////////////////////// + +template +struct no_hasher { + template inline size_t operator () (const T& _data) const { + return (size_t)_data; + } +}; + +#ifdef _WIN64 +template <> struct no_hasher<8> { + template inline size_t operator () (T _data) const { + return (size_t)_data; + } +}; +#endif + +template <> struct no_hasher<4> { + template inline size_t operator () (T _data) const { + return (size_t)_data; + } +}; + +template <> struct no_hasher<2> { + template inline size_t operator () (T _data) const { + return (size_t)_data; + } +}; + +template <> struct no_hasher<1> { + template inline size_t operator () (T _data) const { + return (size_t)_data; + } +}; + +template +struct do_no_hash { + typedef no_hasher hasher_t; +}; + +////////////////////////////////////////////////////////////////////////// + +class MyTreeItem : public QTreeWidgetItem +{ + //Q_OBJECT + + const BlocksTree* m_block; + +public: + + MyTreeItem(const BlocksTree* _block, QTreeWidgetItem* _parent = nullptr); + + const BlocksTree* block() const; + + inline bool operator < (const QTreeWidgetItem& _other) const + { + const auto col = treeWidget()->sortColumn(); + //switch (col) + //{ + // case 1: + // case 2: + // case 3: + if (col > 0 && col < 7) + { +#ifndef _DEBUG + return data(col, Qt::UserRole).toULongLong() < _other.data(col, Qt::UserRole).toULongLong(); +#else + const auto selfdata = data(col, Qt::UserRole).toULongLong(); + const auto otherdata = _other.data(col, Qt::UserRole).toULongLong(); + return selfdata < otherdata; +#endif + } + //} + + return QTreeWidgetItem::operator < (_other); + } + + void setTimeSmart(int _column, const ::profiler::timestamp_t& _time); + + void setTimeMs(int _column, const ::profiler::timestamp_t& _time); + +}; // END of class MyTreeItem. + +////////////////////////////////////////////////////////////////////////// + +class ItemAction : public QAction +{ + Q_OBJECT + +private: + + MyTreeItem* m_item; + +public: + + ItemAction(const char* _label, MyTreeItem* _item) : QAction(_label, nullptr), m_item(_item) + { + connect(this, &QAction::triggered, this, &ItemAction::onToggle); + } + +private: + + void onToggle(bool) + { + emit clicked(m_item); + } + +signals: + + void clicked(MyTreeItem* _item); +}; + +////////////////////////////////////////////////////////////////////////// + +class MyTreeWidget : public QTreeWidget +{ + Q_OBJECT + +protected: + + typedef ::std::unordered_map::hasher_t> BlockItemMap; + + BlockItemMap m_itemblocks; + ::profiler::timestamp_t m_beginTime; + +public: + + MyTreeWidget(const thread_blocks_tree_t& _blocksTree, QWidget* _parent = nullptr); + + void setTree(const thread_blocks_tree_t& _blocksTree); + +protected: + + void setTreeInternal(const thread_blocks_tree_t& _blocksTree); + + void setTreeInternal(const BlocksTree::children_t& _children, MyTreeItem* _parent); + + void contextMenuEvent(QContextMenuEvent* _event); + +private slots: + + void onJumpToMinItemClicked(MyTreeItem* _item); + + void onJumpToMaxItemClicked(MyTreeItem* _item); + + void onCollapseAllClicked(bool); + + void onExpandAllClicked(bool); + + void onItemExpand(QTreeWidgetItem*); + +}; // END of class MyTreeWidget. + +////////////////////////////////////////////////////////////////////////// + +#endif // MY____TREE___VIEW_H diff --git a/profiler_gui/graphics_view.h b/profiler_gui/graphics_view.h deleted file mode 100644 index 52579db..0000000 --- a/profiler_gui/graphics_view.h +++ /dev/null @@ -1,254 +0,0 @@ - - -#ifndef MY____GRAPHICS___VIEW_H -#define MY____GRAPHICS___VIEW_H - -#include -#include -#include -#include -#include -#include -#include "profiler/reader.h" - -class GlobalSignals : public QObject -{ - Q_OBJECT - -public: - - GlobalSignals() : QObject() {} - -signals: - - void scaleIncreased(qreal _scale) const; - void scaleDecreased(qreal _scale) const; - -} const GLOBALS; - -class MyPolygon : public QGraphicsPolygonItem -{ -public: - - MyPolygon(QGraphicsItem* _parent = nullptr) : QGraphicsPolygonItem(_parent) - { - } - - virtual ~MyPolygon() - { - } - -}; - -class MyText : public QObject, public QGraphicsSimpleTextItem -{ - Q_OBJECT - -public: - - MyText(const char* _text, QGraphicsItem* _parent = nullptr) : QGraphicsSimpleTextItem(_text, _parent), QObject() - { - connect(&GLOBALS, &GlobalSignals::scaleIncreased, this, &MyText::onScaleIncrease); - connect(&GLOBALS, &GlobalSignals::scaleDecreased, this, &MyText::onScaleDecrease); - } - -private slots: - - void onScaleIncrease(qreal _scale) - { - setScale(100.0 / _scale); - - if (!isVisible()) - { - QRectF selfRect = boundingRect(); - QRectF parentRect = parentItem()->boundingRect(); - if (selfRect.width() * 100.0 < parentRect.width() * _scale) - show(); - } - } - - void onScaleDecrease(qreal _scale) - { - setScale(100.0 / _scale); - - if (isVisible()) - { - QRectF selfRect = boundingRect(); - QRectF parentRect = parentItem()->boundingRect(); - if (selfRect.width() * 100.0 > parentRect.width() * _scale) - hide(); - } - } - - - -}; - -const qreal LEFT = -2500000; -const qreal WIDTH = 5000000; -const int N_ITEMS = 200000; - -class MyGraphicsScene : public QGraphicsScene -{ - Q_OBJECT - -private: - - profiler::timestamp_t m_start; - -public: - - int items_couinter = 0; - - MyGraphicsScene(QGraphicsView* _parent) : QGraphicsScene(_parent), m_start(0) - { - setSceneRect(QRectF(LEFT, -200, WIDTH, 220)); - test(); - } - - MyGraphicsScene(const thread_blocks_tree_t& _blocksTree, QGraphicsView* _parent) : QGraphicsScene(_parent), m_start(0) - { - setTree(_blocksTree); - } - - virtual ~MyGraphicsScene() - { - } - - void test() - { - QPolygonF poly(QRectF(-5, -180, 10, 180)); - for (int i = 0; i < N_ITEMS; ++i) - { - MyPolygon* item = new MyPolygon(); - 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))); - addItem(item); - } - } - - void setTree(const thread_blocks_tree_t& _blocksTree) - { - m_start = -1; - profiler::timestamp_t finish = 0; - for (const auto& threadTree : _blocksTree) - { - ++items_couinter; - 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 (finish < timefinish) finish = timefinish; - } - - const qreal endX = time2position(finish + 1000000); - setSceneRect(QRectF(0, 0, endX, 110 * _blocksTree.size())); - - qreal y = 0; - for (const auto& threadTree : _blocksTree) - { - setTree(threadTree.second.children, y); - y += 110; - } - } - -private: - - inline qreal time2position(const profiler::timestamp_t& _time) const - { - return qreal(_time - m_start) * 1e-6; - } - - void setTree(const BlocksTree::children_t& _children, qreal _y, int _level = 0) - { - for (const auto& child : _children) - { - ++items_couinter; - MyPolygon* item = new MyPolygon(); - - const qreal xbegin = time2position(child.node->block()->getBegin()); - const qreal height = 100 - _level * 5; - qreal duration = time2position(child.node->block()->getEnd()) - xbegin; - if (duration < 1) - duration = 1; - - item->setPolygon(QRectF(0, _level * 5, duration, height)); - item->setPos(xbegin, _y); - item->setZValue(_level); - - const auto color = child.node->block()->getColor(); - item->setBrush(QBrush(QColor(profiler::colors::get_red(color), profiler::colors::get_green(color), profiler::colors::get_blue(color)))); - item->setPen(QPen(Qt::NoPen)); // disable borders painting - - addItem(item); - MyText* text = new MyText(child.node->getBlockName(), item); - QRectF textRect = text->boundingRect(); - text->setPos(0, _level * 5); - - QRectF itemRect = item->boundingRect(); - if (textRect.width() > itemRect.width()) - text->hide(); - - setTree(child.children, _y, _level + 1); - } - } -}; - - -class MyGraphicsView : public QGraphicsView -{ - Q_OBJECT - -private: - - qreal m_scale; - qreal m_scaleCoeff; - -public: - - MyGraphicsView() : QGraphicsView(), m_scale(100), m_scaleCoeff(1.25) - { - initMode(); - setScene(new MyGraphicsScene(this)); - centerOn(0, 0); - } - - MyGraphicsView(const thread_blocks_tree_t& _blocksTree) : QGraphicsView(), m_scale(100), m_scaleCoeff(1.25) - { - initMode(); - setScene(new MyGraphicsScene(_blocksTree, this)); - centerOn(0, 0); - } - - void initMode() - { - setCacheMode(QGraphicsView::CacheBackground); - setTransformationAnchor(QGraphicsView::AnchorUnderMouse); - setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); - } - - virtual ~MyGraphicsView() - { - } - - void wheelEvent(QWheelEvent* event) - { - //MyGraphicsScene* myscene = (MyGraphicsScene*)scene(); - if (event->delta() > 0) - { - scale(m_scaleCoeff, m_scaleCoeff); - m_scale *= m_scaleCoeff; - emit GLOBALS.scaleIncreased(m_scale); - } - else - { - const qreal scaleCoeff = 1.0 / m_scaleCoeff; - scale(scaleCoeff, scaleCoeff); - m_scale *= scaleCoeff; - emit GLOBALS.scaleDecreased(m_scale); - } - } -}; - -#endif // MY____GRAPHICS___VIEW_H diff --git a/profiler_gui/main.cpp b/profiler_gui/main.cpp index 2e1af4e..298f486 100644 --- a/profiler_gui/main.cpp +++ b/profiler_gui/main.cpp @@ -2,8 +2,8 @@ #include #include #include "treemodel.h" -#include "graphics_view.h" -#include "tree_view.h" +#include "blocks_graphics_view.h" +#include "blocks_tree_widget.h" #include "profiler/reader.h" int main(int argc, char **argv) @@ -53,7 +53,7 @@ int main(int argc, char **argv) } thread_blocks_tree_t threaded_trees; - int blocks_counter = fillTreesFromFile("../test.prof", threaded_trees, true); + int blocks_counter = fillTreesFromFile("test.prof", threaded_trees, true); MyGraphicsView gview(threaded_trees); gview.show(); @@ -64,7 +64,7 @@ int main(int argc, char **argv) case 1: { thread_blocks_tree_t threaded_trees; - int blocks_counter = fillTreesFromFile("../test.prof", threaded_trees, true); + int blocks_counter = fillTreesFromFile("test.prof", threaded_trees, true); MyTreeWidget view(threaded_trees); view.show(); diff --git a/profiler_gui/tree_view.h b/profiler_gui/tree_view.h deleted file mode 100644 index da9611d..0000000 --- a/profiler_gui/tree_view.h +++ /dev/null @@ -1,348 +0,0 @@ - - -#ifndef MY____TREE___VIEW_H -#define MY____TREE___VIEW_H - -#include -#include -#include -#include -#include -#include "profiler/reader.h" - -////////////////////////////////////////////////////////////////////////// - -template -struct no_hasher { - template inline size_t operator () (const T& _data) const { - return (size_t)_data; - } -}; - -#ifdef _WIN64 -template <> struct no_hasher<8> { - template inline size_t operator () (T _data) const { - return (size_t)_data; - } -}; -#endif - -template <> struct no_hasher<4> { - template inline size_t operator () (T _data) const { - return (size_t)_data; - } -}; - -template <> struct no_hasher<2> { - template inline size_t operator () (T _data) const { - return (size_t)_data; - } -}; - -template <> struct no_hasher<1> { - template inline size_t operator () (T _data) const { - return (size_t)_data; - } -}; - -template -struct do_no_hash { - typedef no_hasher hasher_t; -}; - -////////////////////////////////////////////////////////////////////////// - -class MyTreeItem : public QTreeWidgetItem -{ - //Q_OBJECT - - const BlocksTree* m_block; - -public: - - MyTreeItem(const BlocksTree* _block, QTreeWidgetItem* _parent = nullptr) : QTreeWidgetItem(_parent), m_block(_block) - { - } - - const BlocksTree* block() const - { - return m_block; - } - - inline bool operator < (const QTreeWidgetItem& _other) const - { - const auto col = treeWidget()->sortColumn(); - //switch (col) - //{ - // case 1: - // case 2: - // case 3: - if (col > 0 && col < 7) - { -#ifndef _DEBUG - return data(col, Qt::UserRole).toULongLong() < _other.data(col, Qt::UserRole).toULongLong(); -#else - const auto selfdata = data(col, Qt::UserRole).toULongLong(); - const auto otherdata = _other.data(col, Qt::UserRole).toULongLong(); - return selfdata < otherdata; -#endif - } - //} - - return QTreeWidgetItem::operator < (_other); - } - - void setTimeSmart(int _column, const ::profiler::timestamp_t& _time) - { - setData(_column, Qt::UserRole, _time); - - setToolTip(_column, QString("%1 ns").arg(_time)); - - if (_time < 1e3) - { - setText(_column, QString("%1 ns").arg(_time)); - } - else if (_time < 1e6) - { - setText(_column, QString("%1 us").arg(double(_time) * 1e-3, 0, 'f', 3)); - } - else if (_time < 1e9) - { - setText(_column, QString("%1 ms").arg(double(_time) * 1e-6, 0, 'f', 3)); - } - else - { - setText(_column, QString("%1 s").arg(double(_time) * 1e-9, 0, 'f', 3)); - } - } - - void setTimeMs(int _column, const ::profiler::timestamp_t& _time) - { - setData(_column, Qt::UserRole, _time); - setToolTip(_column, QString("%1 ns").arg(_time)); - setText(_column, QString::number(double(_time) * 1e-6, 'g', 9)); - } - -}; - -////////////////////////////////////////////////////////////////////////// - -class ItemAction : public QAction -{ - Q_OBJECT - -private: - - MyTreeItem* m_item; - -public: - - ItemAction(const char* _label, MyTreeItem* _item) : QAction(_label, nullptr), m_item(_item) - { - connect(this, &QAction::triggered, this, &ItemAction::onToggle); - } - -private: - - void onToggle(bool) - { - emit clicked(m_item); - } - -signals: - - void clicked(MyTreeItem* _item); -}; - -////////////////////////////////////////////////////////////////////////// - -class MyTreeWidget : public QTreeWidget -{ - Q_OBJECT - -protected: - - typedef ::std::unordered_map::hasher_t> BlockItemMap; - - BlockItemMap m_itemblocks; - ::profiler::timestamp_t m_beginTime; - -public: - - MyTreeWidget(const thread_blocks_tree_t& _blocksTree, QWidget* _parent = nullptr) : QTreeWidget(_parent), m_beginTime(-1) - { - setAlternatingRowColors(true); - setItemsExpandable(true); - setAnimated(true); - setSortingEnabled(false); - setColumnCount(10); - - auto header = new QTreeWidgetItem(); - header->setText(0, "Name"); - header->setText(1, "Duration"); - header->setText(2, "Begin, ms"); - header->setText(3, "End, ms"); - header->setText(4, "Min dur."); - header->setText(5, "Max dur."); - header->setText(6, "Average dur."); - header->setText(7, "N Calls"); - setHeaderItem(header); - - setTreeInternal(_blocksTree); - - setSortingEnabled(true); - sortByColumn(0, Qt::AscendingOrder); - sortByColumn(2, Qt::AscendingOrder); - - connect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); - } - - void setTree(const thread_blocks_tree_t& _blocksTree) - { - m_itemblocks.clear(); - clear(); - setTreeInternal(_blocksTree); - } - -protected: - - void setTreeInternal(const thread_blocks_tree_t& _blocksTree) - { - for (const auto& threadTree : _blocksTree) - { - const auto beginTime = threadTree.second.children.front().node->block()->getBegin(); - if (m_beginTime > beginTime) - { - m_beginTime = beginTime; - } - } - - for (const auto& threadTree : _blocksTree) - { - auto item = new MyTreeItem(&threadTree.second); - item->setText(0, QString("Thread %1").arg(threadTree.first)); - setTreeInternal(threadTree.second.children, item); - addTopLevelItem(item); - } - } - - void setTreeInternal(const BlocksTree::children_t& _children, MyTreeItem* _parent) - { - for (const auto& child : _children) - { - const auto duration = child.node->block()->duration(); - const auto beginTime = child.node->block()->getBegin() - m_beginTime; - const auto endTime = child.node->block()->getEnd() - m_beginTime; - - auto item = new MyTreeItem(&child, _parent); - item->setText(0, child.node->getBlockName()); - item->setTimeSmart(1, child.node->block()->duration()); - item->setTimeMs(2, child.node->block()->getBegin() - m_beginTime); - item->setTimeMs(3, child.node->block()->getEnd() - m_beginTime); - - if (child.total_statistics) - { - item->setTimeSmart(4, child.total_statistics->min_duration); - item->setTimeSmart(5, child.total_statistics->max_duration); - item->setTimeSmart(6, child.total_statistics->average_duration()); - item->setText(7, QString::number(child.total_statistics->calls_number)); - } - - m_itemblocks[child.node] = item; - - if (!child.children.empty()) - { - setTreeInternal(child.children, item); - } - } - } - - void contextMenuEvent(QContextMenuEvent* event) - { - const auto col = currentColumn(); - auto item = static_cast(currentItem()); - - if (item && col >= 0) - { - QMenu menu; - - auto action = new QAction("Expand all", nullptr); - connect(action, &QAction::triggered, this, &MyTreeWidget::onExpandAllClicked); - menu.addAction(action); - - action = new QAction("Collapse all", nullptr); - connect(action, &QAction::triggered, this, &MyTreeWidget::onCollapseAllClicked); - menu.addAction(action); - - switch (col) - { - case 4: - { - menu.addSeparator(); - auto itemAction = new ItemAction("Jump to such item", item); - connect(itemAction, &ItemAction::clicked, this, &MyTreeWidget::onJumpToMinItemClicked); - menu.addAction(itemAction); - break; - } - - case 5: - { - menu.addSeparator(); - auto itemAction = new ItemAction("Jump to such item", item); - connect(itemAction, &ItemAction::clicked, this, &MyTreeWidget::onJumpToMaxItemClicked); - menu.addAction(itemAction); - break; - } - } - - menu.exec(QCursor::pos()); - - event->accept(); - } - } - -private slots: - - void onJumpToMinItemClicked(MyTreeItem* _item) - { - auto it = m_itemblocks.find(_item->block()->total_statistics->min_duration_block); - if (it != m_itemblocks.end()) - { - scrollToItem(it->second, QAbstractItemView::PositionAtCenter); - setCurrentItem(it->second); - } - } - - void onJumpToMaxItemClicked(MyTreeItem* _item) - { - auto it = m_itemblocks.find(_item->block()->total_statistics->max_duration_block); - if (it != m_itemblocks.end()) - { - scrollToItem(it->second, QAbstractItemView::PositionAtCenter); - setCurrentItem(it->second); - } - } - - void onCollapseAllClicked(bool) - { - collapseAll(); - } - - void onExpandAllClicked(bool) - { - disconnect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); - expandAll(); - resizeColumnToContents(0); - connect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpand); - } - - void onItemExpand(QTreeWidgetItem*) - { - resizeColumnToContents(0); - } - -}; - -////////////////////////////////////////////////////////////////////////// - -#endif // MY____TREE___VIEW_H