diff --git a/include/profiler/reader.h b/include/profiler/reader.h index 88d8eff..72a0e8c 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -23,6 +23,7 @@ along with this program.If not, see . #include #include +#include #include "profiler/profiler.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -87,8 +88,8 @@ namespace profiler { children_t children; ///< List of children blocks. May be empty. ::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.) - ::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks) - ::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) + ::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks) + ::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) ::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread ::profiler::block_index_t block_index; ///< Index of this block @@ -288,6 +289,13 @@ namespace profiler { m_data = _data; } + void swap(SerializedData& other) + { + auto temp = other.m_data; + other.m_data = m_data; + m_data = temp; + } + private: SerializedData(const SerializedData&) = delete; @@ -300,9 +308,13 @@ namespace profiler { } // END of namespace profiler. extern "C"{ - unsigned int PROFILER_API fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); + unsigned int PROFILER_API fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); } +inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) { + ::std::atomic progress = ATOMIC_VAR_INIT(0); + return fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, gather_statistics); +} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/CMakeLists.txt b/profiler_gui/CMakeLists.txt index b43c498..eb7fe3a 100644 --- a/profiler_gui/CMakeLists.txt +++ b/profiler_gui/CMakeLists.txt @@ -22,6 +22,10 @@ add_executable(${PROJECT_NAME} graphics_scrollbar.cpp main_window.h main_window.cpp + tree_widget_item.h + tree_widget_item.cpp + tree_widget_loader.h + tree_widget_loader.cpp #treemodel.h #treemodel.cpp #treeitem.h diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index e2f3150..40f7d5b 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -25,10 +25,12 @@ * license : TODO: add license text ************************************************************************/ +#include #include #include #include #include +#include #include #include #include @@ -64,6 +66,8 @@ const unsigned int TEST_PROGRESSION_BASE = 4; const int FLICKER_INTERVAL = 16; // 60Hz +const auto CHRONOMETER_FONT = QFont("CourierNew", 16, 2); + ////////////////////////////////////////////////////////////////////////// auto const sign = [](int _value) { return _value < 0 ? -1 : 1; }; @@ -81,27 +85,25 @@ inline T logn(T _value) ////////////////////////////////////////////////////////////////////////// -ProfGraphicsItem::ProfGraphicsItem(unsigned char _index, bool _test) : QGraphicsItem(nullptr), m_bTest(_test), m_pRoot(nullptr), m_index(_index) +EasyGraphicsItem::EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root) + : QGraphicsItem(nullptr) + , m_pRoot(_root) + , m_index(_index) { } -ProfGraphicsItem::ProfGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root) : ProfGraphicsItem(_index, false) -{ - m_pRoot = _root; -} - -ProfGraphicsItem::~ProfGraphicsItem() +EasyGraphicsItem::~EasyGraphicsItem() { } -const ProfGraphicsView* ProfGraphicsItem::view() const +const EasyGraphicsView* EasyGraphicsItem::view() const { - return static_cast(scene()->parent()); + return static_cast(scene()->parent()); } ////////////////////////////////////////////////////////////////////////// -QRectF ProfGraphicsItem::boundingRect() const +QRectF EasyGraphicsItem::boundingRect() const { //const auto sceneView = view(); //return QRectF(m_boundingRect.left() - sceneView->offset() / sceneView->scale(), m_boundingRect.top(), m_boundingRect.width() * sceneView->scale(), m_boundingRect.height()); @@ -110,7 +112,7 @@ QRectF ProfGraphicsItem::boundingRect() const ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) { if (m_levels.empty() || m_levels.front().empty()) { @@ -177,6 +179,10 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* previousPenStyle = Qt::SolidLine; _painter->setPen(BORDERS_COLOR); } + else + { + _painter->setPen(Qt::NoPen); + } @@ -187,7 +193,6 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* auto& level = m_levels[l]; const short next_level = l + 1; char state = 1; - //bool changebrush = false; const auto top = levelY(l); for (unsigned int i = m_levelsIndexes[l], end = static_cast(level.size()); i < end; ++i) @@ -207,8 +212,10 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* continue; } + qreal x = 0; + int h = 0, flags = 0; auto w = ::std::max(item.width() * currentScale, 1.0); - if (w < 20) + if (w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded) { // Items which width is less than 20 will be painted as big rectangles which are hiding it's children if (item.left() > sceneRight) @@ -217,20 +224,11 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* break; } - const auto x = item.left() * currentScale - dx; - //if (previousColor != item.color) - //{ - // changebrush = true; - // previousColor = item.color; - // QLinearGradient gradient(x - dx, item.top(), x - dx, item.top() + item.totalHeight); - // gradient.setColorAt(0, item.color); - // gradient.setColorAt(1, 0x00ffffff); - // brush = QBrush(gradient); - // _painter->setBrush(brush); - //} + x = item.left() * currentScale - dx; + h = item.totalHeight; bool changepen = false; - if (!m_bTest && item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) + if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) { selectedItemsWasPainted = true; changepen = true; @@ -291,69 +289,69 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* m_levels[next_level][item.children_begin].state = -1; } - continue; - } + if (w < 20) + continue; - if (next_level < levelsNumber && item.children_begin != MAX_CHILD_INDEX) - { - if (m_levelsIndexes[next_level] == MAX_CHILD_INDEX) - { - // Mark first potentially visible child item on next sublevel - m_levelsIndexes[next_level] = item.children_begin; - } - - // Mark children items that we want to draw them - m_levels[next_level][item.children_begin].state = 1; - } - - if (item.left() > sceneRight) - { - // This is first totally invisible item. No need to check other items. - break; - } - - //if (changebrush) - //{ - // changebrush = false; - // previousColor = item.color; - // brush = QBrush(previousColor); - // _painter->setBrush(brush); - //} else - - if (!m_bTest && item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) - { - selectedItemsWasPainted = true; - QPen pen(Qt::SolidLine); - pen.setColor(Qt::red); - pen.setWidth(2); - _painter->setPen(pen); - - previousColor = SELECTED_ITEM_COLOR; - brush.setColor(previousColor); - _painter->setBrush(brush); + flags = Qt::AlignCenter; } else { - if (previousColor != item.color) + if (next_level < levelsNumber && item.children_begin != MAX_CHILD_INDEX) { - // Set background color brush for rectangle - previousColor = item.color; + if (m_levelsIndexes[next_level] == MAX_CHILD_INDEX) + { + // Mark first potentially visible child item on next sublevel + m_levelsIndexes[next_level] = item.children_begin; + } + + // Mark children items that we want to draw them + m_levels[next_level][item.children_begin].state = 1; + } + + if (item.left() > sceneRight) + { + // This is first totally invisible item. No need to check other items. + break; + } + + if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) + { + selectedItemsWasPainted = true; + QPen pen(Qt::SolidLine); + pen.setColor(Qt::red); + pen.setWidth(2); + _painter->setPen(pen); + + previousColor = SELECTED_ITEM_COLOR; brush.setColor(previousColor); _painter->setBrush(brush); } - - if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders && previousPenStyle != Qt::SolidLine) + else { - // Restore pen for item which is wide enough to paint borders - previousPenStyle = Qt::SolidLine; - _painter->setPen(BORDERS_COLOR); - } - } + if (previousColor != item.color) + { + // Set background color brush for rectangle + previousColor = item.color; + brush.setColor(previousColor); + _painter->setBrush(brush); + } - // Draw rectangle - const auto x = item.left() * currentScale - dx; - rect.setRect(x, top, w, GRAPHICS_ROW_SIZE); - _painter->drawRect(rect); + if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders && previousPenStyle != Qt::SolidLine) + { + // Restore pen for item which is wide enough to paint borders + previousPenStyle = Qt::SolidLine; + _painter->setPen(BORDERS_COLOR); + } + } + + // Draw rectangle + x = item.left() * currentScale - dx; + h = GRAPHICS_ROW_SIZE; + rect.setRect(x, top, w, GRAPHICS_ROW_SIZE); + _painter->drawRect(rect); + + flags = item.width() < 1 ? 0 : Qt::AlignHCenter; + } // Draw text----------------------------------- // calculating text coordinates @@ -366,7 +364,12 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* xtext = sceneLeft * currentScale - dx; } - rect.setRect(xtext + 1, top, w - 1, GRAPHICS_ROW_SIZE); + if (item.right() > sceneRight) + { + w -= (item.right() - sceneRight) * currentScale; + } + + rect.setRect(xtext + 1, top, w - 1, h); // text will be painted with inverse color auto textColor = 0x00ffffff - previousColor; @@ -374,16 +377,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(textColor); // drawing text - if (m_bTest) - { - char text[128] = {0}; - sprintf(text, "ITEM_%u", i); - _painter->drawText(rect, 0, text); - } - else - { - _painter->drawText(rect, 0, ::profiler_gui::toUnicode(item.block->node->getName())); - } + _painter->drawText(rect, flags, ::profiler_gui::toUnicode(item.block->node->getName())); // restore previous pen color if (previousPenStyle == Qt::NoPen) @@ -394,7 +388,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } } - if (!selectedItemsWasPainted && !m_bTest && ::profiler_gui::EASY_GLOBALS.selected_block < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) + if (!selectedItemsWasPainted && ::profiler_gui::EASY_GLOBALS.selected_block < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) { const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[::profiler_gui::EASY_GLOBALS.selected_block]; if (guiblock.graphics_item == m_index) @@ -407,11 +401,50 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* pen.setWidth(2); _painter->setPen(pen); - brush.setColor(previousColor); + brush.setColor(SELECTED_ITEM_COLOR); _painter->setBrush(brush); - rect.setRect(item.left() * currentScale - dx, levelY(guiblock.graphics_item_level), ::std::max(item.width() * currentScale, 1.0), item.totalHeight); + auto top = levelY(guiblock.graphics_item_level); + auto x = item.left() * currentScale - dx; + auto w = ::std::max(item.width() * currentScale, 1.0); + rect.setRect(x, top, w, item.totalHeight); _painter->drawRect(rect); + + if (w > 20) + { + // Draw text----------------------------------- + // calculating text coordinates + auto xtext = x; + if (item.left() < sceneLeft) + { + // if item left border is out of screen then attach text to the left border of the screen + // to ensure text is always visible for items presenting on the screen. + w += (item.left() - sceneLeft) * currentScale; + xtext = sceneLeft * currentScale - dx; + } + + if (item.right() > sceneRight) + { + w -= (item.right() - sceneRight) * currentScale; + } + + rect.setRect(xtext + 1, top, w - 1, item.totalHeight); + + // text will be painted with inverse color + auto textColor = 0x00ffffff - previousColor; + if (textColor == previousColor) textColor = 0; + _painter->setPen(textColor); + + // drawing text + _painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(item.block->node->getName())); + + // restore previous pen color + if (previousPenStyle == Qt::NoPen) + _painter->setPen(Qt::NoPen); + else + _painter->setPen(BORDERS_COLOR); // restore pen for rectangle painting + // END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } } } } @@ -419,14 +452,16 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->restore(); } -QRect ProfGraphicsItem::getRect() const +////////////////////////////////////////////////////////////////////////// + +QRect EasyGraphicsItem::getRect() const { return view()->mapFromScene(m_boundingRect).boundingRect(); } ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const +void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const { //if (m_bTest) //{ @@ -476,7 +511,7 @@ void ProfGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree ////////////////////////////////////////////////////////////////////////// -const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& _pos) const +const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const { if (m_levels.empty() || m_levels.front().empty()) { @@ -544,7 +579,7 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& } const auto w = item.width() * currentScale; - if (i == levelIndex || w < 20) + if (i == levelIndex || w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded) { return &item; } @@ -599,36 +634,36 @@ const ::profiler_gui::ProfBlockItem* ProfGraphicsItem::intersect(const QPointF& ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h) +void EasyGraphicsItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); } -void ProfGraphicsItem::setBoundingRect(const QRectF& _rect) +void EasyGraphicsItem::setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } ////////////////////////////////////////////////////////////////////////// -::profiler::thread_id_t ProfGraphicsItem::threadId() const +::profiler::thread_id_t EasyGraphicsItem::threadId() const { return m_pRoot->thread_id; } ////////////////////////////////////////////////////////////////////////// -unsigned char ProfGraphicsItem::levels() const +unsigned char EasyGraphicsItem::levels() const { return static_cast(m_levels.size()); } -float ProfGraphicsItem::levelY(unsigned char _level) const +float EasyGraphicsItem::levelY(unsigned char _level) const { return y() + static_cast(_level) * static_cast(GRAPHICS_ROW_SIZE_FULL); } -void ProfGraphicsItem::setLevels(unsigned char _levels) +void EasyGraphicsItem::setLevels(unsigned char _levels) { typedef decltype(m_levelsIndexes) IndexesT; static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(); @@ -637,29 +672,29 @@ void ProfGraphicsItem::setLevels(unsigned char _levels) m_levelsIndexes.resize(_levels, MAX_CHILD_INDEX); } -void ProfGraphicsItem::reserve(unsigned char _level, unsigned int _items) +void EasyGraphicsItem::reserve(unsigned char _level, unsigned int _items) { m_levels[_level].reserve(_items); } ////////////////////////////////////////////////////////////////////////// -const ProfGraphicsItem::Children& ProfGraphicsItem::items(unsigned char _level) const +const EasyGraphicsItem::Children& EasyGraphicsItem::items(unsigned char _level) const { return m_levels[_level]; } -const ::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned char _level, unsigned int _index) const +const ::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) const { return m_levels[_level][_index]; } -::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned char _level, unsigned int _index) +::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) { return m_levels[_level][_index]; } -unsigned int ProfGraphicsItem::addItem(unsigned char _level) +unsigned int EasyGraphicsItem::addItem(unsigned char _level) { m_levels[_level].emplace_back(); return static_cast(m_levels[_level].size() - 1); @@ -667,22 +702,29 @@ unsigned int ProfGraphicsItem::addItem(unsigned char _level) ////////////////////////////////////////////////////////////////////////// -ProfChronometerItem::ProfChronometerItem(bool _main) : QGraphicsItem(), m_font(QFont("CourierNew", 16, 2)), m_color(CHRONOMETER_COLOR), m_left(0), m_right(0), m_bMain(_main), m_bReverse(false), m_bHover(false) +EasyChronometerItem::EasyChronometerItem(bool _main) + : QGraphicsItem() + , m_color(CHRONOMETER_COLOR) + , m_left(0) + , m_right(0) + , m_bMain(_main) + , m_bReverse(false) + , m_bHoverIndicator(false) { //setZValue(_main ? 10 : 9); m_indicator.reserve(3); } -ProfChronometerItem::~ProfChronometerItem() +EasyChronometerItem::~EasyChronometerItem() { } -QRectF ProfChronometerItem::boundingRect() const +QRectF EasyChronometerItem::boundingRect() const { return m_boundingRect; } -void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) { const auto sceneView = view(); const auto currentScale = sceneView->scale(); @@ -699,7 +741,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt if (m_bMain) { - const int size = m_bHover ? 12 : 10; + const int size = m_bHoverIndicator ? 12 : 10; auto vcenter = visibleSceneRect.top() + visibleSceneRect.height() * 0.5; auto color = QColor::fromRgb(m_color.rgb()); auto pen = _painter->pen(); @@ -723,7 +765,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt _painter->save(); _painter->setTransform(QTransform::fromTranslate(-x(), -y()), true); - _painter->setBrush(m_bHover ? QColor::fromRgb(0xffff0000) : color); + _painter->setBrush(m_bHoverIndicator ? QColor::fromRgb(0xffff0000) : color); _painter->setPen(pen); _painter->drawPolygon(m_indicator); _painter->restore(); @@ -737,7 +779,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt selectedInterval = units2microseconds(selectedInterval); const QString text = ::profiler_gui::timeStringReal(selectedInterval); // Displayed text - const auto textRect = QFontMetrics(m_font).boundingRect(text); // Calculate displayed text boundingRect + const auto textRect = QFontMetrics(CHRONOMETER_FONT).boundingRect(text); // Calculate displayed text boundingRect const auto rgb = m_color.rgb() & 0x00ffffff; @@ -764,7 +806,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt // draw text _painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background _painter->setPen(0xffffffff - rgb); - _painter->setFont(m_font); + _painter->setFont(CHRONOMETER_FONT); if (m_left < sceneLeft) { @@ -789,14 +831,12 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt return; } - sceneLeft -= offset; - sceneRight -= offset; - if (rect.right() + textRect.width() < sceneRight) + if (m_right + textRect.width() < sceneRight) { // Text will be drawed to the right of rectangle _painter->drawText(QPointF(rect.right(), rect.top() + rect.height() * 0.5 + textRect.height() * 0.33), text); } - else if (rect.left() - textRect.width() > sceneLeft) + else if (m_left - textRect.width() > sceneLeft) { // Text will be drawed to the left of rectangle _painter->drawText(QPointF(rect.left() - textRect.width(), rect.top() + rect.height() * 0.5 + textRect.height() * 0.33), text); @@ -811,7 +851,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt // END Paint!~~~~~~~~~~~~~~~~~~~~~~ } -bool ProfChronometerItem::contains(const QPointF& _pos) const +bool EasyChronometerItem::contains(const QPointF& _pos) const { const auto sceneView = view(); const auto clickX = (_pos.x() - sceneView->offset()) * sceneView->scale() - x(); @@ -820,22 +860,22 @@ bool ProfChronometerItem::contains(const QPointF& _pos) const return false; } -void ProfChronometerItem::setColor(const QColor& _color) +void EasyChronometerItem::setColor(const QColor& _color) { m_color = _color; } -void ProfChronometerItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h) +void EasyChronometerItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); } -void ProfChronometerItem::setBoundingRect(const QRectF& _rect) +void EasyChronometerItem::setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } -void ProfChronometerItem::setLeftRight(qreal _left, qreal _right) +void EasyChronometerItem::setLeftRight(qreal _left, qreal _right) { if (_left < _right) { @@ -849,26 +889,26 @@ void ProfChronometerItem::setLeftRight(qreal _left, qreal _right) } } -void ProfChronometerItem::setReverse(bool _reverse) +void EasyChronometerItem::setReverse(bool _reverse) { m_bReverse = _reverse; } -void ProfChronometerItem::setHover(bool _hover) +void EasyChronometerItem::setHover(bool _hover) { - m_bHover = _hover; + m_bHoverIndicator = _hover; } -const ProfGraphicsView* ProfChronometerItem::view() const +const EasyGraphicsView* EasyChronometerItem::view() const { - return static_cast(scene()->parent()); + return static_cast(scene()->parent()); } ////////////////////////////////////////////////////////////////////////// -void ProfBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +void EasyBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) { - const auto sceneView = static_cast(scene()->parent()); + const auto sceneView = static_cast(scene()->parent()); const auto visibleSceneRect = sceneView->visibleSceneRect(); const auto currentScale = sceneView->scale(); const auto offset = sceneView->offset(); @@ -940,9 +980,9 @@ void ProfBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte ////////////////////////////////////////////////////////////////////////// -void ProfTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) { - const auto sceneView = static_cast(scene()->parent()); + const auto sceneView = static_cast(scene()->parent()); const auto visibleSceneRect = sceneView->visibleSceneRect(); const auto step = sceneView->timelineStep() * sceneView->scale(); const QString text = ::profiler_gui::timeStringInt(units2microseconds(sceneView->timelineStep())); // Displayed text @@ -966,7 +1006,7 @@ void ProfTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap ////////////////////////////////////////////////////////////////////////// -ProfGraphicsView::ProfGraphicsView(QWidget* _parent) +EasyGraphicsView::EasyGraphicsView(QWidget* _parent) : QGraphicsView(_parent) , m_beginTime(::std::numeric_limits::max()) , m_scale(1) @@ -979,7 +1019,7 @@ ProfGraphicsView::ProfGraphicsView(QWidget* _parent) , m_flickerSpeedY(0) , m_bDoubleClick(false) , m_bUpdatingRect(false) - , m_bTest(false) + //, m_bTest(false) , m_bEmpty(true) { initMode(); @@ -987,15 +1027,15 @@ ProfGraphicsView::ProfGraphicsView(QWidget* _parent) updateVisibleSceneRect(); } -ProfGraphicsView::~ProfGraphicsView() +EasyGraphicsView::~EasyGraphicsView() { } ////////////////////////////////////////////////////////////////////////// -ProfChronometerItem* ProfGraphicsView::createChronometer(bool _main) +EasyChronometerItem* EasyGraphicsView::createChronometer(bool _main) { - auto chronoItem = new ProfChronometerItem(_main); + auto chronoItem = new EasyChronometerItem(_main); chronoItem->setColor(_main ? CHRONOMETER_COLOR : CHRONOMETER_COLOR2); chronoItem->setBoundingRect(scene()->sceneRect()); chronoItem->hide(); @@ -1006,7 +1046,7 @@ ProfChronometerItem* ProfGraphicsView::createChronometer(bool _main) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, unsigned int _childrenNumber, unsigned int& _total_items) +/*void EasyGraphicsView::fillTestChildren(EasyGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, unsigned int _childrenNumber, unsigned int& _total_items) { unsigned int nchildren = _childrenNumber; _childrenNumber = TEST_PROGRESSION_BASE; @@ -1041,7 +1081,7 @@ void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxl } } -void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows) +void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows) { static const qreal X_BEGIN = 50; static const qreal Y_BEGIN = 0; @@ -1055,14 +1095,14 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite const auto first_level_children_count = static_cast(static_cast(children_per_frame) * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5); - auto bgItem = new ProfBackgroundItem(); + auto bgItem = new EasyBackgroundItem(); scene()->addItem(bgItem); - ::std::vector thread_items(_rows); + ::std::vector thread_items(_rows); for (unsigned char i = 0; i < _rows; ++i) { - auto item = new ProfGraphicsItem(i, true); + auto item = new EasyGraphicsItem(i, true); thread_items[i] = item; item->setPos(0, Y_BEGIN + i * (max_depth * GRAPHICS_ROW_SIZE_FULL + THREADS_ROW_SPACING * 5)); @@ -1087,7 +1127,7 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite // Create required number of items unsigned int total_items = 0; qreal maxX = 0; - const ProfGraphicsItem* longestItem = nullptr; + const EasyGraphicsItem* longestItem = nullptr; for (unsigned char i = 0; i < _rows; ++i) { auto item = thread_items[i]; @@ -1150,7 +1190,7 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite m_chronometerItem = createChronometer(true); bgItem->setBoundingRect(scene()->sceneRect()); - auto indicator = new ProfTimelineIndicatorItem(); + auto indicator = new EasyTimelineIndicatorItem(); indicator->setBoundingRect(scene()->sceneRect()); scene()->addItem(indicator); @@ -1159,11 +1199,11 @@ void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite m_bEmpty = false; scaleTo(BASE_SCALE); -} +}*/ ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::clearSilent() +void EasyGraphicsView::clearSilent() { const QSignalBlocker blocker(this), sceneBlocker(scene()); // block all scene signals (otherwise clear() would be extremely slow!) @@ -1183,14 +1223,14 @@ void ProfGraphicsView::clearSilent() m_offset = 0; // scroll back to the beginning of the scene // Reset necessary flags - m_bTest = false; + //m_bTest = false; m_bEmpty = true; // notify ProfTreeWidget that selection was reset emit intervalChanged(m_selectedBlocks, m_beginTime, 0, 0, false); } -void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree) +void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree) { // clear scene clearSilent(); @@ -1200,7 +1240,7 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr return; } - auto bgItem = new ProfBackgroundItem(); + auto bgItem = new EasyBackgroundItem(); scene()->addItem(bgItem); // set new blocks tree @@ -1209,7 +1249,7 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // Calculating start and end time ::profiler::timestamp_t finish = 0; const ::profiler::BlocksTree* longestTree = nullptr; - const ProfGraphicsItem* longestItem = nullptr; + const EasyGraphicsItem* longestItem = nullptr; for (const auto& threadTree : _blocksTree) { const auto& tree = threadTree.second.tree; @@ -1236,7 +1276,7 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // fill scene with new items const auto& tree = threadTree.second.tree; qreal h = 0, x = time2position(tree.children.front().node->block()->getBegin()); - auto item = new ProfGraphicsItem(static_cast(m_items.size()), &threadTree.second); + auto item = new EasyGraphicsItem(static_cast(m_items.size()), &threadTree.second); item->setLevels(tree.depth); item->setPos(0, y); @@ -1255,7 +1295,7 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr if (m_items.size() == 0xff) { - qWarning() << "Maximum threads number (255 threads) exceeded! See ProfGraphicsView::setTree() : " << __LINE__ << " in file " << __FILE__; + qWarning() << "Maximum threads number (255 threads) exceeded! See EasyGraphicsView::setTree() : " << __LINE__ << " in file " << __FILE__; break; } } @@ -1283,23 +1323,23 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr m_chronometerItem = createChronometer(true); bgItem->setBoundingRect(0, 0, endX, y); - auto indicator = new ProfTimelineIndicatorItem(); + auto indicator = new EasyTimelineIndicatorItem(); indicator->setBoundingRect(0, 0, endX, y); scene()->addItem(indicator); // Setting flags - m_bTest = false; + //m_bTest = false; m_bEmpty = false; scaleTo(BASE_SCALE); } -const ProfGraphicsView::Items &ProfGraphicsView::getItems() const +const EasyGraphicsView::Items &EasyGraphicsView::getItems() const { return m_items; } -qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level) +qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level) { static const qreal MIN_DURATION = 0.25; @@ -1364,7 +1404,7 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block else if (!child.children.empty() && !warned) { warned = true; - qWarning() << "Maximum blocks depth (255) exceeded! See ProfGraphicsView::setTree() : " << __LINE__ << " in file " << __FILE__; + qWarning() << "Maximum blocks depth (255) exceeded! See EasyGraphicsView::setTree() : " << __LINE__ << " in file " << __FILE__; } if (duration < children_duration) @@ -1394,11 +1434,11 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::setScrollbar(ProfGraphicsScrollbar* _scrollbar) +void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar) { if (m_pScrollbar) { - disconnect(m_pScrollbar, &ProfGraphicsScrollbar::valueChanged, this, &This::onGraphicsScrollbarValueChange); + disconnect(m_pScrollbar, &EasyGraphicsScrollbar::valueChanged, this, &This::onGraphicsScrollbarValueChange); } m_pScrollbar = _scrollbar; @@ -1407,7 +1447,7 @@ void ProfGraphicsView::setScrollbar(ProfGraphicsScrollbar* _scrollbar) m_pScrollbar->setRange(0, scene()->width()); m_pScrollbar->setSliderWidth(m_visibleSceneRect.width()); m_pScrollbar->setValue(0); - connect(m_pScrollbar, &ProfGraphicsScrollbar::valueChanged, this, &This::onGraphicsScrollbarValueChange); + connect(m_pScrollbar, &EasyGraphicsScrollbar::valueChanged, this, &This::onGraphicsScrollbarValueChange); ::profiler_gui::EASY_GLOBALS.selected_thread = 0; emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0); @@ -1415,7 +1455,7 @@ void ProfGraphicsView::setScrollbar(ProfGraphicsScrollbar* _scrollbar) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::updateVisibleSceneRect() +void EasyGraphicsView::updateVisibleSceneRect() { m_visibleSceneRect = mapToScene(rect()).boundingRect(); @@ -1424,7 +1464,7 @@ void ProfGraphicsView::updateVisibleSceneRect() m_visibleSceneRect.setWidth(m_visibleSceneRect.width() - vbar->width() - 2); } -void ProfGraphicsView::updateTimelineStep(qreal _windowWidth) +void EasyGraphicsView::updateTimelineStep(qreal _windowWidth) { const auto time = units2microseconds(_windowWidth); if (time < 100) @@ -1445,14 +1485,14 @@ void ProfGraphicsView::updateTimelineStep(qreal _windowWidth) m_timelineStep = microseconds2units(m_timelineStep); } -void ProfGraphicsView::updateScene() +void EasyGraphicsView::updateScene() { scene()->update(m_visibleSceneRect); } ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::scaleTo(qreal _scale) +void EasyGraphicsView::scaleTo(qreal _scale) { if (m_bEmpty) { @@ -1472,7 +1512,7 @@ void ProfGraphicsView::scaleTo(qreal _scale) updateScene(); } -void ProfGraphicsView::wheelEvent(QWheelEvent* _event) +void EasyGraphicsView::wheelEvent(QWheelEvent* _event) { if (m_bEmpty) { @@ -1511,7 +1551,7 @@ void ProfGraphicsView::wheelEvent(QWheelEvent* _event) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::mousePressEvent(QMouseEvent* _event) +void EasyGraphicsView::mousePressEvent(QMouseEvent* _event) { if (m_bEmpty) { @@ -1534,7 +1574,7 @@ void ProfGraphicsView::mousePressEvent(QMouseEvent* _event) _event->accept(); } -void ProfGraphicsView::mouseDoubleClickEvent(QMouseEvent* _event) +void EasyGraphicsView::mouseDoubleClickEvent(QMouseEvent* _event) { if (m_bEmpty) { @@ -1559,7 +1599,7 @@ void ProfGraphicsView::mouseDoubleClickEvent(QMouseEvent* _event) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::mouseReleaseEvent(QMouseEvent* _event) +void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event) { if (m_bEmpty) { @@ -1583,7 +1623,7 @@ void ProfGraphicsView::mouseReleaseEvent(QMouseEvent* _event) m_selectedBlocks.clear(); } - if (!m_bTest && m_chronometerItem->isVisible()) + if (m_chronometerItem->isVisible()) { //printf("INTERVAL: {%lf, %lf} ms\n", m_chronometerItem->left(), m_chronometerItem->right()); @@ -1605,7 +1645,7 @@ void ProfGraphicsView::mouseReleaseEvent(QMouseEvent* _event) { m_chronometerItemAux->hide(); } - else if (m_chronometerItem->isVisible() && m_chronometerItem->hover()) + else if (m_chronometerItem->isVisible() && m_chronometerItem->hoverIndicator()) { // Jump to selected zone clicked = true; @@ -1613,7 +1653,7 @@ void ProfGraphicsView::mouseReleaseEvent(QMouseEvent* _event) m_pScrollbar->setValue(m_chronometerItem->left() + m_chronometerItem->width() * 0.5 - m_pScrollbar->sliderHalfWidth()); } - if (!clicked && m_mouseMovePath.manhattanLength() < 5 && !m_bTest) + if (!clicked && m_mouseMovePath.manhattanLength() < 5) { // Handle Click @@ -1659,7 +1699,7 @@ void ProfGraphicsView::mouseReleaseEvent(QMouseEvent* _event) ////////////////////////////////////////////////////////////////////////// -bool ProfGraphicsView::moveChrono(ProfChronometerItem* _chronometerItem, qreal _mouseX) +bool EasyGraphicsView::moveChrono(EasyChronometerItem* _chronometerItem, qreal _mouseX) { if (_chronometerItem->reverse()) { @@ -1695,7 +1735,7 @@ bool ProfGraphicsView::moveChrono(ProfChronometerItem* _chronometerItem, qreal _ return false; } -void ProfGraphicsView::mouseMoveEvent(QMouseEvent* _event) +void EasyGraphicsView::mouseMoveEvent(QMouseEvent* _event) { if (m_bEmpty || (m_mouseButtons == 0 && !m_chronometerItem->isVisible())) { @@ -1764,9 +1804,9 @@ void ProfGraphicsView::mouseMoveEvent(QMouseEvent* _event) if (m_chronometerItem->isVisible()) { - auto prevValue = m_chronometerItem->hover(); + auto prevValue = m_chronometerItem->hoverIndicator(); m_chronometerItem->setHover(m_chronometerItem->contains(mouseScenePos)); - needUpdate = needUpdate || (prevValue != m_chronometerItem->hover()); + needUpdate = needUpdate || (prevValue != m_chronometerItem->hoverIndicator()); } if (needUpdate) @@ -1779,7 +1819,7 @@ void ProfGraphicsView::mouseMoveEvent(QMouseEvent* _event) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::resizeEvent(QResizeEvent* _event) +void EasyGraphicsView::resizeEvent(QResizeEvent* _event) { QGraphicsView::resizeEvent(_event); updateVisibleSceneRect(); // Update scene visible rect only once @@ -1788,7 +1828,7 @@ void ProfGraphicsView::resizeEvent(QResizeEvent* _event) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::initMode() +void EasyGraphicsView::initMode() { // TODO: find mode with least number of bugs :) // There are always some display bugs... @@ -1801,19 +1841,20 @@ void ProfGraphicsView::initMode() setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange); connect(&m_flickerTimer, &QTimer::timeout, this, &This::onFlickerTimeout); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::ProfGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::ProfGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); + connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange); } ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::onScrollbarValueChange(int) +void EasyGraphicsView::onScrollbarValueChange(int) { if (!m_bUpdatingRect && !m_bEmpty) updateVisibleSceneRect(); } -void ProfGraphicsView::onGraphicsScrollbarValueChange(qreal _value) +void EasyGraphicsView::onGraphicsScrollbarValueChange(qreal _value) { if (!m_bEmpty) { @@ -1828,7 +1869,7 @@ void ProfGraphicsView::onGraphicsScrollbarValueChange(qreal _value) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::onFlickerTimeout() +void EasyGraphicsView::onFlickerTimeout() { if (m_mouseButtons & Qt::LeftButton) { @@ -1865,9 +1906,9 @@ void ProfGraphicsView::onFlickerTimeout() ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::onSelectedThreadChange(::profiler::thread_id_t _id) +void EasyGraphicsView::onSelectedThreadChange(::profiler::thread_id_t _id) { - if (m_pScrollbar == nullptr || m_pScrollbar->minimapThread() == _id || m_bTest) + if (m_pScrollbar == nullptr || m_pScrollbar->minimapThread() == _id) { return; } @@ -1894,7 +1935,7 @@ void ProfGraphicsView::onSelectedThreadChange(::profiler::thread_id_t _id) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsView::onSelectedBlockChange(unsigned int _block_index) +void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index) { if (!m_bUpdatingRect) { @@ -1921,16 +1962,26 @@ void ProfGraphicsView::onSelectedBlockChange(unsigned int _block_index) ////////////////////////////////////////////////////////////////////////// -ProfGraphicsViewWidget::ProfGraphicsViewWidget(QWidget* _parent) +void EasyGraphicsView::onItemsEspandStateChange() +{ + if (!m_bUpdatingRect) + { + updateScene(); + } +} + +////////////////////////////////////////////////////////////////////////// + +EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent) : QWidget(_parent) - , m_scrollbar(new ProfGraphicsScrollbar(nullptr)) - , m_view(new ProfGraphicsView(nullptr)) - //, m_threadWidget(new ProfThreadViewWidget(this,m_view)) + , m_scrollbar(new EasyGraphicsScrollbar(nullptr)) + , m_view(new EasyGraphicsView(nullptr)) + //, m_threadWidget(new EasyThreadViewWidget(this,m_view)) { initWidget(); } -void ProfGraphicsViewWidget::initWidget() +void EasyGraphicsViewWidget::initWidget() { auto lay = new QGridLayout(this); lay->setContentsMargins(1, 0, 1, 0); @@ -1944,12 +1995,12 @@ void ProfGraphicsViewWidget::initWidget() m_view->setScrollbar(m_scrollbar); } -ProfGraphicsViewWidget::~ProfGraphicsViewWidget() +EasyGraphicsViewWidget::~EasyGraphicsViewWidget() { } -ProfGraphicsView* ProfGraphicsViewWidget::view() +EasyGraphicsView* EasyGraphicsViewWidget::view() { return m_view; } @@ -1957,7 +2008,7 @@ ProfGraphicsView* ProfGraphicsViewWidget::view() ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -ProfThreadViewWidget::ProfThreadViewWidget(QWidget *parent, ProfGraphicsView* view):QWidget(parent), +EasyThreadViewWidget::EasyThreadViewWidget(QWidget *parent, EasyGraphicsView* view):QWidget(parent), m_view(view) , m_label(new QLabel("",this)) { @@ -1967,15 +2018,15 @@ ProfThreadViewWidget::ProfThreadViewWidget(QWidget *parent, ProfGraphicsView* vi //m_layout->addWidget(m_label); //setLayout(m_layout); //show(); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::ProfGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); + connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); } -ProfThreadViewWidget::~ProfThreadViewWidget() +EasyThreadViewWidget::~EasyThreadViewWidget() { } -void ProfThreadViewWidget::onSelectedThreadChange(::profiler::thread_id_t _id) +void EasyThreadViewWidget::onSelectedThreadChange(::profiler::thread_id_t _id) { /* auto threadName = ::profiler_gui::EASY_GLOBALS.profiler_blocks[::profiler_gui::EASY_GLOBALS.selected_thread].thread_name; diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index d36d0b2..f27b724 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -21,13 +21,11 @@ * license : TODO: add license text ************************************************************************/ -#ifndef MY____GRAPHICS___VIEW_H -#define MY____GRAPHICS___VIEW_H +#ifndef EASY__GRAPHICS_VIEW__H_ +#define EASY__GRAPHICS_VIEW__H_ #include -#include #include -#include #include #include #include @@ -40,7 +38,7 @@ ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsView; +class EasyGraphicsView; ////////////////////////////////////////////////////////////////////////// @@ -58,7 +56,7 @@ inline qreal microseconds2units(qreal _value) ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsItem : public QGraphicsItem +class EasyGraphicsItem : public QGraphicsItem { typedef ::profiler_gui::ProfItems Children; typedef ::std::vector DrawIndexes; @@ -69,14 +67,12 @@ class ProfGraphicsItem : public QGraphicsItem QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem) const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy. - const bool m_bTest; ///< If true then we are running test() - unsigned char m_index; ///< This item's index in the list of items of ProfGraphicsView + unsigned char m_index; ///< This item's index in the list of items of EasyGraphicsView public: - ProfGraphicsItem(unsigned char _index, bool _test); - ProfGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root); - virtual ~ProfGraphicsItem(); + EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root); + virtual ~EasyGraphicsItem(); // Public virtual methods @@ -150,38 +146,37 @@ public: private: - ///< Returns pointer to the ProfGraphicsView widget. - const ProfGraphicsView* view() const; + ///< Returns pointer to the EasyGraphicsView widget. + const EasyGraphicsView* view() const; public: // Public inline methods - ///< Returns this item's index in the list of graphics items of ProfGraphicsView + ///< Returns this item's index in the list of graphics items of EasyGraphicsView inline unsigned char index() const { return m_index; } -}; // END of class ProfGraphicsItem. +}; // END of class EasyGraphicsItem. ////////////////////////////////////////////////////////////////////////// -class ProfChronometerItem : public QGraphicsItem +class EasyChronometerItem : public QGraphicsItem { - QFont m_font; ///< Font which is used to draw text QPolygonF m_indicator; ///< Indicator displayed when this chrono item is out of screen (displaying only for main item) QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem) QColor m_color; ///< Color of the item qreal m_left, m_right; ///< Left and right bounds of the selection zone bool m_bMain; ///< Is this chronometer main (true, by default) - bool m_bReverse; - bool m_bHover; ///< Mouse hover above indicator + bool m_bReverse; ///< + bool m_bHoverIndicator; ///< Mouse hover above indicator public: - ProfChronometerItem(bool _main = true); - virtual ~ProfChronometerItem(); + EasyChronometerItem(bool _main = true); + virtual ~EasyChronometerItem(); // Public virtual methods @@ -205,9 +200,9 @@ public: bool contains(const QPointF& _pos) const; - inline bool hover() const + inline bool hoverIndicator() const { - return m_bHover; + return m_bHoverIndicator; } inline bool reverse() const @@ -232,10 +227,10 @@ public: private: - ///< Returns pointer to the ProfGraphicsView widget. - const ProfGraphicsView* view() const; + ///< Returns pointer to the EasyGraphicsView widget. + const EasyGraphicsView* view() const; -}; // END of class ProfChronometerItem. +}; // END of class EasyChronometerItem. ////////////////////////////////////////////////////////////////////////// @@ -251,24 +246,24 @@ public: \ void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } \ } -EASY_QGRAPHICSITEM(ProfBackgroundItem); -EASY_QGRAPHICSITEM(ProfTimelineIndicatorItem); +EASY_QGRAPHICSITEM(EasyBackgroundItem); +EASY_QGRAPHICSITEM(EasyTimelineIndicatorItem); #undef EASY_QGRAPHICSITEM ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsView : public QGraphicsView +class EasyGraphicsView : public QGraphicsView { Q_OBJECT private: - typedef ProfGraphicsView This; - typedef ::std::vector Items; + typedef EasyGraphicsView This; + typedef ::std::vector Items; - Items m_items; ///< Array of all ProfGraphicsItem items - ::profiler_gui::TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (ProfChronometerItem) + Items m_items; ///< Array of all EasyGraphicsItem items + ::profiler_gui::TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (EasyChronometerItem) QTimer m_flickerTimer; ///< Timer for flicking behavior QRectF m_visibleSceneRect; ///< Visible scene rectangle ::profiler::timestamp_t m_beginTime; ///< Begin time of profiler session. Used to reduce values of all begin and end times of profiler blocks. @@ -278,20 +273,19 @@ private: QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent) QPoint m_mouseMovePath; ///< Mouse move path between press and release of any button Qt::MouseButtons m_mouseButtons; ///< Pressed mouse buttons - ProfGraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget - ProfChronometerItem* m_chronometerItem; ///< Pointer to the ProfChronometerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget. - ProfChronometerItem* m_chronometerItemAux; ///< Pointer to the ProfChronometerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time. + EasyGraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget + EasyChronometerItem* m_chronometerItem; ///< Pointer to the EasyChronometerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget. + EasyChronometerItem* m_chronometerItemAux; ///< Pointer to the EasyChronometerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time. int m_flickerSpeedX; ///< Current flicking speed x int m_flickerSpeedY; ///< Current flicking speed y bool m_bDoubleClick; ///< Is mouse buttons double clicked bool m_bUpdatingRect; ///< Stub flag which is used to avoid excess calculations on some scene update (flicking, scaling and so on) - bool m_bTest; ///< Testing flag (true when test() is called) bool m_bEmpty; ///< Indicates whether scene is empty and has no items public: - ProfGraphicsView(QWidget* _parent = nullptr); - virtual ~ProfGraphicsView(); + EasyGraphicsView(QWidget* _parent = nullptr); + virtual ~EasyGraphicsView(); // Public virtual methods @@ -306,10 +300,9 @@ public: // Public non-virtual methods - void setScrollbar(ProfGraphicsScrollbar* _scrollbar); + void setScrollbar(EasyGraphicsScrollbar* _scrollbar); void clearSilent(); - void test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows); void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree); const Items& getItems() const; @@ -324,15 +317,14 @@ private: // Private non-virtual methods - ProfChronometerItem* createChronometer(bool _main = true); - bool moveChrono(ProfChronometerItem* _chronometerItem, qreal _mouseX); + EasyChronometerItem* createChronometer(bool _main = true); + bool moveChrono(EasyChronometerItem* _chronometerItem, qreal _mouseX); void initMode(); void updateVisibleSceneRect(); void updateTimelineStep(qreal _windowWidth); void updateScene(); void scaleTo(qreal _scale); - qreal setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level); - void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, unsigned int _childrenNumber, unsigned int& _total_items); + qreal setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level); private slots: @@ -343,6 +335,7 @@ private slots: void onFlickerTimeout(); void onSelectedThreadChange(::profiler::thread_id_t _id); void onSelectedBlockChange(unsigned int _block_index); + void onItemsEspandStateChange(); public: @@ -384,53 +377,53 @@ private: //return PROF_FROM_MILLISECONDS(_pos); } -}; // END of class ProfGraphicsView. +}; // END of class EasyGraphicsView. -class ProfThreadViewWidget : public QWidget +////////////////////////////////////////////////////////////////////////// + +class EasyThreadViewWidget : public QWidget { Q_OBJECT private: - ProfGraphicsView* m_view; + EasyGraphicsView* m_view; QLabel* m_label; - typedef ProfThreadViewWidget This; + typedef EasyThreadViewWidget This; QHBoxLayout *m_layout; public: - ProfThreadViewWidget(QWidget *parent, ProfGraphicsView* view); - virtual ~ProfThreadViewWidget(); + EasyThreadViewWidget(QWidget *parent, EasyGraphicsView* view); + virtual ~EasyThreadViewWidget(); public slots: void onSelectedThreadChange(::profiler::thread_id_t _id); }; - ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsViewWidget : public QWidget +class EasyGraphicsViewWidget : public QWidget { Q_OBJECT private: - ProfGraphicsView* m_view; - ProfGraphicsScrollbar* m_scrollbar; - //ProfThreadViewWidget* m_threadWidget; + EasyGraphicsView* m_view; + EasyGraphicsScrollbar* m_scrollbar; + //EasyThreadViewWidget* m_threadWidget; public: - ProfGraphicsViewWidget(QWidget* _parent = nullptr); - virtual ~ProfGraphicsViewWidget(); + EasyGraphicsViewWidget(QWidget* _parent = nullptr); + virtual ~EasyGraphicsViewWidget(); - ProfGraphicsView* view(); + EasyGraphicsView* view(); private: void initWidget(); -}; // END of class ProfGraphicsViewWidget. - +}; // END of class EasyGraphicsViewWidget. ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -#endif // MY____GRAPHICS___VIEW_H +#endif // EASY__GRAPHICS_VIEW__H_ diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 1cc52bc..74cf71e 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -6,7 +6,7 @@ * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : -* description : The file contains implementation of TreeWidget and it's auxiliary classes +* description : The file contains implementation of EasyTreeWidget and it's auxiliary classes * : for displyaing easy_profiler blocks tree. * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: Moved sources from tree_view.h @@ -19,21 +19,22 @@ * : * : * 2016/06/29 Victor Zarubkin: Added clearSilent() method. * : -* : * +* : * 2016/08/18 Victor Zarubkin: Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp * ----------------- : * license : TODO: add license text ************************************************************************/ -#include #include #include #include #include -#include +#include +#include +#include #include "blocks_tree_widget.h" +#include "tree_widget_item.h" #include "globals.h" - #ifdef max #undef max #endif @@ -44,216 +45,7 @@ ////////////////////////////////////////////////////////////////////////// -enum ColumnsIndexes -{ - COL_UNKNOWN = -1, - - COL_NAME = 0, - - COL_BEGIN, - - COL_DURATION, - COL_SELF_DURATION, - COL_DURATION_SUM_PER_PARENT, - COL_DURATION_SUM_PER_FRAME, - COL_DURATION_SUM_PER_THREAD, - - COL_SELF_DURATION_PERCENT, - COL_PERCENT_PER_PARENT, - COL_PERCENT_PER_FRAME, - COL_PERCENT_SUM_PER_PARENT, - COL_PERCENT_SUM_PER_FRAME, - COL_PERCENT_SUM_PER_THREAD, - - COL_END, - - COL_MIN_PER_FRAME, - COL_MAX_PER_FRAME, - COL_AVERAGE_PER_FRAME, - COL_NCALLS_PER_FRAME, - - COL_MIN_PER_THREAD, - COL_MAX_PER_THREAD, - COL_AVERAGE_PER_THREAD, - COL_NCALLS_PER_THREAD, - - COL_MIN_PER_PARENT, - COL_MAX_PER_PARENT, - COL_AVERAGE_PER_PARENT, - COL_NCALLS_PER_PARENT, - - COL_COLUMNS_NUMBER -}; - -////////////////////////////////////////////////////////////////////////// - -ProfTreeWidgetItem::ProfTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent) - : Parent(_parent) - , m_block(_treeBlock) - , m_customBGColor(0) - , m_customTextColor(0) -{ - -} - -ProfTreeWidgetItem::~ProfTreeWidgetItem() -{ -} - -bool ProfTreeWidgetItem::operator < (const Parent& _other) const -{ - const auto col = treeWidget()->sortColumn(); - - switch (col) - { - //case COL_UNKNOWN: - case COL_NAME: - { - if (parent() == nullptr) - return false; // Do not sort topLevelItems by name - return Parent::operator < (_other); - } - - case COL_NCALLS_PER_THREAD: - case COL_NCALLS_PER_PARENT: - case COL_NCALLS_PER_FRAME: - { - return data(col, Qt::UserRole).toUInt() < _other.data(col, Qt::UserRole).toUInt(); - } - - case COL_SELF_DURATION_PERCENT: - case COL_PERCENT_PER_PARENT: - case COL_PERCENT_PER_FRAME: - case COL_PERCENT_SUM_PER_PARENT: - case COL_PERCENT_SUM_PER_FRAME: - case COL_PERCENT_SUM_PER_THREAD: - { - return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt(); - } - - default: - { - // durations min, max, average - return data(col, Qt::UserRole).toULongLong() < _other.data(col, Qt::UserRole).toULongLong(); - } - } - - return false; -} - -const ::profiler::BlocksTree* ProfTreeWidgetItem::block() const -{ - return m_block; -} - -::profiler::timestamp_t ProfTreeWidgetItem::duration() const -{ - if (m_block->node) - return m_block->node->block()->duration(); - return data(COL_DURATION, Qt::UserRole).toULongLong(); -} - -::profiler::timestamp_t ProfTreeWidgetItem::selfDuration() const -{ - return data(COL_SELF_DURATION, Qt::UserRole).toULongLong(); -} - -void ProfTreeWidgetItem::setTimeSmart(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix) -{ - const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time); - - setData(_column, Qt::UserRole, (quint64)nanosecondsTime); - - setToolTip(_column, QString("%1 ns").arg(nanosecondsTime)); - - if (_time < 1e3) - { - setText(_column, QString("%1%2 ns").arg(_prefix).arg(nanosecondsTime)); - } - else if (_time < 1e6) - { - setText(_column, QString("%1%2 us").arg(_prefix).arg(double(nanosecondsTime) * 1e-3, 0, 'f', 3)); - } - else if (_time < 1e9) - { - setText(_column, QString("%1%2 ms").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'f', 3)); - } - else - { - setText(_column, QString("%1%2 s").arg(_prefix).arg(double(nanosecondsTime) * 1e-9, 0, 'f', 3)); - } -} - -void ProfTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time) -{ - const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time); - setData(_column, Qt::UserRole, (quint64)nanosecondsTime); - setToolTip(_column, QString("%1 ns").arg(nanosecondsTime)); - setText(_column, QString::number(double(nanosecondsTime) * 1e-6, 'g', 9)); -} - -void ProfTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix) -{ - const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time); - setData(_column, Qt::UserRole, (quint64)nanosecondsTime); - setToolTip(_column, QString("%1 ns").arg(nanosecondsTime)); - setText(_column, QString("%1%2").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'g', 9)); -} - -void ProfTreeWidgetItem::setBackgroundColor(QRgb _color) -{ - m_customBGColor = _color; -} - -void ProfTreeWidgetItem::setTextColor(QRgb _color) -{ - m_customTextColor = _color; -} - -void ProfTreeWidgetItem::colorize(bool _colorize) -{ - if (_colorize) - { - for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) - { - setBackground(i, QColor::fromRgb(m_customBGColor)); - setForeground(i, QColor::fromRgb(m_customTextColor)); - } - } - else - { - const QBrush nobrush; - for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) - { - setBackground(i, nobrush); - setForeground(i, nobrush); - } - } -} - -void ProfTreeWidgetItem::collapseAll() -{ - for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i) - { - static_cast(child(i))->collapseAll(); - } - - setExpanded(false); -} - -void ProfTreeWidgetItem::expandAll() -{ - for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i) - { - static_cast(child(i))->expandAll(); - } - - setExpanded(true); -} - -////////////////////////////////////////////////////////////////////////// - -ProfTreeWidget::ProfTreeWidget(QWidget* _parent) : Parent(_parent), m_beginTime(::std::numeric_limits::max()), m_bColorRows(true) +EasyTreeWidget::EasyTreeWidget(QWidget* _parent) : Parent(_parent), m_beginTime(::std::numeric_limits::max()), m_progress(nullptr), m_bColorRows(true), m_bLocked(false) { setAutoFillBackground(false); setAlternatingRowColors(true); @@ -301,33 +93,100 @@ ProfTreeWidget::ProfTreeWidget(QWidget* _parent) : Parent(_parent), m_beginTime( setHeaderItem(header); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::ProfGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); - connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::ProfGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); + connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); + connect(&m_fillTimer, &QTimer::timeout, this, &This::onFillTimerTimeout); loadSettings(); + + m_progress = new QProgressDialog("Building blocks hierarchy...", "", 0, 100, this, Qt::FramelessWindowHint); + m_progress->setAttribute(Qt::WA_TranslucentBackground); + m_progress->setCancelButton(nullptr); + m_progress->hide(); + + QTimer::singleShot(40, this, &This::alignProgressBar); } -ProfTreeWidget::~ProfTreeWidget() +EasyTreeWidget::~EasyTreeWidget() { saveSettings(); + delete m_progress; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree) +void EasyTreeWidget::onFillTimerTimeout() +{ + if (m_hierarchyBuilder.done()) + { + m_fillTimer.stop(); + + ThreadedItems toplevelitems; + m_hierarchyBuilder.takeItems(m_items); + m_hierarchyBuilder.takeTopLevelItems(toplevelitems); + m_hierarchyBuilder.interrupt(); + { + const QSignalBlocker b(this); + for (auto& item : toplevelitems) + { + addTopLevelItem(item.second); + m_roots[item.first] = item.second; + } + } + + if (m_progress) + { + m_progress->setValue(100); + m_progress->hide(); + } + + m_bLocked = false; + m_inputBlocks.clear(); + + setSortingEnabled(true); + sortByColumn(COL_BEGIN, Qt::AscendingOrder); + resizeColumnToContents(COL_NAME); + + connect(this, &Parent::itemExpanded, this, &This::onItemExpand); + connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); + onSelectedThreadChange(::profiler_gui::EASY_GLOBALS.selected_thread); + onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); + } + else + { + m_progress->setValue(m_hierarchyBuilder.progress()); + } +} + +void EasyTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree) { clearSilent(); - setTreeInternal(_blocksNumber, _blocksTree); + if (!_blocksTree.empty()) + { + m_bLocked = true; + m_progress->setValue(0); + m_progress->show(); + m_hierarchyBuilder.fillTree(m_beginTime, _blocksNumber, _blocksTree, m_bColorRows); + m_fillTimer.start(20); + } - setSortingEnabled(true); - sortByColumn(COL_BEGIN, Qt::AscendingOrder); - resizeColumnToContents(COL_NAME); - - connect(this, &Parent::itemExpanded, this, &This::onItemExpand); + //StubLocker l; + //ThreadedItems toplevelitems; + //FillTreeClass::setTreeInternal1(l, m_items, toplevelitems, m_beginTime, _blocksNumber, _blocksTree, m_bColorRows); + //{ + // const QSignalBlocker b(this); + // for (auto& item : toplevelitems) + // { + // addTopLevelItem(item.second); + // m_roots[item.first] = item.second; + // if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread) + // item.second->colorize(true); + // } + //} } -void ProfTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict) +void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict) { clearSilent(); @@ -335,30 +194,65 @@ void ProfTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, :: _left += m_beginTime;// - ::std::min(m_beginTime, 1000ULL); _right += m_beginTime;// + 1000; - setTreeInternal(_blocks, _left, _right, _strict); + m_inputBlocks = _blocks; + if (!m_inputBlocks.empty()) + { + m_bLocked = true; + m_progress->setValue(0); + m_progress->show(); + m_hierarchyBuilder.fillTreeBlocks(m_inputBlocks, _session_begin_time, _left, _right, _strict, m_bColorRows); + m_fillTimer.start(20); + } - setSortingEnabled(true); - sortByColumn(COL_BEGIN, Qt::AscendingOrder); - resizeColumnToContents(COL_NAME); + //StubLocker l; + //ThreadedItems toplevelitems; + //FillTreeClass::setTreeInternal2(l, m_items, toplevelitems, m_beginTime, _blocks, _left, _right, _strict, m_bColorRows); + //{ + // const QSignalBlocker b(this); + // for (auto& item : toplevelitems) + // { + // addTopLevelItem(item.second); + // m_roots[item.first] = item.second; + // if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread) + // item.second->colorize(true); + // } + //} - connect(this, &Parent::itemExpanded, this, &This::onItemExpand); - onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); + //setSortingEnabled(true); + //sortByColumn(COL_BEGIN, Qt::AscendingOrder); + //resizeColumnToContents(COL_NAME); + + //connect(this, &Parent::itemExpanded, this, &This::onItemExpand); + //connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); + //onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::clearSilent(bool _global) +void EasyTreeWidget::clearSilent(bool _global) { + m_hierarchyBuilder.interrupt(); + + if (m_progress) + { + m_progress->setValue(100); + m_progress->hide(); + } + + m_bLocked = false; m_beginTime = ::std::numeric_limits::max(); setSortingEnabled(false); disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand); + disconnect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); if (!_global) { for (auto item : m_items) { - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item); + auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index]; + ::profiler_gui::set_max(gui_block.tree_item); + gui_block.expanded = false; } } @@ -367,459 +261,23 @@ void ProfTreeWidget::clearSilent(bool _global) const QSignalBlocker b(this); clear(); + + if (!_global) + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// -size_t ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree) +void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) { - m_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks - - decltype(m_beginTime) finishtime = 0; - for (const auto& threadTree : _blocksTree) + if (m_bLocked) { - const auto node_block = threadTree.second.tree.children.front().node->block(); - const auto startTime = node_block->getBegin(); - const auto endTime = node_block->getEnd(); - - if (m_beginTime > startTime) - { - m_beginTime = startTime; - } - - if (finishtime < endTime) - { - finishtime = endTime; - } + _event->accept(); + return; } - size_t total_items = 0; - const QSignalBlocker b(this); - for (const auto& threadTree : _blocksTree) - { - auto& block = threadTree.second.tree; - auto item = new ProfTreeWidgetItem(&block); - - if (threadTree.second.thread_name && threadTree.second.thread_name[0] != 0) - { - item->setText(COL_NAME, QString("%1 Thread %2").arg(threadTree.second.thread_name).arg(threadTree.first)); - } - else - { - item->setText(COL_NAME, QString("Thread %1").arg(threadTree.first)); - } - - ::profiler::timestamp_t duration = 0; - if (!block.children.empty()) - { - duration = block.children.back().node->block()->getEnd() - block.children.front().node->block()->getBegin(); - } - - item->setTimeSmart(COL_DURATION, duration); - item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); - item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); - m_items.push_back(item); - - // TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now) - ::profiler::timestamp_t children_duration = 0; - for (const auto& child : block.children) - children_duration += child.node->block()->duration(); - item->setTimeSmart(COL_SELF_DURATION, children_duration); - - children_duration = 0; - const auto children_items_number = setTreeInternal(block.children, item, nullptr, item, m_beginTime, finishtime + 1000000000ULL, false, children_duration); - - if (children_items_number > 0) - { - total_items += children_items_number + 1; - addTopLevelItem(item); - - if (threadTree.first == ::profiler_gui::EASY_GLOBALS.selected_thread) - { - item->colorize(true); - } - - m_roots[threadTree.first] = item; - } - else - { - m_items.pop_back(); - delete item; - } - } - - return total_items; -} - -auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size()) -{ - auto children_number = _tree->children.size(); - for (const auto& child : _tree->children) - children_number += calculateTotalChildrenNumber(&child); - return children_number; -} - -size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict) -{ - if (_blocks.empty()) - { - return 0; - } - - //size_t blocksNumber = 0; - //for (const auto& block : _blocks) - // blocksNumber += calculateTotalChildrenNumber(block.tree); - // //blocksNumber += block.tree->total_children_number; - //m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks - - typedef ::std::unordered_map<::profiler::thread_id_t, ProfTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> ThreadsMap; - ThreadsMap threadsMap; - - size_t total_items = 0; - const QSignalBlocker b(this); - for (const auto& block : _blocks) - { - const auto startTime = block.tree->node->block()->getBegin(); - const auto endTime = block.tree->node->block()->getEnd(); - if (startTime > _right || endTime < _left) - { - continue; - } - - ::profiler::timestamp_t duration = 0; - ProfTreeWidgetItem* thread_item = nullptr; - auto thread_item_it = threadsMap.find(block.root->thread_id); - if (thread_item_it != threadsMap.end()) - { - thread_item = thread_item_it->second; - } - else - { - thread_item = new ProfTreeWidgetItem(&block.root->tree); - - if (block.root->thread_name && block.root->thread_name[0] != 0) - { - thread_item->setText(COL_NAME, QString("%1 Thread %2").arg(block.root->thread_name).arg(block.root->thread_id)); - } - else - { - thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id)); - } - - if (!block.root->tree.children.empty()) - { - duration = block.root->tree.children.back().node->block()->getEnd() - block.root->tree.children.front().node->block()->getBegin(); - } - - thread_item->setTimeSmart(COL_DURATION, duration); - thread_item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); - thread_item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); - - // Calculate clean duration (sum of all children durations) - ::profiler::timestamp_t children_duration = 0; - for (const auto& child : block.root->tree.children) - children_duration += child.node->block()->duration(); - thread_item->setTimeSmart(COL_SELF_DURATION, children_duration); - - threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item)); - } - - auto item = new ProfTreeWidgetItem(block.tree, thread_item); - duration = endTime - startTime; - - item->setText(COL_NAME, ::profiler_gui::toUnicode(block.tree->node->getName())); - item->setTimeSmart(COL_DURATION, duration); - item->setTimeMs(COL_BEGIN, startTime - m_beginTime); - item->setTimeMs(COL_END, endTime - m_beginTime); - - item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_PARENT, ""); - - item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_FRAME, ""); - - if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also - { - const auto& per_thread_stats = block.tree->per_thread_stats; - const auto& per_parent_stats = block.tree->per_parent_stats; - const auto& per_frame_stats = block.tree->per_frame_stats; - - - if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); - item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); - - auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(thread_item->selfDuration())); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); - item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); - - - if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); - item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); - - - if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); - item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); - } - else - { - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_THREAD, ""); - } - - const auto color = block.tree->node->block()->getColor(); - const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - const auto fgColor = 0x00ffffff - bgColor; - item->setBackgroundColor(bgColor); - item->setTextColor(fgColor); - - m_items.push_back(item); - - size_t children_items_number = 0; - ::profiler::timestamp_t children_duration = 0; - if (!block.tree->children.empty()) - { - children_items_number = setTreeInternal(block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration); - } - - int percentage = 100; - auto self_duration = duration - children_duration; - if (children_duration > 0 && duration > 0) - { - percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); - } - - item->setTimeSmart(COL_SELF_DURATION, self_duration); - item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); - item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); - - if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) - { - total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = static_cast(m_items.size() - 1); - - if (m_bColorRows) - { - item->colorize(m_bColorRows); - } - } - else - { - m_items.pop_back(); - delete item; - } - } - - for (auto& it : threadsMap) - { - auto item = it.second; - - if (item->childCount() > 0) - { - addTopLevelItem(item); - - if (it.first == ::profiler_gui::EASY_GLOBALS.selected_thread) - { - item->colorize(true); - } - - m_roots[it.first] = item; - m_items.push_back(item); - ++total_items; - } - else - { - delete item; - } - } - - return total_items; -} - -size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ProfTreeWidgetItem* _frame, ProfTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration) -{ - size_t total_items = 0; - for (const auto& child : _children) - { - const auto startTime = child.node->block()->getBegin(); - const auto endTime = child.node->block()->getEnd(); - const auto duration = endTime - startTime; - _duration += duration; - - if (startTime > _right || endTime < _left) - { - continue; - } - - auto item = new ProfTreeWidgetItem(&child, _parent); - item->setText(COL_NAME, ::profiler_gui::toUnicode(child.node->getName())); - item->setTimeSmart(COL_DURATION, duration); - item->setTimeMs(COL_BEGIN, startTime - m_beginTime); - item->setTimeMs(COL_END, endTime - m_beginTime); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); - - if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also - { - const auto& per_thread_stats = child.per_thread_stats; - const auto& per_parent_stats = child.per_parent_stats; - const auto& per_frame_stats = child.per_frame_stats; - - auto percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_parent->duration())); - auto percentage_sum = static_cast(0.5 + 100. * static_cast(per_parent_stats->total_duration) / static_cast(_parent->duration())); - item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage); - item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage)); - item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum); - item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum)); - - if (_frame != nullptr) - { - if (_parent != _frame) - { - percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_frame->duration())); - percentage_sum = static_cast(0.5 + 100. * static_cast(per_frame_stats->total_duration) / static_cast(_frame->duration())); - } - - item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage); - item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage)); - item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum); - item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum)); - } - else - { - item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_FRAME, ""); - item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_FRAME, ""); - } - - - if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); - item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); - - if (_thread) - { - auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(_thread->selfDuration())); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); - item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); - } - - - if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); - item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); - - - if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) - { - item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); - item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); - item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); - item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); - } - - item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); - item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); - } - else - { - item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); - item->setText(COL_PERCENT_PER_PARENT, ""); - item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_PARENT, ""); - item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); - item->setText(COL_PERCENT_SUM_PER_THREAD, ""); - } - - const auto color = child.node->block()->getColor(); - const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); - const auto fgColor = 0x00ffffff - bgColor; - item->setBackgroundColor(bgColor); - item->setTextColor(fgColor); - - m_items.push_back(item); - - size_t children_items_number = 0; - ::profiler::timestamp_t children_duration = 0; - if (!child.children.empty()) - { - children_items_number = setTreeInternal(child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration); - } - - int percentage = 100; - auto self_duration = duration - children_duration; - if (children_duration > 0 && duration > 0) - { - percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); - } - - item->setTimeSmart(COL_SELF_DURATION, self_duration); - item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); - item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); - - if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) - { - total_items += children_items_number + 1; - ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = static_cast(m_items.size() - 1); - - if (m_bColorRows) - { - item->colorize(m_bColorRows); - } - } - else - { - m_items.pop_back(); - delete item; - } - } - - return total_items; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) -{ const auto col = currentColumn(); - auto item = static_cast(currentItem()); + auto item = static_cast(currentItem()); QMenu menu; auto action = new QAction("Expand all", nullptr); @@ -853,9 +311,9 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) if (item != nullptr) { - auto itemAction = new ProfItemAction("Show this item on scene", item->block()->block_index); + auto itemAction = new EasyItemAction("Show this item on scene", item->block()->block_index); itemAction->setToolTip("Scroll graphics scene to current item in the tree"); - connect(itemAction, &ProfItemAction::clicked, this, &This::onJumpToItemClicked); + connect(itemAction, &EasyItemAction::clicked, this, &This::onJumpToItemClicked); menu.addAction(itemAction); if (col >= 0) @@ -884,9 +342,9 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) if (i != ::profiler_gui::numeric_max(i)) { menu.addSeparator(); - itemAction = new ProfItemAction("Jump to such item", i); + itemAction = new EasyItemAction("Jump to such item", i); itemAction->setToolTip("Jump to item with min/max duration (depending on clicked column)"); - connect(itemAction, &ProfItemAction::clicked, this, &This::onJumpToItemClicked); + connect(itemAction, &EasyItemAction::clicked, this, &This::onJumpToItemClicked); menu.addAction(itemAction); } @@ -903,10 +361,10 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) { - auto columnAction = new ProfHideShowColumnAction(hdr->text(i), i); + auto columnAction = new EasyHideShowColumnAction(hdr->text(i), i); columnAction->setCheckable(true); columnAction->setChecked(!isColumnHidden(i)); - connect(columnAction, &ProfHideShowColumnAction::clicked, this, &This::onHideShowColumn); + connect(columnAction, &EasyHideShowColumnAction::clicked, this, &This::onHideShowColumn); hidemenu->addAction(columnAction); } @@ -915,57 +373,92 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event) _event->accept(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::onJumpToItemClicked(unsigned int _block_index) +void EasyTreeWidget::resizeEvent(QResizeEvent* _event) +{ + Parent::resizeEvent(_event); + alignProgressBar(); +} + +void EasyTreeWidget::moveEvent(QMoveEvent* _event) +{ + Parent::moveEvent(_event); + alignProgressBar(); +} + +void EasyTreeWidget::alignProgressBar() +{ + auto pos = mapToGlobal(rect().center()); + m_progress->move(pos.x() - (m_progress->width() >> 1), pos.y() - (m_progress->height() >> 1)); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyTreeWidget::onJumpToItemClicked(unsigned int _block_index) { ::profiler_gui::EASY_GLOBALS.selected_block = _block_index; emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(_block_index); } -void ProfTreeWidget::onCollapseAllClicked(bool) +void EasyTreeWidget::onCollapseAllClicked(bool) { + const QSignalBlocker b(this); collapseAll(); + + for (auto item : m_items) + ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = false; + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } -void ProfTreeWidget::onExpandAllClicked(bool) +void EasyTreeWidget::onExpandAllClicked(bool) { - disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand); + const QSignalBlocker b(this); expandAll(); - //resizeColumnToContents(COL_NAME); resizeColumnsToContents(); - connect(this, &Parent::itemExpanded, this, &This::onItemExpand); + + for (auto item : m_items) + ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = true; + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } -void ProfTreeWidget::onCollapseAllChildrenClicked(bool) +void EasyTreeWidget::onCollapseAllChildrenClicked(bool) { - auto current = static_cast(currentItem()); + auto current = static_cast(currentItem()); if (current != nullptr) { + const QSignalBlocker b(this); current->collapseAll(); + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } } -void ProfTreeWidget::onExpandAllChildrenClicked(bool) +void EasyTreeWidget::onExpandAllChildrenClicked(bool) { - auto current = static_cast(currentItem()); + auto current = static_cast(currentItem()); if (current != nullptr) { - disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand); + const QSignalBlocker b(this); current->expandAll(); - //resizeColumnToContents(COL_NAME); resizeColumnsToContents(); - connect(this, &Parent::itemExpanded, this, &This::onItemExpand); + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } } -void ProfTreeWidget::onItemExpand(QTreeWidgetItem*) +void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item) { - //resizeColumnToContents(COL_NAME); resizeColumnsToContents(); + ::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast(_item)->block()->block_index].expanded = true; + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); } -void ProfTreeWidget::onColorizeRowsTriggered(bool _colorize) +void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item) +{ + ::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast(_item)->block()->block_index].expanded = false; + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); +} + +void EasyTreeWidget::onColorizeRowsTriggered(bool _colorize) { const QSignalBlocker b(this); @@ -991,7 +484,7 @@ void ProfTreeWidget::onColorizeRowsTriggered(bool _colorize) ////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::onSelectedThreadChange(::profiler::thread_id_t _id) +void EasyTreeWidget::onSelectedThreadChange(::profiler::thread_id_t _id) { for (auto& it : m_roots) { @@ -999,9 +492,9 @@ void ProfTreeWidget::onSelectedThreadChange(::profiler::thread_id_t _id) } } -void ProfTreeWidget::onSelectedBlockChange(unsigned int _block_index) +void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index) { - ProfTreeWidgetItem* item = nullptr; + EasyTreeWidgetItem* item = nullptr; if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) { @@ -1011,13 +504,25 @@ void ProfTreeWidget::onSelectedBlockChange(unsigned int _block_index) } if (item != nullptr) + { + const QSignalBlocker b(this); + expandItem(item); + setCurrentItem(item); scrollToItem(item, QAbstractItemView::PositionAtCenter); - setCurrentItem(item); + resizeColumnsToContents(); + + ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = true; + emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); + } + else + { + setCurrentItem(item); + } } ////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::resizeColumnsToContents() +void EasyTreeWidget::resizeColumnsToContents() { for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) { @@ -1027,7 +532,7 @@ void ProfTreeWidget::resizeColumnsToContents() ////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::onHideShowColumn(int _column) +void EasyTreeWidget::onHideShowColumn(int _column) { if (isColumnHidden(_column)) { @@ -1041,7 +546,7 @@ void ProfTreeWidget::onHideShowColumn(int _column) ////////////////////////////////////////////////////////////////////////// -void ProfTreeWidget::loadSettings() +void EasyTreeWidget::loadSettings() { QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); settings.beginGroup("tree_widget"); @@ -1059,7 +564,7 @@ void ProfTreeWidget::loadSettings() settings.endGroup(); } -void ProfTreeWidget::saveSettings() +void EasyTreeWidget::saveSettings() { QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); settings.beginGroup("tree_widget"); diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index 7be18a1..2b428d7 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -6,8 +6,8 @@ * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : -* description : The file contains declaration of TreeWidget and it's auxiliary classes -* : for displyaing easy_profiler blocks tree. +* description : The file contains declaration of EasyTreeWidget and it's auxiliary classes +* : for displyaing EasyProfiler blocks tree. * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: moved sources from tree_view.h * : and renamed classes from My* to Prof*. @@ -17,66 +17,20 @@ * : * : * 2016/06/29 Victor Zarubkin: Added clearSilent() method. * : -* : * +* : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread; +* : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp * ----------------- : * license : TODO: add license text ************************************************************************/ -#ifndef MY____TREE___VIEW_H -#define MY____TREE___VIEW_H +#ifndef EASY__TREE_WIDGET__H_ +#define EASY__TREE_WIDGET__H_ #include #include -#include -#include -#include +#include +#include "tree_widget_loader.h" #include "profiler/reader.h" -#include "common_types.h" - -////////////////////////////////////////////////////////////////////////// - -class ProfTreeWidgetItem : public QTreeWidgetItem -{ - typedef QTreeWidgetItem Parent; - typedef ProfTreeWidgetItem This; - - const ::profiler::BlocksTree* m_block; - QRgb m_customBGColor; - QRgb m_customTextColor; - -public: - - using Parent::setBackgroundColor; - using Parent::setTextColor; - - ProfTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr); - virtual ~ProfTreeWidgetItem(); - - bool operator < (const Parent& _other) const override; - -public: - - const ::profiler::BlocksTree* block() const; - - ::profiler::timestamp_t duration() const; - ::profiler::timestamp_t selfDuration() const; - - void setTimeSmart(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix = ""); - - void setTimeMs(int _column, const ::profiler::timestamp_t& _time); - void setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix); - - void setBackgroundColor(QRgb _color); - - void setTextColor(QRgb _color); - - void colorize(bool _colorize); - - void collapseAll(); - - void expandAll(); - -}; // END of class ProfTreeWidgetItem. ////////////////////////////////////////////////////////////////////////// @@ -90,38 +44,40 @@ public: \ connect(this, &QAction::triggered, this, &ClassName::onToggle); } \ ClassName(const QString& _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \ connect(this, &QAction::triggered, this, &ClassName::onToggle); } \ - virtual ~ClassName() {}\ + virtual ~ClassName() {} \ private: \ void onToggle(bool) { emit clicked(m_item); } -DECLARE_QACTION(ProfItemAction, unsigned int) signals: void clicked(unsigned int _item); }; -DECLARE_QACTION(ProfHideShowColumnAction, int) signals: void clicked(int _item); }; +DECLARE_QACTION(EasyItemAction, unsigned int) signals: void clicked(unsigned int _item); }; +DECLARE_QACTION(EasyHideShowColumnAction, int) signals: void clicked(int _item); }; #undef DECLARE_QACTION ////////////////////////////////////////////////////////////////////////// -class ProfTreeWidget : public QTreeWidget +class EasyTreeWidget : public QTreeWidget { Q_OBJECT typedef QTreeWidget Parent; - typedef ProfTreeWidget This; + typedef EasyTreeWidget This; protected: - typedef ::std::vector Items; - typedef ::std::unordered_map<::profiler::thread_id_t, ProfTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap; - - Items m_items; - RootsMap m_roots; - ::profiler::timestamp_t m_beginTime; - bool m_bColorRows; + EasyTreeWidgetLoader m_hierarchyBuilder; + Items m_items; + RootsMap m_roots; + ::profiler_gui::TreeBlocks m_inputBlocks; + QTimer m_fillTimer; + ::profiler::timestamp_t m_beginTime; + class QProgressDialog* m_progress; + bool m_bColorRows; + bool m_bLocked; public: - ProfTreeWidget(QWidget* _parent = nullptr); - virtual ~ProfTreeWidget(); + EasyTreeWidget(QWidget* _parent = nullptr); + virtual ~EasyTreeWidget(); void clearSilent(bool _global = false); @@ -133,13 +89,9 @@ public slots: protected: - size_t setTreeInternal(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree); - - size_t setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict); - - size_t setTreeInternal(const ::profiler::BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ProfTreeWidgetItem* _frame, ProfTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration); - void contextMenuEvent(QContextMenuEvent* _event) override; + void resizeEvent(QResizeEvent* _event) override; + void moveEvent(QMoveEvent* _event) override; private slots: @@ -153,7 +105,8 @@ private slots: void onExpandAllChildrenClicked(bool); - void onItemExpand(QTreeWidgetItem*); + void onItemExpand(QTreeWidgetItem* _item); + void onItemCollapse(QTreeWidgetItem* _item); void onColorizeRowsTriggered(bool _colorize); @@ -165,13 +118,16 @@ private slots: void onHideShowColumn(int _column); + void onFillTimerTimeout(); + protected: void loadSettings(); void saveSettings(); + void alignProgressBar(); -}; // END of class ProfTreeWidget. +}; // END of class EasyTreeWidget. ////////////////////////////////////////////////////////////////////////// -#endif // MY____TREE___VIEW_H +#endif // EASY__TREE_WIDGET__H_ diff --git a/profiler_gui/globals.cpp b/profiler_gui/globals.cpp index 8659e7b..61896c8 100644 --- a/profiler_gui/globals.cpp +++ b/profiler_gui/globals.cpp @@ -24,13 +24,13 @@ namespace profiler_gui { - ProfGlobals& ProfGlobals::instance() + EasyGlobals& EasyGlobals::instance() { - static ProfGlobals globals; + static EasyGlobals globals; return globals; } - ProfGlobals::ProfGlobals() + EasyGlobals::EasyGlobals() : selected_thread(0) , selected_block(-1) , draw_graphics_items_borders(true) diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index 424d0e1..26483d2 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -28,11 +28,6 @@ ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsItem; -class ProfTreeWidgetItem; - -////////////////////////////////////////////////////////////////////////// - namespace profiler_gui { const QString ORGANAZATION_NAME = "EasyProfiler"; @@ -45,16 +40,17 @@ namespace profiler_gui { ////////////////////////////////////////////////////////////////////////// #pragma pack(push, 1) - struct ProfBlock final + struct EasyBlock final { unsigned int tree_item; unsigned int graphics_item_index; unsigned char graphics_item_level; unsigned char graphics_item; + bool expanded; }; #pragma pack(pop) - typedef ::std::vector ProfBlocks; + typedef ::std::vector EasyBlocks; template inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString)) @@ -64,13 +60,13 @@ namespace profiler_gui { ////////////////////////////////////////////////////////////////////////// - struct ProfGlobals final + struct EasyGlobals final { - static ProfGlobals& instance(); + static EasyGlobals& instance(); - ProfGlobalSignals events; ///< Global signals + EasyGlobalSignals events; ///< Global signals ::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file - ProfBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI + EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI ::profiler::thread_id_t selected_thread; ///< Current selected thread id unsigned int selected_block; ///< Current selected profiler block index bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not @@ -78,10 +74,10 @@ namespace profiler_gui { private: - ProfGlobals(); + EasyGlobals(); }; #ifndef IGNORE_GLOBALS_DECLARATION - static ProfGlobals& EASY_GLOBALS = ProfGlobals::instance(); + static EasyGlobals& EASY_GLOBALS = EasyGlobals::instance(); #endif ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/globals_qobjects.cpp b/profiler_gui/globals_qobjects.cpp index b2770ba..3f9879f 100644 --- a/profiler_gui/globals_qobjects.cpp +++ b/profiler_gui/globals_qobjects.cpp @@ -6,7 +6,7 @@ * author : Victor Zarubkin * email : v.s.zarubkin@gmail.com * ----------------- : -* description : The file contains implementation of ProfGlobalSignals QObject class. +* description : The file contains implementation of EasyGlobalSignals QObject class. * ----------------- : * change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.cpp * : @@ -22,11 +22,11 @@ namespace profiler_gui { - ProfGlobalSignals::ProfGlobalSignals() : QObject() + EasyGlobalSignals::EasyGlobalSignals() : QObject() { } - ProfGlobalSignals::~ProfGlobalSignals() + EasyGlobalSignals::~EasyGlobalSignals() { } diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index 44349f5..aefa485 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -5,21 +5,24 @@ #include "profiler/profiler.h" namespace profiler_gui { - class ProfGlobalSignals final : public QObject + + class EasyGlobalSignals final : public QObject { Q_OBJECT public: - ProfGlobalSignals(); - virtual ~ProfGlobalSignals(); + EasyGlobalSignals(); + virtual ~EasyGlobalSignals(); signals: void selectedThreadChanged(::profiler::thread_id_t _id); void selectedBlockChanged(unsigned int _block_index); - }; + void itemsExpandStateChanged(); -} + }; // END of class EasyGlobalSignals. + +} // END of namespace profiler_gui. #endif // GLOBALS_QOBJECTS_H diff --git a/profiler_gui/graphics_scrollbar.cpp b/profiler_gui/graphics_scrollbar.cpp index 89bb732..256acb1 100644 --- a/profiler_gui/graphics_scrollbar.cpp +++ b/profiler_gui/graphics_scrollbar.cpp @@ -16,6 +16,7 @@ ************************************************************************/ #include +#include #include #include #include @@ -41,33 +42,33 @@ auto const clamp = [](qreal _minValue, qreal _value, qreal _maxValue) ////////////////////////////////////////////////////////////////////////// -ProfGraphicsSliderItem::ProfGraphicsSliderItem(bool _main) : Parent(), m_halfwidth(0) +EasyGraphicsSliderItem::EasyGraphicsSliderItem(bool _main) : Parent(), m_halfwidth(0) { - m_leftIndicator.reserve(3); - m_rightIndicator.reserve(3); - - const auto vcenter = DEFAULT_TOP + (_main ? INDICATOR_SIZE : DEFAULT_HEIGHT - INDICATOR_SIZE); - m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter - INDICATOR_SIZE)); - m_leftIndicator.push_back(QPointF(0, vcenter)); - m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter + INDICATOR_SIZE)); - - m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter - INDICATOR_SIZE)); - m_rightIndicator.push_back(QPointF(0, vcenter)); - m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter + INDICATOR_SIZE)); +// m_leftIndicator.reserve(3); +// m_rightIndicator.reserve(3); +// +// const auto vcenter = DEFAULT_TOP + (_main ? INDICATOR_SIZE : DEFAULT_HEIGHT - INDICATOR_SIZE); +// m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter - INDICATOR_SIZE)); +// m_leftIndicator.push_back(QPointF(0, vcenter)); +// m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter + INDICATOR_SIZE)); +// +// m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter - INDICATOR_SIZE)); +// m_rightIndicator.push_back(QPointF(0, vcenter)); +// m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter + INDICATOR_SIZE)); setWidth(1); setBrush(Qt::SolidPattern); } -ProfGraphicsSliderItem::~ProfGraphicsSliderItem() +EasyGraphicsSliderItem::~EasyGraphicsSliderItem() { } -void ProfGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +void EasyGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) { //Parent::paint(_painter, _option, _widget); - const auto currentScale = static_cast(scene()->parent())->getWindowScale(); + const auto currentScale = static_cast(scene()->parent())->getWindowScale(); const auto br = rect(); qreal w = width() * currentScale; @@ -80,59 +81,67 @@ void ProfGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphic } QRectF r(dx + br.left() * currentScale, br.top(), w, br.height()); + const auto r_right = r.right(); + const auto r_bottom = r.bottom(); + auto b = brush(); _painter->save(); _painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true); - _painter->setBrush(brush()); + _painter->setBrush(b); _painter->setPen(Qt::NoPen); _painter->drawRect(r); - if (w < INDICATOR_SIZE) - { - m_leftIndicator[0].setX(r.left() - INDICATOR_SIZE); - m_leftIndicator[1].setX(r.left()); - m_leftIndicator[2].setX(r.left() - INDICATOR_SIZE); + // Draw left and right borders + _painter->setPen(QColor::fromRgba(0xe0000000 | b.color().rgb())); + _painter->drawLine(QPointF(r.left(), r.top()), QPointF(r.left(), r_bottom)); + _painter->drawLine(QPointF(r_right, r.top()), QPointF(r_right, r_bottom)); - const auto r_right = r.right(); - m_rightIndicator[0].setX(r_right + INDICATOR_SIZE); - m_rightIndicator[1].setX(r_right); - m_rightIndicator[2].setX(r_right + INDICATOR_SIZE); - - _painter->drawPolygon(m_leftIndicator); - _painter->drawPolygon(m_rightIndicator); - } +// // Draw triangle indicators for small slider +// if (w < INDICATOR_SIZE) +// { +// m_leftIndicator[0].setX(r.left() - INDICATOR_SIZE); +// m_leftIndicator[1].setX(r.left()); +// m_leftIndicator[2].setX(r.left() - INDICATOR_SIZE); +// +// m_rightIndicator[0].setX(r_right + INDICATOR_SIZE); +// m_rightIndicator[1].setX(r_right); +// m_rightIndicator[2].setX(r_right + INDICATOR_SIZE); +// +// _painter->drawPolygon(m_leftIndicator); +// _painter->drawPolygon(m_rightIndicator); +// } _painter->restore(); } -qreal ProfGraphicsSliderItem::width() const +qreal EasyGraphicsSliderItem::width() const { return m_halfwidth * 2.0; } -qreal ProfGraphicsSliderItem::halfwidth() const +qreal EasyGraphicsSliderItem::halfwidth() const { return m_halfwidth; } -void ProfGraphicsSliderItem::setWidth(qreal _width) +void EasyGraphicsSliderItem::setWidth(qreal _width) { m_halfwidth = _width * 0.5; setRect(-m_halfwidth, DEFAULT_TOP, _width, DEFAULT_HEIGHT); } -void ProfGraphicsSliderItem::setHalfwidth(qreal _halfwidth) +void EasyGraphicsSliderItem::setHalfwidth(qreal _halfwidth) { m_halfwidth = _halfwidth; setRect(-m_halfwidth, DEFAULT_TOP, m_halfwidth * 2.0, DEFAULT_HEIGHT); } -void ProfGraphicsSliderItem::setColor(QRgb _color) +void EasyGraphicsSliderItem::setColor(QRgb _color) { setColor(QColor::fromRgba(_color)); } -void ProfGraphicsSliderItem::setColor(const QColor& _color) +void EasyGraphicsSliderItem::setColor(const QColor& _color) { auto b = brush(); b.setColor(_color); @@ -141,29 +150,29 @@ void ProfGraphicsSliderItem::setColor(const QColor& _color) ////////////////////////////////////////////////////////////////////////// -ProfMinimapItem::ProfMinimapItem() : Parent(), m_pSource(nullptr), m_maxDuration(0), m_minDuration(0), m_threadId(0) +EasyMinimapItem::EasyMinimapItem() : Parent(), m_pSource(nullptr), m_maxDuration(0), m_minDuration(0), m_threadId(0) { } -ProfMinimapItem::~ProfMinimapItem() +EasyMinimapItem::~EasyMinimapItem() { } -QRectF ProfMinimapItem::boundingRect() const +QRectF EasyMinimapItem::boundingRect() const { return m_boundingRect; } -void ProfMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) +void EasyMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) { if (m_pSource == nullptr) { return; } - const auto currentScale = static_cast(scene()->parent())->getWindowScale(); + const auto currentScale = static_cast(scene()->parent())->getWindowScale(); const auto bottom = m_boundingRect.bottom(); const auto coeff = m_boundingRect.height() / (m_maxDuration - m_minDuration); const auto heightRevert = 1.0 / m_boundingRect.height(); @@ -204,17 +213,17 @@ void ProfMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->restore(); } -::profiler::thread_id_t ProfMinimapItem::threadId() const +::profiler::thread_id_t EasyMinimapItem::threadId() const { return m_threadId; } -void ProfMinimapItem::setBoundingRect(const QRectF& _rect) +void EasyMinimapItem::setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } -void ProfMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items) +void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items) { m_pSource = _items; m_threadId = _thread_id; @@ -258,7 +267,7 @@ void ProfMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::prof ////////////////////////////////////////////////////////////////////////// -ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent) +EasyGraphicsScrollbar::EasyGraphicsScrollbar(QWidget* _parent) : Parent(_parent) , m_minimumValue(0) , m_maximumValue(500) @@ -287,20 +296,20 @@ ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent) selfScene->setSceneRect(0, DEFAULT_TOP, 500, DEFAULT_HEIGHT); setScene(selfScene); - m_slider = new ProfGraphicsSliderItem(true); + m_slider = new EasyGraphicsSliderItem(true); m_slider->setPos(0, 0); m_slider->setZValue(5); - m_slider->setColor(0x80e00000); + m_slider->setColor(0x40c0c0c0); selfScene->addItem(m_slider); - m_chronometerIndicator = new ProfGraphicsSliderItem(false); + m_chronometerIndicator = new EasyGraphicsSliderItem(false); m_chronometerIndicator->setPos(0, 0); m_chronometerIndicator->setZValue(10); m_chronometerIndicator->setColor(0x40000000 | ::profiler_gui::CHRONOMETER_COLOR.rgba()); selfScene->addItem(m_chronometerIndicator); m_chronometerIndicator->hide(); - m_minimap = new ProfMinimapItem(); + m_minimap = new EasyMinimapItem(); m_minimap->setPos(0, 0); m_minimap->setBoundingRect(selfScene->sceneRect()); selfScene->addItem(m_minimap); @@ -309,63 +318,63 @@ ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent) centerOn(0, 0); } -ProfGraphicsScrollbar::~ProfGraphicsScrollbar() +EasyGraphicsScrollbar::~EasyGraphicsScrollbar() { } ////////////////////////////////////////////////////////////////////////// -qreal ProfGraphicsScrollbar::getWindowScale() const +qreal EasyGraphicsScrollbar::getWindowScale() const { return m_windowScale; } -::profiler::thread_id_t ProfGraphicsScrollbar::minimapThread() const +::profiler::thread_id_t EasyGraphicsScrollbar::minimapThread() const { return m_minimap->threadId(); } -qreal ProfGraphicsScrollbar::minimum() const +qreal EasyGraphicsScrollbar::minimum() const { return m_minimumValue; } -qreal ProfGraphicsScrollbar::maximum() const +qreal EasyGraphicsScrollbar::maximum() const { return m_maximumValue; } -qreal ProfGraphicsScrollbar::range() const +qreal EasyGraphicsScrollbar::range() const { return m_maximumValue - m_minimumValue; } -qreal ProfGraphicsScrollbar::value() const +qreal EasyGraphicsScrollbar::value() const { return m_value; } -qreal ProfGraphicsScrollbar::sliderWidth() const +qreal EasyGraphicsScrollbar::sliderWidth() const { return m_slider->width(); } -qreal ProfGraphicsScrollbar::sliderHalfWidth() const +qreal EasyGraphicsScrollbar::sliderHalfWidth() const { return m_slider->halfwidth(); } ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::setValue(qreal _value) +void EasyGraphicsScrollbar::setValue(qreal _value) { m_value = clamp(m_minimumValue, _value, ::std::max(m_minimumValue, m_maximumValue - m_slider->width())); m_slider->setX(m_value + m_slider->halfwidth()); emit valueChanged(m_value); } -void ProfGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue) +void EasyGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue) { const auto oldRange = range(); const auto oldValue = oldRange < 1e-3 ? 0.0 : m_value / oldRange; @@ -380,7 +389,7 @@ void ProfGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue) onWindowWidthChange(width()); } -void ProfGraphicsScrollbar::setSliderWidth(qreal _width) +void EasyGraphicsScrollbar::setSliderWidth(qreal _width) { m_slider->setWidth(_width); setValue(m_value); @@ -388,25 +397,25 @@ void ProfGraphicsScrollbar::setSliderWidth(qreal _width) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::setChronoPos(qreal _left, qreal _right) +void EasyGraphicsScrollbar::setChronoPos(qreal _left, qreal _right) { m_chronometerIndicator->setWidth(_right - _left); m_chronometerIndicator->setX(_left + m_chronometerIndicator->halfwidth()); } -void ProfGraphicsScrollbar::showChrono() +void EasyGraphicsScrollbar::showChrono() { m_chronometerIndicator->show(); } -void ProfGraphicsScrollbar::hideChrono() +void EasyGraphicsScrollbar::hideChrono() { m_chronometerIndicator->hide(); } ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items) +void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items) { m_minimap->setSource(_thread_id, _items); scene()->update(); @@ -414,7 +423,7 @@ void ProfGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, c ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::mousePressEvent(QMouseEvent* _event) +void EasyGraphicsScrollbar::mousePressEvent(QMouseEvent* _event) { m_mouseButtons = _event->buttons(); @@ -429,7 +438,7 @@ void ProfGraphicsScrollbar::mousePressEvent(QMouseEvent* _event) //QGraphicsView::mousePressEvent(_event); } -void ProfGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event) +void EasyGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event) { m_mouseButtons = _event->buttons(); m_bScrolling = false; @@ -437,7 +446,7 @@ void ProfGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event) //QGraphicsView::mouseReleaseEvent(_event); } -void ProfGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event) +void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event) { if (m_mouseButtons & Qt::LeftButton) { @@ -452,14 +461,14 @@ void ProfGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event) } } -void ProfGraphicsScrollbar::resizeEvent(QResizeEvent* _event) +void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event) { onWindowWidthChange(_event->size().width()); } ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) +void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) { if (::profiler_gui::EASY_GLOBALS.profiler_blocks.empty()) { @@ -480,10 +489,10 @@ void ProfGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) label = ::std::move(QString("Thread %1").arg(it.first)); } - auto action = new ProfIdAction(label, it.first); + auto action = new EasyIdAction(label, it.first); action->setCheckable(true); action->setChecked(it.first == ::profiler_gui::EASY_GLOBALS.selected_thread); - connect(action, &ProfIdAction::clicked, this, &This::onThreadActionClicked); + connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked); menu.addAction(action); } @@ -494,7 +503,7 @@ void ProfGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id) +void EasyGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id) { if (_id != m_minimap->threadId()) { @@ -505,7 +514,7 @@ void ProfGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id) ////////////////////////////////////////////////////////////////////////// -void ProfGraphicsScrollbar::onWindowWidthChange(qreal _width) +void EasyGraphicsScrollbar::onWindowWidthChange(qreal _width) { const auto oldScale = m_windowScale; const auto scrollingRange = range(); diff --git a/profiler_gui/graphics_scrollbar.h b/profiler_gui/graphics_scrollbar.h index 5b82762..bfe8501 100644 --- a/profiler_gui/graphics_scrollbar.h +++ b/profiler_gui/graphics_scrollbar.h @@ -15,33 +15,32 @@ * license : TODO: add license text ************************************************************************/ -#ifndef EASY_PROFILER__GRAPHICS_SCROLLBAR__H -#define EASY_PROFILER__GRAPHICS_SCROLLBAR__H +#ifndef EASY__GRAPHICS_SCROLLBAR__H +#define EASY__GRAPHICS_SCROLLBAR__H #include #include -#include #include #include -#include +//#include #include "common_types.h" ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsSliderItem : public QGraphicsRectItem +class EasyGraphicsSliderItem : public QGraphicsRectItem { typedef QGraphicsRectItem Parent; - typedef ProfGraphicsSliderItem This; + typedef EasyGraphicsSliderItem This; private: - QPolygonF m_leftIndicator, m_rightIndicator; + //QPolygonF m_leftIndicator, m_rightIndicator; qreal m_halfwidth; public: - ProfGraphicsSliderItem(bool _main); - virtual ~ProfGraphicsSliderItem(); + EasyGraphicsSliderItem(bool _main); + virtual ~EasyGraphicsSliderItem(); void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; @@ -54,14 +53,14 @@ public: void setColor(QRgb _color); void setColor(const QColor& _color); -}; // END of class ProfGraphicsSliderItem. +}; // END of class EasyGraphicsSliderItem. ////////////////////////////////////////////////////////////////////////// -class ProfMinimapItem : public QGraphicsItem +class EasyMinimapItem : public QGraphicsItem { typedef QGraphicsItem Parent; - typedef ProfMinimapItem This; + typedef EasyMinimapItem This; QRectF m_boundingRect; qreal m_maxDuration; @@ -71,8 +70,8 @@ class ProfMinimapItem : public QGraphicsItem public: - ProfMinimapItem(); - virtual ~ProfMinimapItem(); + EasyMinimapItem(); + virtual ~EasyMinimapItem(); // Public virtual methods @@ -89,34 +88,34 @@ public: void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items); -}; // END of class ProfMinimapItem. +}; // END of class EasyMinimapItem. ////////////////////////////////////////////////////////////////////////// -class ProfIdAction : public QAction +class EasyIdAction : public QAction { Q_OBJECT private: typedef QAction Parent; - typedef ProfIdAction This; + typedef EasyIdAction This; ::profiler::thread_id_t m_id; public: - ProfIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id) + EasyIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id) { connect(this, &Parent::triggered, this, &This::onToggle); } - ProfIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id) + EasyIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id) { connect(this, &Parent::triggered, this, &This::onToggle); } - virtual ~ProfIdAction() + virtual ~EasyIdAction() { } @@ -134,14 +133,14 @@ signals: ////////////////////////////////////////////////////////////////////////// -class ProfGraphicsScrollbar : public QGraphicsView +class EasyGraphicsScrollbar : public QGraphicsView { Q_OBJECT private: typedef QGraphicsView Parent; - typedef ProfGraphicsScrollbar This; + typedef EasyGraphicsScrollbar This; qreal m_minimumValue; qreal m_maximumValue; @@ -149,15 +148,15 @@ private: qreal m_windowScale; QPoint m_mousePressPos; Qt::MouseButtons m_mouseButtons; - ProfGraphicsSliderItem* m_slider; - ProfGraphicsSliderItem* m_chronometerIndicator; - ProfMinimapItem* m_minimap; + EasyGraphicsSliderItem* m_slider; + EasyGraphicsSliderItem* m_chronometerIndicator; + EasyMinimapItem* m_minimap; bool m_bScrolling; public: - ProfGraphicsScrollbar(QWidget* _parent = nullptr); - virtual ~ProfGraphicsScrollbar(); + EasyGraphicsScrollbar(QWidget* _parent = nullptr); + virtual ~EasyGraphicsScrollbar(); // Public virtual methods @@ -205,8 +204,8 @@ private slots: void onThreadActionClicked(::profiler::thread_id_t _id); void onWindowWidthChange(qreal _width); -}; // END of class ProfGraphicsScrollbar. +}; // END of class EasyGraphicsScrollbar. ////////////////////////////////////////////////////////////////////////// -#endif // EASY_PROFILER__GRAPHICS_SCROLLBAR__H +#endif // EASY__GRAPHICS_SCROLLBAR__H diff --git a/profiler_gui/main.cpp b/profiler_gui/main.cpp index 5d091e8..8ac8ed1 100644 --- a/profiler_gui/main.cpp +++ b/profiler_gui/main.cpp @@ -37,7 +37,7 @@ int main(int argc, char **argv) auto now = ::std::chrono::duration_cast(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1; srand((unsigned int)now); - ProfMainWindow window; + EasyMainWindow window; window.show(); return app.exec(); diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 0031ed5..1bf2a15 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -10,7 +10,7 @@ * ----------------- : * change log : * 2016/06/26 Victor Zarubkin: Initial commit. * : -* : * 2016/06/27 Victor Zarubkin: Passing blocks number to ProfTreeWidget::setTree(). +* : * 2016/06/27 Victor Zarubkin: Passing blocks number to EasyTreeWidget::setTree(). * : * : * 2016/06/29 Victor Zarubkin: Added menu with tests. * : @@ -30,29 +30,31 @@ #include #include #include +#include +#include #include "main_window.h" #include "blocks_tree_widget.h" #include "blocks_graphics_view.h" #include "globals.h" -#include + ////////////////////////////////////////////////////////////////////////// -ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graphicsView(nullptr) +EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsView(nullptr), m_progress(nullptr) { setObjectName("ProfilerGUI_MainWindow"); - setWindowTitle("easy_profiler reader"); + setWindowTitle("EasyProfiler Reader v0.2.0"); setDockNestingEnabled(true); resize(800, 600); setStatusBar(new QStatusBar()); - auto graphicsView = new ProfGraphicsViewWidget(); + auto graphicsView = new EasyGraphicsViewWidget(); m_graphicsView = new QDockWidget("Blocks diagram"); m_graphicsView->setMinimumHeight(50); m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas); m_graphicsView->setWidget(graphicsView); - auto treeWidget = new ProfTreeWidget(); + auto treeWidget = new EasyTreeWidget(); m_treeWidget = new QDockWidget("Blocks hierarchy"); m_treeWidget->setMinimumHeight(50); m_treeWidget->setAllowedAreas(Qt::AllDockWidgetAreas); @@ -70,9 +72,6 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph auto actionExit = new QAction("Exit", nullptr); connect(actionExit, &QAction::triggered, this, &This::onExitClicked); - auto actionTestView = new QAction("Test viewport", nullptr); - connect(actionTestView, &QAction::triggered, this, &This::onTestViewportClicked); - auto menu = new QMenu("File"); menu->addAction(actionOpen); menu->addAction(actionReload); @@ -80,10 +79,6 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph menu->addAction(actionExit); menuBar()->addMenu(menu); - menu = new QMenu("Tests"); - menu->addAction(actionTestView); - menuBar()->addMenu(menu); - QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); settings.beginGroup("main"); @@ -113,15 +108,27 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph } encodingMenu->addAction(action); connect(action, &QAction::triggered, this, &This::onEncodingChanged); - } + menu->addSeparator(); + auto actionBorders = menu->addAction("Draw items' borders"); + actionBorders->setCheckable(true); + actionBorders->setChecked(::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders); + connect(actionBorders, &QAction::triggered, this, &This::onDrawBordersChanged); + menuBar()->addMenu(menu); - connect(graphicsView->view(), &ProfGraphicsView::intervalChanged, treeWidget, &ProfTreeWidget::setTreeBlocks); + connect(graphicsView->view(), &EasyGraphicsView::intervalChanged, treeWidget, &EasyTreeWidget::setTreeBlocks); + connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout); loadSettings(); + m_progress = new QProgressDialog("Loading file...", "Cancel", 0, 100, this); + m_progress->setWindowTitle("EasyProfiler"); + m_progress->setModal(true); + m_progress->hide(); + connect(m_progress, &QProgressDialog::canceled, this, &This::onFileReaderCancel); + if(QCoreApplication::arguments().size() > 1) { auto opened_filename = QCoreApplication::arguments().at(1).toStdString(); @@ -129,13 +136,14 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph } } -ProfMainWindow::~ProfMainWindow() +EasyMainWindow::~EasyMainWindow() { + delete m_progress; } ////////////////////////////////////////////////////////////////////////// -void ProfMainWindow::onOpenFileClicked(bool) +void EasyMainWindow::onOpenFileClicked(bool) { auto filename = QFileDialog::getOpenFileName(this, "Open profiler log", m_lastFile.c_str(), "Profiler Log File (*.prof);;All Files (*.*)"); loadFile(filename.toStdString()); @@ -143,85 +151,53 @@ void ProfMainWindow::onOpenFileClicked(bool) ////////////////////////////////////////////////////////////////////////// -void ProfMainWindow::loadFile(const std::string& stdfilename) +void EasyMainWindow::loadFile(const std::string& stdfilename) { - ::profiler::SerializedData data; - ::profiler::thread_blocks_tree_t prof_blocks; - auto nblocks = fillTreesFromFile(stdfilename.c_str(), data, prof_blocks, true); + m_progress->setValue(0); + m_progress->show(); + m_readerTimer.start(20); + m_reader.load(stdfilename); - if (nblocks != 0) - { - static_cast(m_treeWidget->widget())->clearSilent(true); - - m_lastFile = stdfilename; - m_serializedData = ::std::move(data); - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); - ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); - ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); - memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::ProfBlock) * nblocks); - for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); - - static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); - } +// ::profiler::SerializedData data; +// ::profiler::thread_blocks_tree_t prof_blocks; +// auto nblocks = fillTreesFromFile(stdfilename.c_str(), data, prof_blocks, true); +// +// if (nblocks != 0) +// { +// static_cast(m_treeWidget->widget())->clearSilent(true); +// +// m_lastFile = stdfilename; +// m_serializedData = ::std::move(data); +// ::profiler_gui::EASY_GLOBALS.selected_thread = 0; +// ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); +// ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); +// ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); +// memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); +// for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); +// +// static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); +// } } ////////////////////////////////////////////////////////////////////////// -void ProfMainWindow::onReloadFileClicked(bool) +void EasyMainWindow::onReloadFileClicked(bool) { if (m_lastFile.empty()) - { return; - } - - ::profiler::SerializedData data; - ::profiler::thread_blocks_tree_t prof_blocks; - auto nblocks = fillTreesFromFile(m_lastFile.c_str(), data, prof_blocks, true); - - if (nblocks != 0) - { - static_cast(m_treeWidget->widget())->clearSilent(true); - - m_serializedData = ::std::move(data); - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); - ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); - ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); - memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::ProfBlock) * nblocks); - for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); - - static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); - } + loadFile(m_lastFile); } ////////////////////////////////////////////////////////////////////////// -void ProfMainWindow::onExitClicked(bool) +void EasyMainWindow::onExitClicked(bool) { close(); } ////////////////////////////////////////////////////////////////////////// -void ProfMainWindow::onTestViewportClicked(bool) -{ - static_cast(m_treeWidget->widget())->clearSilent(true); - - auto view = static_cast(m_graphicsView->widget())->view(); - view->clearSilent(); - - m_serializedData.clear(); - ::profiler_gui::EASY_GLOBALS.gui_blocks.clear(); - ::profiler_gui::EASY_GLOBALS.profiler_blocks.clear(); - ::profiler_gui::EASY_GLOBALS.selected_thread = 0; - ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); - - //view->test(18000, 40000000, 2); - view->test(100, 9000, 1); -} - -void ProfMainWindow::onEncodingChanged(bool) +void EasyMainWindow::onEncodingChanged(bool) { auto _sender = qobject_cast(sender()); auto name = _sender->text(); @@ -229,17 +205,22 @@ void ProfMainWindow::onEncodingChanged(bool) QTextCodec::setCodecForLocale(codec); } -////////////////////////////////////////////////////////////////////////// - -void ProfMainWindow::closeEvent(QCloseEvent* close_event) +void EasyMainWindow::onDrawBordersChanged(bool _checked) { - saveSettings(); - QMainWindow::closeEvent(close_event); + ::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = _checked; } ////////////////////////////////////////////////////////////////////////// -void ProfMainWindow::loadSettings() +void EasyMainWindow::closeEvent(QCloseEvent* close_event) +{ + saveSettings(); + Parent::closeEvent(close_event); +} + +////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::loadSettings() { QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); settings.beginGroup("main"); @@ -259,7 +240,7 @@ void ProfMainWindow::loadSettings() settings.endGroup(); } -void ProfMainWindow::saveSettings() +void EasyMainWindow::saveSettings() { QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); settings.beginGroup("main"); @@ -272,3 +253,111 @@ void ProfMainWindow::saveSettings() } ////////////////////////////////////////////////////////////////////////// + +void EasyMainWindow::onFileReaderTimeout() +{ + if (m_reader.done()) + { + auto nblocks = m_reader.size(); + if (nblocks != 0) + { + static_cast(m_treeWidget->widget())->clearSilent(true); + + ::profiler::SerializedData data; + ::profiler::thread_blocks_tree_t prof_blocks; + ::std::string stdfilename; + m_reader.get(data, prof_blocks, stdfilename); + + m_lastFile = ::std::move(stdfilename); + m_serializedData = ::std::move(data); + ::profiler_gui::EASY_GLOBALS.selected_thread = 0; + ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); + ::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks); + ::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks); + memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks); + for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item); + + static_cast(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks); + } + + m_reader.interrupt(); + + m_readerTimer.stop(); + m_progress->setValue(100); + m_progress->hide(); + } + else + { + m_progress->setValue(m_reader.progress()); + } +} + +void EasyMainWindow::onFileReaderCancel() +{ + m_readerTimer.stop(); + m_reader.interrupt(); + m_progress->hide(); +} + +////////////////////////////////////////////////////////////////////////// + +EasyFileReader::EasyFileReader() +{ + +} + +EasyFileReader::~EasyFileReader() +{ + interrupt(); +} + +bool EasyFileReader::done() const +{ + return m_bDone.load(); +} + +int EasyFileReader::progress() const +{ + return m_progress.load(); +} + +unsigned int EasyFileReader::size() const +{ + return m_size.load(); +} + +void EasyFileReader::load(const ::std::string& _filename) +{ + interrupt(); + + m_filename = _filename; + m_thread = ::std::move(::std::thread([](::std::atomic_bool& isDone, ::std::atomic& blocks_number, ::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees) { + blocks_number.store(fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, true)); + isDone.store(true); + }, ::std::ref(m_bDone), ::std::ref(m_size), ::std::ref(m_progress), m_filename.c_str(), ::std::ref(m_serializedData), ::std::ref(m_blocksTree))); +} + +void EasyFileReader::interrupt() +{ + m_progress.store(-100); + if (m_thread.joinable()) + m_thread.join(); + + m_bDone.store(false); + m_progress.store(0); + m_size.store(0); + m_serializedData.clear(); + m_blocksTree.clear(); +} + +void EasyFileReader::get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, ::std::string& _filename) +{ + if (done()) + { + m_serializedData.swap(_data); + m_blocksTree.swap(_tree); + m_filename.swap(_filename); + } +} + +////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 5e6c2e5..bf606aa 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -17,33 +17,67 @@ #ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H #define EASY_PROFILER_GUI__MAIN_WINDOW__H -#include #include +#include +#include +#include +#include #include "profiler/reader.h" ////////////////////////////////////////////////////////////////////////// -class ProfTreeWidget; -class ProfGraphicsView; class QDockWidget; -class ProfMainWindow : public QMainWindow +////////////////////////////////////////////////////////////////////////// + +class EasyFileReader final +{ + ::profiler::SerializedData m_serializedData; ///< + ::profiler::thread_blocks_tree_t m_blocksTree; ///< + ::std::string m_filename; ///< + ::std::thread m_thread; ///< + ::std::atomic_bool m_bDone; ///< + ::std::atomic m_progress; ///< + ::std::atomic m_size; ///< + +public: + + EasyFileReader(); + ~EasyFileReader(); + + bool done() const; + int progress() const; + unsigned int size() const; + + void load(const ::std::string& _filename); + void interrupt(); + void get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, ::std::string& _filename); + +}; // END of class EasyFileReader. + +////////////////////////////////////////////////////////////////////////// + +class EasyMainWindow : public QMainWindow { Q_OBJECT protected: - typedef ProfMainWindow This; + typedef EasyMainWindow This; + typedef QMainWindow Parent; ::std::string m_lastFile; QDockWidget* m_treeWidget; QDockWidget* m_graphicsView; + class QProgressDialog* m_progress; + QTimer m_readerTimer; ::profiler::SerializedData m_serializedData; + EasyFileReader m_reader; public: - ProfMainWindow(); - virtual ~ProfMainWindow(); + EasyMainWindow(); + virtual ~EasyMainWindow(); // Public virtual methods @@ -54,8 +88,10 @@ protected slots: void onOpenFileClicked(bool); void onReloadFileClicked(bool); void onExitClicked(bool); - void onTestViewportClicked(bool); void onEncodingChanged(bool); + void onDrawBordersChanged(bool); + void onFileReaderTimeout(); + void onFileReaderCancel(); private: @@ -66,7 +102,7 @@ private: void loadSettings(); void saveSettings(); -}; // END of class ProfMainWindow. +}; // END of class EasyMainWindow. ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/tree_widget_item.cpp b/profiler_gui/tree_widget_item.cpp new file mode 100644 index 0000000..c3a04b1 --- /dev/null +++ b/profiler_gui/tree_widget_item.cpp @@ -0,0 +1,190 @@ +/************************************************************************ +* file name : tree_widget_item.cpp +* ----------------- : +* creation time : 2016/08/18 +* copyright : (c) 2016 Victor Zarubkin +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of EasyTreeWidgetItem. +* ----------------- : +* change log : * 2016/08/18 Victor Zarubkin: Moved sources from blocks_tree_widget.cpp +* : and renamed classes from Prof* to Easy*. +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#include "tree_widget_item.h" +#include "globals.h" + +////////////////////////////////////////////////////////////////////////// + +EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent) + : Parent(_parent) + , m_block(_treeBlock) + , m_customBGColor(0) + , m_customTextColor(0) +{ + +} + +EasyTreeWidgetItem::~EasyTreeWidgetItem() +{ +} + +bool EasyTreeWidgetItem::operator < (const Parent& _other) const +{ + const auto col = treeWidget()->sortColumn(); + + switch (col) + { + //case COL_UNKNOWN: + case COL_NAME: + { + if (parent() == nullptr) + return false; // Do not sort topLevelItems by name + return Parent::operator < (_other); + } + + case COL_NCALLS_PER_THREAD: + case COL_NCALLS_PER_PARENT: + case COL_NCALLS_PER_FRAME: + { + return data(col, Qt::UserRole).toUInt() < _other.data(col, Qt::UserRole).toUInt(); + } + + case COL_SELF_DURATION_PERCENT: + case COL_PERCENT_PER_PARENT: + case COL_PERCENT_PER_FRAME: + case COL_PERCENT_SUM_PER_PARENT: + case COL_PERCENT_SUM_PER_FRAME: + case COL_PERCENT_SUM_PER_THREAD: + { + return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt(); + } + + default: + { + // durations min, max, average + return data(col, Qt::UserRole).toULongLong() < _other.data(col, Qt::UserRole).toULongLong(); + } + } + + return false; +} + +const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const +{ + return m_block; +} + +::profiler::timestamp_t EasyTreeWidgetItem::duration() const +{ + if (m_block->node) + return m_block->node->block()->duration(); + return data(COL_DURATION, Qt::UserRole).toULongLong(); +} + +::profiler::timestamp_t EasyTreeWidgetItem::selfDuration() const +{ + return data(COL_SELF_DURATION, Qt::UserRole).toULongLong(); +} + +void EasyTreeWidgetItem::setTimeSmart(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix) +{ + const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time); + + setData(_column, Qt::UserRole, (quint64)nanosecondsTime); + + setToolTip(_column, QString("%1 ns").arg(nanosecondsTime)); + + if (_time < 1e3) + { + setText(_column, QString("%1%2 ns").arg(_prefix).arg(nanosecondsTime)); + } + else if (_time < 1e6) + { + setText(_column, QString("%1%2 us").arg(_prefix).arg(double(nanosecondsTime) * 1e-3, 0, 'f', 3)); + } + else if (_time < 1e9) + { + setText(_column, QString("%1%2 ms").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'f', 3)); + } + else + { + setText(_column, QString("%1%2 s").arg(_prefix).arg(double(nanosecondsTime) * 1e-9, 0, 'f', 3)); + } +} + +void EasyTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time) +{ + const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time); + setData(_column, Qt::UserRole, (quint64)nanosecondsTime); + setToolTip(_column, QString("%1 ns").arg(nanosecondsTime)); + setText(_column, QString::number(double(nanosecondsTime) * 1e-6, 'g', 9)); +} + +void EasyTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix) +{ + const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time); + setData(_column, Qt::UserRole, (quint64)nanosecondsTime); + setToolTip(_column, QString("%1 ns").arg(nanosecondsTime)); + setText(_column, QString("%1%2").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'g', 9)); +} + +void EasyTreeWidgetItem::setBackgroundColor(QRgb _color) +{ + m_customBGColor = _color; +} + +void EasyTreeWidgetItem::setTextColor(QRgb _color) +{ + m_customTextColor = _color; +} + +void EasyTreeWidgetItem::colorize(bool _colorize) +{ + if (_colorize) + { + for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) + { + setBackground(i, QColor::fromRgb(m_customBGColor)); + setForeground(i, QColor::fromRgb(m_customTextColor)); + } + } + else + { + const QBrush nobrush; + for (int i = 0; i < COL_COLUMNS_NUMBER; ++i) + { + setBackground(i, nobrush); + setForeground(i, nobrush); + } + } +} + +void EasyTreeWidgetItem::collapseAll() +{ + for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i) + { + static_cast(child(i))->collapseAll(); + } + + setExpanded(false); + ::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = false; +} + +void EasyTreeWidgetItem::expandAll() +{ + for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i) + { + static_cast(child(i))->expandAll(); + } + + setExpanded(true); + ::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = true; +} + +////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/tree_widget_item.h b/profiler_gui/tree_widget_item.h new file mode 100644 index 0000000..466b9f6 --- /dev/null +++ b/profiler_gui/tree_widget_item.h @@ -0,0 +1,118 @@ +/************************************************************************ +* file name : tree_widget_item.h +* ----------------- : +* creation time : 2016/08/18 +* copyright : (c) 2016 Victor Zarubkin +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains declaration of EasyTreeWidgetItem +* : for displyaing EasyProfiler blocks tree. +* ----------------- : +* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h +* : and renamed classes from Prof* to Easy*. +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#ifndef EASY__TREE_WIDGET_ITEM__H_ +#define EASY__TREE_WIDGET_ITEM__H_ + +#include +#include +#include "profiler/reader.h" +#include "common_types.h" + +////////////////////////////////////////////////////////////////////////// + +enum EasyColumnsIndexes +{ + COL_UNKNOWN = -1, + + COL_NAME = 0, + + COL_BEGIN, + + COL_DURATION, + COL_SELF_DURATION, + COL_DURATION_SUM_PER_PARENT, + COL_DURATION_SUM_PER_FRAME, + COL_DURATION_SUM_PER_THREAD, + + COL_SELF_DURATION_PERCENT, + COL_PERCENT_PER_PARENT, + COL_PERCENT_PER_FRAME, + COL_PERCENT_SUM_PER_PARENT, + COL_PERCENT_SUM_PER_FRAME, + COL_PERCENT_SUM_PER_THREAD, + + COL_END, + + COL_MIN_PER_FRAME, + COL_MAX_PER_FRAME, + COL_AVERAGE_PER_FRAME, + COL_NCALLS_PER_FRAME, + + COL_MIN_PER_THREAD, + COL_MAX_PER_THREAD, + COL_AVERAGE_PER_THREAD, + COL_NCALLS_PER_THREAD, + + COL_MIN_PER_PARENT, + COL_MAX_PER_PARENT, + COL_AVERAGE_PER_PARENT, + COL_NCALLS_PER_PARENT, + + COL_COLUMNS_NUMBER +}; + +////////////////////////////////////////////////////////////////////////// + +class EasyTreeWidgetItem : public QTreeWidgetItem +{ + typedef QTreeWidgetItem Parent; + typedef EasyTreeWidgetItem This; + + const ::profiler::BlocksTree* m_block; + QRgb m_customBGColor; + QRgb m_customTextColor; + +public: + + using Parent::setBackgroundColor; + using Parent::setTextColor; + + EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr); + virtual ~EasyTreeWidgetItem(); + + bool operator < (const Parent& _other) const override; + +public: + + const ::profiler::BlocksTree* block() const; + + ::profiler::timestamp_t duration() const; + ::profiler::timestamp_t selfDuration() const; + + void setTimeSmart(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix = ""); + + void setTimeMs(int _column, const ::profiler::timestamp_t& _time); + void setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix); + + void setBackgroundColor(QRgb _color); + + void setTextColor(QRgb _color); + + void colorize(bool _colorize); + + void collapseAll(); + + void expandAll(); + +}; // END of class EasyTreeWidgetItem. + +////////////////////////////////////////////////////////////////////////// + +#endif // EASY__TREE_WIDGET_ITEM__H_ diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp new file mode 100644 index 0000000..194de9b --- /dev/null +++ b/profiler_gui/tree_widget_loader.cpp @@ -0,0 +1,584 @@ +/************************************************************************ +* file name : tree_widget_loader.h +* ----------------- : +* creation time : 2016/08/18 +* copyright : (c) 2016 Victor Zarubkin +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains implementation of EasyTreeWidgetLoader which aim is +* : to load EasyProfiler blocks hierarchy in separate thread. +* ----------------- : +* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp +* : and renamed Prof* to Easy*. +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#include "tree_widget_loader.h" +#include "tree_widget_item.h" +#include "globals.h" + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +////////////////////////////////////////////////////////////////////////// + +EasyTreeWidgetLoader::EasyTreeWidgetLoader() : m_bDone(ATOMIC_VAR_INIT(false)), m_bInterrupt(ATOMIC_VAR_INIT(false)), m_progress(ATOMIC_VAR_INIT(0)) +{ +} + +EasyTreeWidgetLoader::~EasyTreeWidgetLoader() +{ + interrupt(); +} + +bool EasyTreeWidgetLoader::done() const +{ + return m_bDone.load(); +} + +void EasyTreeWidgetLoader::setDone() +{ + m_bDone.store(true); + //m_progress.store(100); +} + +void EasyTreeWidgetLoader::setProgress(int _progress) +{ + m_progress.store(_progress); +} + +bool EasyTreeWidgetLoader::interrupted() const +{ + return m_bInterrupt.load(); +} + +int EasyTreeWidgetLoader::progress() const +{ + return m_progress.load(); +} + +void EasyTreeWidgetLoader::takeTopLevelItems(ThreadedItems& _output) +{ + if (done()) + { + _output = ::std::move(m_topLevelItems); + m_topLevelItems.clear(); + } +} + +void EasyTreeWidgetLoader::takeItems(Items& _output) +{ + if (done()) + { + _output = ::std::move(m_items); + m_items.clear(); + } +} + +void EasyTreeWidgetLoader::interrupt() +{ + m_bInterrupt.store(true); + if (m_thread.joinable()) + m_thread.join(); + + m_bInterrupt.store(false); + m_bDone.store(false); + m_progress.store(0); + + for (auto item : m_topLevelItems) + { + //qDeleteAll(item.second->takeChildren()); + delete item.second; + } + + m_items.clear(); + m_topLevelItems.clear(); +} + +void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows) +{ + interrupt(); + m_thread = ::std::move(::std::thread(&FillTreeClass::setTreeInternal1, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), ::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows)); +} + +void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows) +{ + interrupt(); + m_thread = ::std::move(::std::thread(&FillTreeClass::setTreeInternal2, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), _beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows)); +} + +////////////////////////////////////////////////////////////////////////// + +template +void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows) +{ + _items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks + + ::profiler::timestamp_t finishtime = 0; + for (const auto& threadTree : _blocksTree) + { + const auto node_block = threadTree.second.tree.children.front().node->block(); + const auto startTime = node_block->getBegin(); + const auto endTime = node_block->getEnd(); + + if (_beginTime > startTime) + _beginTime = startTime; + + if (finishtime < endTime) + finishtime = endTime; + } + + //const QSignalBlocker b(this); + int i = 0; + const int total = static_cast(_blocksTree.size()); + for (const auto& threadTree : _blocksTree) + { + if (_safelocker.interrupted()) + break; + + auto& block = threadTree.second.tree; + auto item = new EasyTreeWidgetItem(&block); + + if (threadTree.second.thread_name && threadTree.second.thread_name[0] != 0) + { + item->setText(COL_NAME, QString("%1 Thread %2").arg(threadTree.second.thread_name).arg(threadTree.first)); + } + else + { + item->setText(COL_NAME, QString("Thread %1").arg(threadTree.first)); + } + + ::profiler::timestamp_t duration = 0; + if (!block.children.empty()) + { + duration = block.children.back().node->block()->getEnd() - block.children.front().node->block()->getBegin(); + } + + item->setTimeSmart(COL_DURATION, duration); + item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); + item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); + + _items.push_back(item); + + // TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now) + ::profiler::timestamp_t children_duration = 0; + for (const auto& child : block.children) + children_duration += child.node->block()->duration(); + item->setTimeSmart(COL_SELF_DURATION, children_duration); + + children_duration = 0; + const auto children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows); + + if (children_items_number > 0) + { + //total_items += children_items_number + 1; + //addTopLevelItem(item); + //m_roots[threadTree.first] = item; + _topLevelItems.emplace_back(threadTree.first, item); + } + else + { + _items.pop_back(); + delete item; + } + + _safelocker.setProgress((100 * ++i) / total); + } + + _safelocker.setDone(); + //return total_items; +} + +////////////////////////////////////////////////////////////////////////// + +auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size()) +{ + auto children_number = _tree->children.size(); + for (const auto& child : _tree->children) + children_number += calculateTotalChildrenNumber(&child); + return children_number; +} + +template +void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows) +{ + //size_t blocksNumber = 0; + //for (const auto& block : _blocks) + // blocksNumber += calculateTotalChildrenNumber(block.tree); + // //blocksNumber += block.tree->total_children_number; + //m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks + + RootsMap threadsMap; + + int i = 0, total = static_cast(_blocks.size()); + //const QSignalBlocker b(this); + for (const auto& block : _blocks) + { + if (_safelocker.interrupted()) + break; + + const auto startTime = block.tree->node->block()->getBegin(); + const auto endTime = block.tree->node->block()->getEnd(); + if (startTime > _right || endTime < _left) + { + _safelocker.setProgress((90 * ++i) / total); + continue; + } + + ::profiler::timestamp_t duration = 0; + EasyTreeWidgetItem* thread_item = nullptr; + auto thread_item_it = threadsMap.find(block.root->thread_id); + if (thread_item_it != threadsMap.end()) + { + thread_item = thread_item_it->second; + } + else + { + thread_item = new EasyTreeWidgetItem(&block.root->tree); + + if (block.root->thread_name && block.root->thread_name[0] != 0) + { + thread_item->setText(COL_NAME, QString("%1 Thread %2").arg(block.root->thread_name).arg(block.root->thread_id)); + } + else + { + thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id)); + } + + if (!block.root->tree.children.empty()) + { + duration = block.root->tree.children.back().node->block()->getEnd() - block.root->tree.children.front().node->block()->getBegin(); + } + + thread_item->setTimeSmart(COL_DURATION, duration); + thread_item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND); + thread_item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND); + + // Calculate clean duration (sum of all children durations) + ::profiler::timestamp_t children_duration = 0; + for (const auto& child : block.root->tree.children) + children_duration += child.node->block()->duration(); + thread_item->setTimeSmart(COL_SELF_DURATION, children_duration); + + threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item)); + } + + auto item = new EasyTreeWidgetItem(block.tree, thread_item); + duration = endTime - startTime; + + item->setText(COL_NAME, ::profiler_gui::toUnicode(block.tree->node->getName())); + item->setTimeSmart(COL_DURATION, duration); + item->setTimeMs(COL_BEGIN, startTime - _beginTime); + item->setTimeMs(COL_END, endTime - _beginTime); + + item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_PARENT, ""); + + item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_FRAME, ""); + + if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also + { + const auto& per_thread_stats = block.tree->per_thread_stats; + const auto& per_parent_stats = block.tree->per_parent_stats; + const auto& per_frame_stats = block.tree->per_frame_stats; + + + if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); + item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); + + auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(thread_item->selfDuration())); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); + item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); + + + if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); + item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); + + + if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); + item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); + } + else + { + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_THREAD, ""); + } + + const auto color = block.tree->node->block()->getColor(); + const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + const auto fgColor = 0x00ffffff - bgColor; + item->setBackgroundColor(bgColor); + item->setTextColor(fgColor); + + auto item_index = static_cast(_items.size()); + _items.push_back(item); + + size_t children_items_number = 0; + ::profiler::timestamp_t children_duration = 0; + if (!block.tree->children.empty()) + { + children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows); + if (_safelocker.interrupted()) + break; + } + + int percentage = 100; + auto self_duration = duration - children_duration; + if (children_duration > 0 && duration > 0) + { + percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); + } + + item->setTimeSmart(COL_SELF_DURATION, self_duration); + item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); + item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); + + if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) + { + //total_items += children_items_number + 1; + ::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item_index; + + if (_colorizeRows) + { + item->colorize(_colorizeRows); + } + } + else + { + _items.pop_back(); + delete item; + } + + _safelocker.setProgress((90 * ++i) / total); + } + + i = 0; + total = static_cast(threadsMap.size()); + for (auto& it : threadsMap) + { + auto item = it.second; + + if (item->childCount() > 0) + { + //addTopLevelItem(item); + //m_roots[it.first] = item; + + _items.push_back(item); + _topLevelItems.emplace_back(it.first, item); + + //++total_items; + } + else + { + delete item; + } + + _safelocker.setProgress(90 + (10 * ++i) / total); + } + + _safelocker.setDone(); + //return total_items; +} + +template +size_t FillTreeClass::setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows) +{ + size_t total_items = 0; + for (const auto& child : _children) + { + if (_safelocker.interrupted()) + break; + + const auto startTime = child.node->block()->getBegin(); + const auto endTime = child.node->block()->getEnd(); + const auto duration = endTime - startTime; + _duration += duration; + + if (startTime > _right || endTime < _left) + { + continue; + } + + auto item = new EasyTreeWidgetItem(&child, _parent); + item->setText(COL_NAME, ::profiler_gui::toUnicode(child.node->getName())); + item->setTimeSmart(COL_DURATION, duration); + item->setTimeMs(COL_BEGIN, startTime - _beginTime); + item->setTimeMs(COL_END, endTime - _beginTime); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); + + if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also + { + const auto& per_thread_stats = child.per_thread_stats; + const auto& per_parent_stats = child.per_parent_stats; + const auto& per_frame_stats = child.per_frame_stats; + + auto percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_parent->duration())); + auto percentage_sum = static_cast(0.5 + 100. * static_cast(per_parent_stats->total_duration) / static_cast(_parent->duration())); + item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage); + item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage)); + item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum); + item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum)); + + if (_frame != nullptr) + { + if (_parent != _frame) + { + percentage = duration == 0 ? 0 : static_cast(0.5 + 100. * static_cast(duration) / static_cast(_frame->duration())); + percentage_sum = static_cast(0.5 + 100. * static_cast(per_frame_stats->total_duration) / static_cast(_frame->duration())); + } + + item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage); + item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage)); + item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum); + item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum)); + } + else + { + item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_FRAME, ""); + item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_FRAME, ""); + } + + + if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number); + item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number)); + + if (_thread) + { + auto percentage_per_thread = static_cast(0.5 + 100. * static_cast(per_thread_stats->total_duration) / static_cast(_thread->selfDuration())); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread); + item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread)); + } + + + if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number); + item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number)); + + + if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats) + { + item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min "); + item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max "); + item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration()); + item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration); + } + + item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number); + item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number)); + } + else + { + item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0); + item->setText(COL_PERCENT_PER_PARENT, ""); + item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_PARENT, ""); + item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0); + item->setText(COL_PERCENT_SUM_PER_THREAD, ""); + } + + const auto color = child.node->block()->getColor(); + const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color)); + const auto fgColor = 0x00ffffff - bgColor; + item->setBackgroundColor(bgColor); + item->setTextColor(fgColor); + + auto item_index = static_cast(_items.size()); + _items.push_back(item); + + size_t children_items_number = 0; + ::profiler::timestamp_t children_duration = 0; + if (!child.children.empty()) + { + children_items_number = FillTreeClass::setTreeInternal(_safelocker, _items, _beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows); + if (_safelocker.interrupted()) + break; + } + + int percentage = 100; + auto self_duration = duration - children_duration; + if (children_duration > 0 && duration > 0) + { + percentage = static_cast(0.5 + 100. * static_cast(self_duration) / static_cast(duration)); + } + + item->setTimeSmart(COL_SELF_DURATION, self_duration); + item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage); + item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage)); + + if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right)) + { + total_items += children_items_number + 1; + ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item_index; + + if (_colorizeRows) + { + item->colorize(_colorizeRows); + } + } + else + { + _items.pop_back(); + delete item; + } + } + + return total_items; +} + +////////////////////////////////////////////////////////////////////////// + +template struct FillTreeClass; +template struct FillTreeClass; + +////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/tree_widget_loader.h b/profiler_gui/tree_widget_loader.h new file mode 100644 index 0000000..1de12ee --- /dev/null +++ b/profiler_gui/tree_widget_loader.h @@ -0,0 +1,90 @@ +/************************************************************************ +* file name : tree_widget_loader.h +* ----------------- : +* creation time : 2016/08/18 +* copyright : (c) 2016 Victor Zarubkin +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : The file contains declaration of EasyTreeWidgetLoader which aim is +* : to load EasyProfiler blocks hierarchy in separate thread. +* ----------------- : +* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp +* : and renamed Prof* to Easy*. +* : +* : * +* ----------------- : +* license : TODO: add license text +************************************************************************/ + +#ifndef EASY__TREE_WIDGET_LOADER__H_ +#define EASY__TREE_WIDGET_LOADER__H_ + +#include +#include +#include +#include +#include "profiler/reader.h" +#include "common_types.h" + +////////////////////////////////////////////////////////////////////////// + +class EasyTreeWidgetItem; +typedef ::std::vector Items; +typedef ::std::vector<::std::pair<::profiler::thread_id_t, EasyTreeWidgetItem*> > ThreadedItems; +typedef ::std::unordered_map<::profiler::thread_id_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap; + +////////////////////////////////////////////////////////////////////////// + +class EasyTreeWidgetLoader final +{ + ThreadedItems m_topLevelItems; ///< + Items m_items; ///< + ::std::thread m_thread; ///< + ::std::atomic_bool m_bDone; ///< + ::std::atomic_bool m_bInterrupt; ///< + ::std::atomic m_progress; ///< + +public: + + EasyTreeWidgetLoader(); + ~EasyTreeWidgetLoader(); + + bool interrupted() const; + int progress() const; + bool done() const; + + void takeTopLevelItems(ThreadedItems& _output); + void takeItems(Items& _output); + + void interrupt(); + void fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows); + void fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows); + + void setDone(); + void setProgress(int _progress); + +}; // END of class EasyTreeWidgetLoader. + +////////////////////////////////////////////////////////////////////////// + +template +struct FillTreeClass final +{ + static void setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows); + static void setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows); + static size_t setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows); +}; + +////////////////////////////////////////////////////////////////////////// + +struct StubLocker final +{ + void setDone() {} + bool interrupted() const { return false; } + void setProgress(int) {} +}; + +////////////////////////////////////////////////////////////////////////// + +#endif // EASY__TREE_WIDGET_LOADER__H_ diff --git a/sample/main.cpp b/sample/main.cpp index 04a1ee0..3513020 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -1,282 +1,283 @@ -//#define FULL_DISABLE_PROFILER -#include "profiler/profiler.h" -#include -#include -#include -#include -#include -#include "profiler/reader.h" -#include -#include - -std::condition_variable cv; -std::mutex cv_m; -int g_i = 0; - -int OBJECTS = 500; -int RENDER_SPEPS = 1600; -int MODELLING_STEPS = 1000; -int RESOURCE_LOADING_COUNT = 50; - -void localSleep(int magic=200000) -{ - //PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - volatile int i = 0; - for (; i < magic; ++i); -} - -void loadingResources(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan); - localSleep(); -// std::this_thread::sleep_for(std::chrono::milliseconds(50)); -} - -void prepareMath(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - int* intarray = new int[OBJECTS]; - for (int i = 0; i < OBJECTS; ++i) - intarray[i] = i * i; - delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(3)); -} - -void calcIntersect(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - //int* intarray = new int[OBJECTS * OBJECTS]; - int* intarray = new int[OBJECTS]; - for (int i = 0; i < OBJECTS; ++i) - { - for (int j = i; j < OBJECTS; ++j) - //intarray[i * OBJECTS + j] = i * j - i / 2 + (OBJECTS - j) * 5; - intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5; - } - delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(4)); -} - -double multModel(double i) -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - return i * sin(i) * cos(i); -} - -void calcPhys(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - double* intarray = new double[OBJECTS]; - for (int i = 0; i < OBJECTS; ++i) - intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2); - calcIntersect(); - delete[] intarray; -} - -double calcSubbrain(int i) -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - return i * i * i - i / 10 + (OBJECTS - i) * 7 ; -} - -void calcBrain(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); - double* intarray = new double[OBJECTS]; - for (int i = 0; i < OBJECTS; ++i) - intarray[i] = calcSubbrain(double(i)) + double(i * 180 / 3); - delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(3)); -} - -void calculateBehavior(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue); - calcPhys(); - calcBrain(); -} - -void modellingStep(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy); - prepareMath(); - calculateBehavior(); -} - -void prepareRender(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred); - localSleep(); - //std::this_thread::sleep_for(std::chrono::milliseconds(8)); - -} - -int multPhys(int i) -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - return i * i * i * i / 100; -} - -int calcPhysicForObject(int i) -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - return multPhys(i) + i / 3 - (OBJECTS - i) * 15; -} - -void calculatePhysics(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - unsigned int* intarray = new unsigned int[OBJECTS]; - for (int i = 0; i < OBJECTS; ++i) - intarray[i] = calcPhysicForObject(i); - delete[] intarray; - //std::this_thread::sleep_for(std::chrono::milliseconds(8)); -} - -void frame(){ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta); - prepareRender(); - calculatePhysics(); -} - -void loadingResourcesThread(){ - //std::unique_lock lk(cv_m); - //cv.wait(lk, []{return g_i == 1; }); - PROFILER_SET_THREAD_NAME("Resource loading") - for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){ - loadingResources(); - PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan); - //std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } -} - -void modellingThread(){ - //std::unique_lock lk(cv_m); - //cv.wait(lk, []{return g_i == 1; }); - PROFILER_SET_THREAD_NAME("Modelling") - for (int i = 0; i < RENDER_SPEPS; i++){ - modellingStep(); - localSleep(300000); - //std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } -} - -void renderThread(){ - //std::unique_lock lk(cv_m); - //cv.wait(lk, []{return g_i == 1; }); - PROFILER_SET_THREAD_NAME("Render") - for (int i = 0; i < MODELLING_STEPS; i++){ - frame(); - localSleep(300000); - //std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } -} - -void four() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(37)); -} - -void five() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); -} -void six() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(42)); -} - -void three() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - four(); - five(); - six(); -} - -void seven() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(147)); -} - -void two() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - std::this_thread::sleep_for(std::chrono::milliseconds(26)); -} - -void one() -{ - PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); - two(); - three(); - seven(); -} - -/* -one - two - three - four - five - six - seven -*/ - -int main(int argc, char* argv[]) -{ - if (argc > 1 && argv[1]){ - OBJECTS = std::atoi(argv[1]); - } - if (argc > 2 && argv[2]){ - RENDER_SPEPS = std::atoi(argv[2]); - } - if (argc > 3 && argv[3]){ - MODELLING_STEPS = std::atoi(argv[3]); - } - if (argc > 4 && argv[4]){ - RESOURCE_LOADING_COUNT = std::atoi(argv[4]); - } - - std::cout << "Objects count: " << OBJECTS << std::endl; - std::cout << "Render steps: " << RENDER_SPEPS << std::endl; - std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl; - std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; - - auto start = std::chrono::system_clock::now(); - PROFILER_ENABLE; - PROFILER_SET_MAIN_THREAD; - //one(); - //one(); - /**/ - std::vector threads; - - std::thread render = std::thread(renderThread); - std::thread modelling = std::thread(modellingThread); - - - for(int i=0; i < 3; i++){ - threads.emplace_back(std::thread(loadingResourcesThread)); - threads.emplace_back(std::thread(renderThread)); - threads.emplace_back(std::thread(modellingThread)); - } - { - std::lock_guard lk(cv_m); - g_i = 1; - } - cv.notify_all(); - - render.join(); - modelling.join(); - for(auto& t : threads){ - t.join(); - } - /**/ - - auto end = std::chrono::system_clock::now(); - auto elapsed = - std::chrono::duration_cast(end - start); - - std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl; - - auto blocks_count = profiler::dumpBlocksToFile("test.prof"); - - std::cout << "Blocks count: " << blocks_count << std::endl; - - return 0; -} +//#define FULL_DISABLE_PROFILER +#include "profiler/profiler.h" +#include +#include +#include +#include +#include +#include "profiler/reader.h" +#include +#include + +std::condition_variable cv; +std::mutex cv_m; +int g_i = 0; + +int OBJECTS = 500; +int RENDER_SPEPS = 1600; +int MODELLING_STEPS = 1000; +int RESOURCE_LOADING_COUNT = 50; + +void localSleep(int magic=200000) +{ + //PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + volatile int i = 0; + for (; i < magic; ++i); +} + +void loadingResources(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan); + localSleep(); +// std::this_thread::sleep_for(std::chrono::milliseconds(50)); +} + +void prepareMath(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + int* intarray = new int[OBJECTS]; + for (int i = 0; i < OBJECTS; ++i) + intarray[i] = i * i; + delete[] intarray; + //std::this_thread::sleep_for(std::chrono::milliseconds(3)); +} + +void calcIntersect(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + //int* intarray = new int[OBJECTS * OBJECTS]; + int* intarray = new int[OBJECTS]; + for (int i = 0; i < OBJECTS; ++i) + { + for (int j = i; j < OBJECTS; ++j) + //intarray[i * OBJECTS + j] = i * j - i / 2 + (OBJECTS - j) * 5; + intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5; + } + delete[] intarray; + //std::this_thread::sleep_for(std::chrono::milliseconds(4)); +} + +double multModel(double i) +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + return i * sin(i) * cos(i); +} + +void calcPhys(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + double* intarray = new double[OBJECTS]; + for (int i = 0; i < OBJECTS; ++i) + intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2); + calcIntersect(); + delete[] intarray; +} + +double calcSubbrain(int i) +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + return i * i * i - i / 10 + (OBJECTS - i) * 7 ; +} + +void calcBrain(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + double* intarray = new double[OBJECTS]; + for (int i = 0; i < OBJECTS; ++i) + intarray[i] = calcSubbrain(i) + double(i * 180 / 3); + delete[] intarray; + //std::this_thread::sleep_for(std::chrono::milliseconds(3)); +} + +void calculateBehavior(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue); + calcPhys(); + calcBrain(); +} + +void modellingStep(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy); + prepareMath(); + calculateBehavior(); +} + +void prepareRender(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred); + localSleep(); + //std::this_thread::sleep_for(std::chrono::milliseconds(8)); + +} + +int multPhys(int i) +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + return i * i * i * i / 100; +} + +int calcPhysicForObject(int i) +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + return multPhys(i) + i / 3 - (OBJECTS - i) * 15; +} + +void calculatePhysics(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + unsigned int* intarray = new unsigned int[OBJECTS]; + for (int i = 0; i < OBJECTS; ++i) + intarray[i] = calcPhysicForObject(i); + delete[] intarray; + //std::this_thread::sleep_for(std::chrono::milliseconds(8)); +} + +void frame(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta); + prepareRender(); + calculatePhysics(); +} + +void loadingResourcesThread(){ + //std::unique_lock lk(cv_m); + //cv.wait(lk, []{return g_i == 1; }); + PROFILER_SET_THREAD_NAME("Resource loading") + for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){ + loadingResources(); + PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan); + localSleep(1200000); + //std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } +} + +void modellingThread(){ + //std::unique_lock lk(cv_m); + //cv.wait(lk, []{return g_i == 1; }); + PROFILER_SET_THREAD_NAME("Modelling") + for (int i = 0; i < RENDER_SPEPS; i++){ + modellingStep(); + localSleep(1200000); + //std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } +} + +void renderThread(){ + //std::unique_lock lk(cv_m); + //cv.wait(lk, []{return g_i == 1; }); + PROFILER_SET_THREAD_NAME("Render") + for (int i = 0; i < MODELLING_STEPS; i++){ + frame(); + localSleep(1200000); + //std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } +} + +void four() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + std::this_thread::sleep_for(std::chrono::milliseconds(37)); +} + +void five() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); +} +void six() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + std::this_thread::sleep_for(std::chrono::milliseconds(42)); +} + +void three() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + four(); + five(); + six(); +} + +void seven() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + std::this_thread::sleep_for(std::chrono::milliseconds(147)); +} + +void two() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + std::this_thread::sleep_for(std::chrono::milliseconds(26)); +} + +void one() +{ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); + two(); + three(); + seven(); +} + +/* +one + two + three + four + five + six + seven +*/ + +int main(int argc, char* argv[]) +{ + if (argc > 1 && argv[1]){ + OBJECTS = std::atoi(argv[1]); + } + if (argc > 2 && argv[2]){ + RENDER_SPEPS = std::atoi(argv[2]); + } + if (argc > 3 && argv[3]){ + MODELLING_STEPS = std::atoi(argv[3]); + } + if (argc > 4 && argv[4]){ + RESOURCE_LOADING_COUNT = std::atoi(argv[4]); + } + + std::cout << "Objects count: " << OBJECTS << std::endl; + std::cout << "Render steps: " << RENDER_SPEPS << std::endl; + std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl; + std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; + + auto start = std::chrono::system_clock::now(); + PROFILER_ENABLE; + PROFILER_SET_MAIN_THREAD; + //one(); + //one(); + /**/ + std::vector threads; + + std::thread render = std::thread(renderThread); + std::thread modelling = std::thread(modellingThread); + + + for(int i=0; i < 3; i++){ + threads.emplace_back(std::thread(loadingResourcesThread)); + threads.emplace_back(std::thread(renderThread)); + threads.emplace_back(std::thread(modellingThread)); + } + { + std::lock_guard lk(cv_m); + g_i = 1; + } + cv.notify_all(); + + render.join(); + modelling.join(); + for(auto& t : threads){ + t.join(); + } + /**/ + + auto end = std::chrono::system_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start); + + std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl; + + auto blocks_count = profiler::dumpBlocksToFile("test.prof"); + + std::cout << "Blocks count: " << blocks_count << std::endl; + + return 0; +} diff --git a/src/reader.cpp b/src/reader.cpp index 7dec23d..f728882 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -221,14 +221,16 @@ typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats; extern "C"{ - unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) + unsigned int fillTreesFromFile(::std::atomic& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics) { PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(::profiler::colors::Cyan) ::std::ifstream inFile(filename, ::std::fstream::binary); + progress.store(0); if (!inFile.is_open()) { + progress.store(100); return 0; } @@ -239,6 +241,7 @@ extern "C"{ inFile.read((char*)&memory_size, sizeof(uint64_t)); if (memory_size == 0) { + progress.store(100); return 0; } @@ -346,8 +349,19 @@ extern "C"{ current.per_thread_stats = update_statistics(per_thread_statistics, current); } + if (progress.load() < 0) + break; + progress.store(static_cast(90 * i / memory_size)); } + if (progress.load() < 0) + { + progress.store(100); + serialized_blocks.clear(); + threaded_trees.clear(); + return 0; + } + PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple) if (gather_statistics) { @@ -382,13 +396,16 @@ extern "C"{ }, ::std::ref(root)))); } + int j = 0, n = static_cast(statistics_threads.size()); for (auto& t : statistics_threads) { t.join(); + progress.store(90 + (10 * ++j) / n); } } else { + int j = 0, n = static_cast(threaded_trees.size()); for (auto& it : threaded_trees) { auto& root = it.second; @@ -402,11 +419,14 @@ extern "C"{ } ++root.tree.depth; + + progress.store(90 + (10 * ++j) / n); } } PROFILER_END_BLOCK // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors + progress.store(100); return blocks_counter; } }