From 089fcf1e31e127fb2b20efa72ccb60df0a7c9d42 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Mon, 5 Jun 2017 21:26:10 +0300 Subject: [PATCH] (GUI) Added an option to display thread ids in HEX mode; * (GUI) Fixed problem with searching selected blocks in histogram when selecting block from BlocksList widget --- profiler_gui/blocks_graphics_view.cpp | 44 ++-- profiler_gui/blocks_graphics_view.h | 1 + profiler_gui/easy_graphics_item.cpp | 4 +- profiler_gui/easy_graphics_scrollbar.cpp | 300 +++++++++++------------ profiler_gui/easy_graphics_scrollbar.h | 5 +- profiler_gui/globals.cpp | 1 + profiler_gui/globals.h | 23 +- profiler_gui/globals_qobjects.h | 1 + profiler_gui/main_window.cpp | 15 ++ profiler_gui/tree_widget_loader.cpp | 12 +- profiler_gui/tree_widget_loader.h | 4 +- 11 files changed, 221 insertions(+), 189 deletions(-) diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index a7badf5..be237a4 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -1368,21 +1368,8 @@ void EasyGraphicsView::initMode() onRefreshRequired(); }); - connect(globalSignals, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, [this]() - { - if (m_bEmpty) - return; - - for (auto item : m_items) - item->validateName(); - - emit treeChanged(); - - updateVisibleSceneRect(); - onHierarchyFlagChange(EASY_GLOBALS.only_current_thread_hierarchy); - - repaintScene(); - }); + connect(globalSignals, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged); + connect(globalSignals, &::profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged); connect(globalSignals, &::profiler_gui::EasyGlobalSignals::blocksTreeModeChanged, [this]() { @@ -1393,6 +1380,24 @@ void EasyGraphicsView::initMode() ////////////////////////////////////////////////////////////////////////// +void EasyGraphicsView::onThreadViewChanged() +{ + if (m_bEmpty) + return; + + for (auto item : m_items) + item->validateName(); + + emit treeChanged(); + + updateVisibleSceneRect(); + onHierarchyFlagChange(EASY_GLOBALS.only_current_thread_hierarchy); + + repaintScene(); +} + +////////////////////////////////////////////////////////////////////////// + void EasyGraphicsView::onScrollbarValueChange(int) { if (!m_bUpdatingRect && !m_bEmpty) @@ -1675,7 +1680,14 @@ void EasyGraphicsView::onIdleTimeout() lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight); auto it = EASY_GLOBALS.profiler_blocks.find(cse->tree.node->id()); if (it != EASY_GLOBALS.profiler_blocks.end()) - lay->addWidget(new QLabel(QString("%1 %2").arg(cse->tree.node->id()).arg(it->second.name()), widget), row, 1, 1, 2, Qt::AlignLeft); + { + if (EASY_GLOBALS.hex_thread_id) + lay->addWidget(new QLabel(QString("0x%1 %2").arg(cse->tree.node->id(), 0, 16).arg(it->second.name()), widget), row, 1, 1, 2, Qt::AlignLeft); + else + lay->addWidget(new QLabel(QString("%1 %2").arg(cse->tree.node->id()).arg(it->second.name()), widget), row, 1, 1, 2, Qt::AlignLeft); + } + else if (EASY_GLOBALS.hex_thread_id) + lay->addWidget(new QLabel(QString("0x%1").arg(cse->tree.node->id(), 0, 16), widget), row, 1, 1, 2, Qt::AlignLeft); else lay->addWidget(new QLabel(QString::number(cse->tree.node->id()), widget), row, 1, 1, 2, Qt::AlignLeft); ++row; diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 6e13c21..49a346a 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -222,6 +222,7 @@ private slots: void onSelectedThreadChange(::profiler::thread_id_t _id); void onSelectedBlockChange(unsigned int _block_index); void onRefreshRequired(); + void onThreadViewChanged(); public: diff --git a/profiler_gui/easy_graphics_item.cpp b/profiler_gui/easy_graphics_item.cpp index ee2511e..096a53d 100644 --- a/profiler_gui/easy_graphics_item.cpp +++ b/profiler_gui/easy_graphics_item.cpp @@ -96,7 +96,7 @@ const auto SELECTED_ITEM_FONT = ::profiler_gui::EFont("Helvetica", 10, QFont::Bo EasyGraphicsItem::EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot& _root) : QGraphicsItem(nullptr) - , m_threadName(::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, _root)) + , m_threadName(::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, _root, EASY_GLOBALS.hex_thread_id)) , m_pRoot(&_root) , m_index(_index) { @@ -108,7 +108,7 @@ EasyGraphicsItem::~EasyGraphicsItem() void EasyGraphicsItem::validateName() { - m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, *m_pRoot); + m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, *m_pRoot, EASY_GLOBALS.hex_thread_id); } const EasyGraphicsView* EasyGraphicsItem::view() const diff --git a/profiler_gui/easy_graphics_scrollbar.cpp b/profiler_gui/easy_graphics_scrollbar.cpp index 4c40096..8ae7efc 100644 --- a/profiler_gui/easy_graphics_scrollbar.cpp +++ b/profiler_gui/easy_graphics_scrollbar.cpp @@ -253,6 +253,7 @@ EasyHistogramItem::EasyHistogramItem() : Parent(nullptr) , m_workerImageScale(1) , m_workerTopDuration(0) , m_workerBottomDuration(0) + , m_blockTotalDuraion(0) , m_timer(::std::bind(&This::onTimeout, this)) , m_boundaryTimer([this](){ updateImage(); }, true) , m_pProfilerThread(nullptr) @@ -749,26 +750,15 @@ void EasyHistogramItem::paintById(QPainter* _painter) _painter->setPen(Qt::black); rect.setRect(0, bottom + 2, width, widget->defaultFontHeight()); - const auto* item = !::profiler_gui::is_max(EASY_GLOBALS.selected_block) ? &easyBlock(EASY_GLOBALS.selected_block) : (!m_selectedBlocks.empty() ? &easyBlock(m_selectedBlocks.front()) : nullptr); - if (item != nullptr) + if (!m_selectedBlocks.empty()) { - const auto name = *item->tree.node->name() != 0 ? item->tree.node->name() : easyDescriptor(item->tree.node->id()).name(); - if (item->tree.per_thread_stats != nullptr) - { - _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | %3 calls | %4% of thread profiled time").arg(m_threadName).arg(::profiler_gui::toUnicode(name)) - .arg(item->tree.per_thread_stats->calls_number) - .arg(m_threadProfiledTime ? QString::number(100. * (double)item->tree.per_thread_stats->total_duration / (double)m_threadProfiledTime, 'f', 2) : QString("100"))); - } - else - { - _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | %3 calls").arg(m_threadName).arg(::profiler_gui::toUnicode(name)) - .arg(m_selectedBlocks.size())); - } + _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | %3 calls | %4% of thread profiled time") + .arg(m_threadName).arg(m_blockName).arg(m_selectedBlocks.size()) + .arg(m_threadProfiledTime ? QString::number(100. * (double)m_blockTotalDuraion / (double)m_threadProfiledTime, 'f', 2) : QString("100"))); } else { - _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | %3 calls").arg(m_threadName).arg(::profiler_gui::toUnicode(easyDescriptor(m_blockId).name())) - .arg(m_selectedBlocks.size())); + _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | 0 calls").arg(m_threadName).arg(m_blockName)); } _painter->drawText(rect, Qt::AlignLeft, bindMode ? " MODE: zoom" : " MODE: overview"); @@ -803,13 +793,16 @@ void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, const ::pr if (m_workerThread.joinable()) m_workerThread.join(); + m_blockName.clear(); + m_blockTotalDuraion = 0; + delete m_workerImage; m_workerImage = nullptr; m_imageOriginUpdate = m_imageOrigin = 0; m_imageScaleUpdate = m_imageScale = 1; m_selectedBlocks.clear(); - ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); + { ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); } m_bPermitImageUpdate = false; m_regime = Hist_Pointer; @@ -826,7 +819,7 @@ void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, const ::pr else { const auto& root = EASY_GLOBALS.profiler_blocks[_thread_id]; - m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root); + m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root, EASY_GLOBALS.hex_thread_id); if (root.children.empty()) m_threadDuration = 0; @@ -918,9 +911,6 @@ void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, ::profiler m_bPermitImageUpdate = false; // Set to false because m_workerThread have to parse input data first. This will be set to true when m_workerThread finish - see onTimeout() m_regime = Hist_Id; - m_pSource = nullptr; - m_topDurationStr.clear(); - m_bottomDurationStr.clear(); m_timer.stop(); m_boundaryTimer.stop(); @@ -929,138 +919,173 @@ void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, ::profiler if (m_workerThread.joinable()) m_workerThread.join(); + m_pSource = nullptr; + m_topDurationStr.clear(); + m_bottomDurationStr.clear(); + m_blockName.clear(); + m_blockTotalDuraion = 0; + delete m_workerImage; m_workerImage = nullptr; m_imageOriginUpdate = m_imageOrigin = 0; m_imageScaleUpdate = m_imageScale = 1; m_selectedBlocks.clear(); - ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); + { ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); } m_threadId = _thread_id; m_blockId = _block_id; if (m_threadId != 0 && !::profiler_gui::is_max(m_blockId)) { + m_blockName = ::profiler_gui::toUnicode(easyDescriptor(m_blockId).name()); + const auto& root = EASY_GLOBALS.profiler_blocks[_thread_id]; - m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root); - - if (root.children.empty()) - m_threadDuration = 0; - else - m_threadDuration = easyBlock(root.children.back()).tree.node->end() - easyBlock(root.children.front()).tree.node->begin(); - - m_threadProfiledTime = root.profiled_time; - m_threadWaitTime = root.wait_time; + m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root, EASY_GLOBALS.hex_thread_id); m_pProfilerThread = &root; m_timeUnits = EASY_GLOBALS.time_units; - m_bReady.store(false, ::std::memory_order_release); - m_workerThread = ::std::thread([this](decltype(root) profiler_thread) + if (root.children.empty()) { - typedef ::std::vector<::std::pair<::profiler::block_index_t, ::profiler::block_index_t> > Stack; + m_threadDuration = 0; + m_threadProfiledTime = 0; + m_threadWaitTime = 0; - m_maxDuration = 0; - m_minDuration = 1e30; - //const auto& profiler_thread = EASY_GLOBALS.profiler_blocks[m_threadId]; - Stack stack; - stack.reserve(profiler_thread.depth); + m_topDuration = m_maxDuration = 0; + m_bottomDuration = m_minDuration = 1e30; - for (auto frame : profiler_thread.children) + m_bPermitImageUpdate = true; + + m_bReady.store(true, ::std::memory_order_release); + } + else + { + m_threadDuration = easyBlock(root.children.back()).tree.node->end() - easyBlock(root.children.front()).tree.node->begin(); + m_threadProfiledTime = root.profiled_time; + m_threadWaitTime = root.wait_time; + + m_bReady.store(false, ::std::memory_order_release); + m_workerThread = ::std::thread([this](decltype(root) profiler_thread, ::profiler::block_index_t selected_block) { - const auto& frame_block = easyBlock(frame).tree; - if (frame_block.node->id() == m_blockId) + typedef ::std::vector<::std::pair<::profiler::block_index_t, ::profiler::block_index_t> > Stack; + + m_maxDuration = 0; + m_minDuration = 1e30; + //const auto& profiler_thread = EASY_GLOBALS.profiler_blocks[m_threadId]; + Stack stack; + stack.reserve(profiler_thread.depth); + + const bool has_selected_block = !::profiler_gui::is_max(selected_block); + + for (auto frame : profiler_thread.children) { - m_selectedBlocks.push_back(frame); + const auto& frame_block = easyBlock(frame).tree; + if (frame_block.node->id() == m_blockId || (!has_selected_block && m_blockId == easyDescriptor(frame_block.node->id()).id())) + { + m_selectedBlocks.push_back(frame); - const auto w = frame_block.node->duration(); - if (w > m_maxDuration) - m_maxDuration = w; + const auto w = frame_block.node->duration(); + if (w > m_maxDuration) + m_maxDuration = w; - if (w < m_minDuration) - m_minDuration = w; - } + if (w < m_minDuration) + m_minDuration = w; - stack.push_back(::std::make_pair(frame, 0U)); - while (!stack.empty()) - { - if (m_bReady.load(::std::memory_order_acquire)) - return; + m_blockTotalDuraion += w; + } - auto& top = stack.back(); - const auto& top_children = easyBlock(top.first).tree.children; - const auto stack_size = stack.size(); - for (auto end = top_children.size(); top.second < end; ++top.second) + stack.push_back(::std::make_pair(frame, 0U)); + while (!stack.empty()) { if (m_bReady.load(::std::memory_order_acquire)) return; - const auto child_index = top_children[top.second]; - const auto& child = easyBlock(child_index).tree; - if (child.node->id() == m_blockId) + auto& top = stack.back(); + const auto& top_children = easyBlock(top.first).tree.children; + const auto stack_size = stack.size(); + for (auto end = top_children.size(); top.second < end; ++top.second) { - m_selectedBlocks.push_back(child_index); + if (m_bReady.load(::std::memory_order_acquire)) + return; - const auto w = child.node->duration(); - if (w > m_maxDuration) - m_maxDuration = w; - if (w < m_minDuration) - m_minDuration = w; + const auto child_index = top_children[top.second]; + const auto& child = easyBlock(child_index).tree; + if (child.node->id() == m_blockId || (!has_selected_block && m_blockId == easyDescriptor(child.node->id()).id())) + { + m_selectedBlocks.push_back(child_index); + + const auto w = child.node->duration(); + if (w > m_maxDuration) + m_maxDuration = w; + + if (w < m_minDuration) + m_minDuration = w; + + m_blockTotalDuraion += w; + } + + if (!child.children.empty()) + { + ++top.second; + stack.push_back(::std::make_pair(child_index, 0U)); + break; + } } - if (!child.children.empty()) + if (stack_size == stack.size()) { - ++top.second; - stack.push_back(::std::make_pair(child_index, 0U)); - break; + stack.pop_back(); } } - - if (stack_size == stack.size()) - { - stack.pop_back(); - } } - } - if (m_selectedBlocks.empty()) - { - m_topDurationStr.clear(); - m_bottomDurationStr.clear(); - } - else - { - m_maxDuration *= 1e-3; - m_minDuration *= 1e-3; - - if ((m_maxDuration - m_minDuration) < 1e-3) + if (m_selectedBlocks.empty()) { - if (m_minDuration > 0.1) + m_topDurationStr.clear(); + m_bottomDurationStr.clear(); + } + else + { + if (has_selected_block) { - m_minDuration -= 0.1; + const auto& item = easyBlock(selected_block).tree; + if (*item.node->name() != 0) + m_blockName = ::profiler_gui::toUnicode(item.node->name()); } - else + + m_maxDuration *= 1e-3; + m_minDuration *= 1e-3; + + if ((m_maxDuration - m_minDuration) < 1e-3) { - m_maxDuration = 0.1; - m_minDuration = 0; + if (m_minDuration > 0.1) + { + m_minDuration -= 0.1; + } + else + { + m_maxDuration = 0.1; + m_minDuration = 0; + } } + + m_topDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_maxDuration, 3); + m_bottomDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_minDuration, 3); } - m_topDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_maxDuration, 3); - m_bottomDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_minDuration, 3); - } + m_topDuration = m_maxDuration; + m_bottomDuration = m_minDuration; - m_topDuration = m_maxDuration; - m_bottomDuration = m_minDuration; + m_bReady.store(true, ::std::memory_order_release); - m_bReady.store(true, ::std::memory_order_release); + }, std::ref(root), EASY_GLOBALS.selected_block); - }, std::ref(root)); + m_timeouts = 3; + m_timer.start(WORKER_THREAD_CHECK_INTERVAL); + } - m_timeouts = 3; - m_timer.start(WORKER_THREAD_CHECK_INTERVAL); show(); } else @@ -1077,7 +1102,7 @@ void EasyHistogramItem::validateName() { if (m_threadName.isEmpty()) return; - m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.profiler_blocks[m_threadId]); + m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.profiler_blocks[m_threadId], EASY_GLOBALS.hex_thread_id); } ////////////////////////////////////////////////////////////////////////// @@ -1712,14 +1737,8 @@ EasyGraphicsScrollbar::EasyGraphicsScrollbar(QWidget* _parent) m_histogramItem->onModeChanged(); }); - connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, [this]() - { - if (m_histogramItem->isVisible()) - { - m_histogramItem->validateName(); - scene()->update(); - } - }); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged); centerOn(0, 0); } @@ -1731,6 +1750,17 @@ EasyGraphicsScrollbar::~EasyGraphicsScrollbar() ////////////////////////////////////////////////////////////////////////// +void EasyGraphicsScrollbar::onThreadViewChanged() +{ + if (m_histogramItem->isVisible()) + { + m_histogramItem->validateName(); + scene()->update(); + } +} + +////////////////////////////////////////////////////////////////////////// + void EasyGraphicsScrollbar::clear() { setHistogramSource(0, nullptr); @@ -2003,54 +2033,6 @@ void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event) m_histogramItem->updateImage(); } -////////////////////////////////////////////////////////////////////////// -/* -void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) -{ - if (EASY_GLOBALS.profiler_blocks.empty()) - { - return; - } - - QMenu menu; - - for (const auto& it : EASY_GLOBALS.profiler_blocks) - { - QString label; - if (it.second.got_name()) - label = ::std::move(QString("%1 Thread %2").arg(it.second.name()).arg(it.first)); - else - label = ::std::move(QString("Thread %1").arg(it.first)); - - auto action = new QAction(label, nullptr); - action->setData(it.first); - action->setCheckable(true); - action->setChecked(it.first == EASY_GLOBALS.selected_thread); - connect(action, &QAction::triggered, this, &This::onThreadActionClicked); - - menu.addAction(action); - } - - menu.exec(QCursor::pos()); - _event->accept(); -} -*/ -////////////////////////////////////////////////////////////////////////// - -void EasyGraphicsScrollbar::onThreadActionClicked(bool) -{ - auto action = qobject_cast(sender()); - if (action == nullptr) - return; - - const auto thread_id = action->data().toUInt(); - if (thread_id != EASY_GLOBALS.selected_thread) - { - EASY_GLOBALS.selected_thread = thread_id; - emit EASY_GLOBALS.events.selectedThreadChanged(thread_id); - } -} - ////////////////////////////////////////////////////////////////////////// void EasyGraphicsScrollbar::onWindowWidthChange(qreal _width) diff --git a/profiler_gui/easy_graphics_scrollbar.h b/profiler_gui/easy_graphics_scrollbar.h index f7bd0e2..3adf61f 100644 --- a/profiler_gui/easy_graphics_scrollbar.h +++ b/profiler_gui/easy_graphics_scrollbar.h @@ -157,9 +157,11 @@ class EasyHistogramItem : public QGraphicsItem qreal m_workerImageScale; qreal m_workerTopDuration; qreal m_workerBottomDuration; + ::profiler::timestamp_t m_blockTotalDuraion; QString m_topDurationStr; QString m_bottomDurationStr; QString m_threadName; + QString m_blockName; ::profiler::BlocksTree::children_t m_selectedBlocks; QImage m_mainImage; EasyQTimer m_timer; @@ -270,7 +272,6 @@ public: void mouseMoveEvent(QMouseEvent* _event) override; void wheelEvent(QWheelEvent* _event) override; void resizeEvent(QResizeEvent* _event) override; - //void contextMenuEvent(QContextMenuEvent* _event) override; void dragEnterEvent(QDragEnterEvent*) override {} @@ -325,7 +326,7 @@ signals: private slots: - void onThreadActionClicked(bool); + void onThreadViewChanged(); void onWindowWidthChange(qreal _width); }; // END of class EasyGraphicsScrollbar. diff --git a/profiler_gui/globals.cpp b/profiler_gui/globals.cpp index 6e1c718..9b4d0b4 100644 --- a/profiler_gui/globals.cpp +++ b/profiler_gui/globals.cpp @@ -84,6 +84,7 @@ namespace profiler_gui { , connected(false) , fps_enabled(true) , use_decorated_thread_name(false) + , hex_thread_id(false) , enable_event_markers(true) , enable_statistics(true) , enable_zero_length(true) diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index cd094e4..0e35a2c 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -101,29 +101,47 @@ namespace profiler_gui { ////////////////////////////////////////////////////////////////////////// - inline QString decoratedThreadName(bool _use_decorated_thread_name, const::profiler::BlocksTreeRoot& _root, const QString& _unicodeThreadWord) + inline QString decoratedThreadName(bool _use_decorated_thread_name, const::profiler::BlocksTreeRoot& _root, const QString& _unicodeThreadWord, bool _hex = false) { if (_root.got_name()) { QString rootname(toUnicode(_root.name())); if (!_use_decorated_thread_name || rootname.contains(_unicodeThreadWord, Qt::CaseInsensitive)) + { + if (_hex) + return QString("%1 0x%2").arg(rootname).arg(_root.thread_id, 0, 16); return QString("%1 %2").arg(rootname).arg(_root.thread_id); + } + + if (_hex) + return QString("%1 Thread 0x%2").arg(rootname).arg(_root.thread_id, 0, 16); return QString("%1 Thread %2").arg(rootname).arg(_root.thread_id); } + if (_hex) + return QString("Thread 0x%1").arg(_root.thread_id, 0, 16); return QString("Thread %1").arg(_root.thread_id); } - inline QString decoratedThreadName(bool _use_decorated_thread_name, const ::profiler::BlocksTreeRoot& _root) + inline QString decoratedThreadName(bool _use_decorated_thread_name, const ::profiler::BlocksTreeRoot& _root, bool _hex = false) { if (_root.got_name()) { QString rootname(toUnicode(_root.name())); if (!_use_decorated_thread_name || rootname.contains(toUnicode("thread"), Qt::CaseInsensitive)) + { + if (_hex) + return QString("%1 0x%2").arg(rootname).arg(_root.thread_id, 0, 16); return QString("%1 %2").arg(rootname).arg(_root.thread_id); + } + + if (_hex) + return QString("%1 Thread 0x%2").arg(rootname).arg(_root.thread_id, 0, 16); return QString("%1 Thread %2").arg(rootname).arg(_root.thread_id); } + if (_hex) + return QString("Thread 0x%1").arg(_root.thread_id, 0, 16); return QString("Thread %1").arg(_root.thread_id); } @@ -163,6 +181,7 @@ namespace profiler_gui { bool connected; ///< Is connected to source (to be able to capture profiling information) bool fps_enabled; ///< Is FPS Monitor enabled bool use_decorated_thread_name; ///< Add "Thread" to the name of each thread (if there is no one) + bool hex_thread_id; ///< Use hex view for thread-id instead of decimal bool enable_event_markers; ///< Enable event indicators painting (These are narrow rectangles at the bottom of each thread) bool enable_statistics; ///< Enable gathering and using statistics (Disable if you want to consume less memory) bool enable_zero_length; ///< Enable zero length blocks (if true, then such blocks will have width == 1 pixel on each scale) diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index 7cfa330..664c7cc 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -82,6 +82,7 @@ namespace profiler_gui { void autoAdjustHistogramChanged(); void hierarchyFlagChanged(bool); void threadNameDecorationChanged(); + void hexThreadIdChanged(); void refreshRequired(); void blocksTreeModeChanged(); diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 2a4cb46..5faf31a 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -385,6 +385,16 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("localhost"), m_lastP emit EASY_GLOBALS.events.threadNameDecorationChanged(); }); + action = submenu->addAction("Display hex thread id"); + action->setToolTip("Display hex thread id instead of decimal."); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.hex_thread_id); + connect(action, &QAction::triggered, [this](bool _checked) + { + EASY_GLOBALS.hex_thread_id = _checked; + emit EASY_GLOBALS.events.hexThreadIdChanged(); + }); + submenu->addSeparator(); auto actionGroup = new QActionGroup(this); actionGroup->setExclusive(true); @@ -1264,6 +1274,10 @@ void EasyMainWindow::loadSettings() if (!flag.isNull()) EASY_GLOBALS.use_decorated_thread_name = flag.toBool(); + flag = settings.value("hex_thread_id"); + if (!flag.isNull()) + EASY_GLOBALS.hex_thread_id = flag.toBool(); + flag = settings.value("fps_timer_interval"); if (!flag.isNull()) EASY_GLOBALS.fps_timer_interval = flag.toInt(); @@ -1334,6 +1348,7 @@ void EasyMainWindow::saveSettingsAndGeometry() settings.setValue("enable_event_indicators", EASY_GLOBALS.enable_event_markers); settings.setValue("auto_adjust_histogram_height", EASY_GLOBALS.auto_adjust_histogram_height); settings.setValue("use_decorated_thread_name", EASY_GLOBALS.use_decorated_thread_name); + settings.setValue("hex_thread_id", EASY_GLOBALS.hex_thread_id); settings.setValue("enable_statistics", EASY_GLOBALS.enable_statistics); settings.setValue("fps_timer_interval", EASY_GLOBALS.fps_timer_interval); settings.setValue("max_fps_history", EASY_GLOBALS.max_fps_history); diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index b3cbaea..d582075 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -176,7 +176,7 @@ void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const u m_mode = _mode; m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal1, this, ::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows, - EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.time_units); + EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.hex_thread_id, EASY_GLOBALS.time_units); } void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, EasyTreeMode _mode) @@ -185,12 +185,12 @@ void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _bloc m_mode = _mode; m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal2, this, _beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows, - EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.time_units); + EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.hex_thread_id, EASY_GLOBALS.time_units); } ////////////////////////////////////////////////////////////////////////// -void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units) +void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units) { m_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks @@ -219,7 +219,7 @@ void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime, const auto& root = threadTree.second; auto item = new EasyTreeWidgetItem(); - item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, root, u_thread)); + item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, root, u_thread, _hexThreadId)); ::profiler::timestamp_t duration = 0; if (!root.children.empty()) @@ -268,7 +268,7 @@ void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime, typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::block_index_t, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> BeginEndIndicesMap; -void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units) +void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units) { //size_t blocksNumber = 0; //for (const auto& block : _blocks) @@ -309,7 +309,7 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi else { thread_item = new EasyTreeWidgetItem(); - thread_item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, *block.root, u_thread)); + thread_item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, *block.root, u_thread, _hexThreadId)); if (!block.root->children.empty()) duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin(); diff --git a/profiler_gui/tree_widget_loader.h b/profiler_gui/tree_widget_loader.h index ebda2e7..8fe3085 100644 --- a/profiler_gui/tree_widget_loader.h +++ b/profiler_gui/tree_widget_loader.h @@ -122,8 +122,8 @@ private: void setDone(); void setProgress(int _progress); - void setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units); - void setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units); + void setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units); + void setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units); size_t setTreeInternal(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units); size_t setTreeInternalPlain(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);