0
0
mirror of https://github.com/yse/easy_profiler.git synced 2025-01-14 08:37:55 +08:00

(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
This commit is contained in:
Victor Zarubkin 2017-06-05 21:26:10 +03:00
parent 65ac892e32
commit 089fcf1e31
11 changed files with 221 additions and 189 deletions

View File

@ -1368,21 +1368,8 @@ void EasyGraphicsView::initMode()
onRefreshRequired(); onRefreshRequired();
}); });
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, [this]() connect(globalSignals, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged);
{ connect(globalSignals, &::profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged);
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::blocksTreeModeChanged, [this]() 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) void EasyGraphicsView::onScrollbarValueChange(int)
{ {
if (!m_bUpdatingRect && !m_bEmpty) if (!m_bUpdatingRect && !m_bEmpty)
@ -1675,7 +1680,14 @@ void EasyGraphicsView::onIdleTimeout()
lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight); lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight);
auto it = EASY_GLOBALS.profiler_blocks.find(cse->tree.node->id()); auto it = EASY_GLOBALS.profiler_blocks.find(cse->tree.node->id());
if (it != EASY_GLOBALS.profiler_blocks.end()) 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 else
lay->addWidget(new QLabel(QString::number(cse->tree.node->id()), widget), row, 1, 1, 2, Qt::AlignLeft); lay->addWidget(new QLabel(QString::number(cse->tree.node->id()), widget), row, 1, 1, 2, Qt::AlignLeft);
++row; ++row;

View File

@ -222,6 +222,7 @@ private slots:
void onSelectedThreadChange(::profiler::thread_id_t _id); void onSelectedThreadChange(::profiler::thread_id_t _id);
void onSelectedBlockChange(unsigned int _block_index); void onSelectedBlockChange(unsigned int _block_index);
void onRefreshRequired(); void onRefreshRequired();
void onThreadViewChanged();
public: public:

View File

@ -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) EasyGraphicsItem::EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot& _root)
: QGraphicsItem(nullptr) : 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_pRoot(&_root)
, m_index(_index) , m_index(_index)
{ {
@ -108,7 +108,7 @@ EasyGraphicsItem::~EasyGraphicsItem()
void EasyGraphicsItem::validateName() 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 const EasyGraphicsView* EasyGraphicsItem::view() const

View File

@ -253,6 +253,7 @@ EasyHistogramItem::EasyHistogramItem() : Parent(nullptr)
, m_workerImageScale(1) , m_workerImageScale(1)
, m_workerTopDuration(0) , m_workerTopDuration(0)
, m_workerBottomDuration(0) , m_workerBottomDuration(0)
, m_blockTotalDuraion(0)
, m_timer(::std::bind(&This::onTimeout, this)) , m_timer(::std::bind(&This::onTimeout, this))
, m_boundaryTimer([this](){ updateImage(); }, true) , m_boundaryTimer([this](){ updateImage(); }, true)
, m_pProfilerThread(nullptr) , m_pProfilerThread(nullptr)
@ -749,26 +750,15 @@ void EasyHistogramItem::paintById(QPainter* _painter)
_painter->setPen(Qt::black); _painter->setPen(Qt::black);
rect.setRect(0, bottom + 2, width, widget->defaultFontHeight()); 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 (!m_selectedBlocks.empty())
if (item != nullptr)
{ {
const auto name = *item->tree.node->name() != 0 ? item->tree.node->name() : easyDescriptor(item->tree.node->id()).name(); _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | %3 calls | %4% of thread profiled time")
if (item->tree.per_thread_stats != nullptr) .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")));
_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()));
}
} }
else else
{ {
_painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | %3 calls").arg(m_threadName).arg(::profiler_gui::toUnicode(easyDescriptor(m_blockId).name())) _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | 0 calls").arg(m_threadName).arg(m_blockName));
.arg(m_selectedBlocks.size()));
} }
_painter->drawText(rect, Qt::AlignLeft, bindMode ? " MODE: zoom" : " MODE: overview"); _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()) if (m_workerThread.joinable())
m_workerThread.join(); m_workerThread.join();
m_blockName.clear();
m_blockTotalDuraion = 0;
delete m_workerImage; delete m_workerImage;
m_workerImage = nullptr; m_workerImage = nullptr;
m_imageOriginUpdate = m_imageOrigin = 0; m_imageOriginUpdate = m_imageOrigin = 0;
m_imageScaleUpdate = m_imageScale = 1; m_imageScaleUpdate = m_imageScale = 1;
m_selectedBlocks.clear(); m_selectedBlocks.clear();
::profiler::BlocksTree::children_t().swap(m_selectedBlocks); { ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); }
m_bPermitImageUpdate = false; m_bPermitImageUpdate = false;
m_regime = Hist_Pointer; m_regime = Hist_Pointer;
@ -826,7 +819,7 @@ void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, const ::pr
else else
{ {
const auto& root = EASY_GLOBALS.profiler_blocks[_thread_id]; 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()) if (root.children.empty())
m_threadDuration = 0; 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_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_regime = Hist_Id;
m_pSource = nullptr;
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_timer.stop(); m_timer.stop();
m_boundaryTimer.stop(); m_boundaryTimer.stop();
@ -929,138 +919,173 @@ void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, ::profiler
if (m_workerThread.joinable()) if (m_workerThread.joinable())
m_workerThread.join(); m_workerThread.join();
m_pSource = nullptr;
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_blockName.clear();
m_blockTotalDuraion = 0;
delete m_workerImage; delete m_workerImage;
m_workerImage = nullptr; m_workerImage = nullptr;
m_imageOriginUpdate = m_imageOrigin = 0; m_imageOriginUpdate = m_imageOrigin = 0;
m_imageScaleUpdate = m_imageScale = 1; m_imageScaleUpdate = m_imageScale = 1;
m_selectedBlocks.clear(); m_selectedBlocks.clear();
::profiler::BlocksTree::children_t().swap(m_selectedBlocks); { ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); }
m_threadId = _thread_id; m_threadId = _thread_id;
m_blockId = _block_id; m_blockId = _block_id;
if (m_threadId != 0 && !::profiler_gui::is_max(m_blockId)) 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]; 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;
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_pProfilerThread = &root; m_pProfilerThread = &root;
m_timeUnits = EASY_GLOBALS.time_units; m_timeUnits = EASY_GLOBALS.time_units;
m_bReady.store(false, ::std::memory_order_release); if (root.children.empty())
m_workerThread = ::std::thread([this](decltype(root) profiler_thread)
{ {
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_topDuration = m_maxDuration = 0;
m_minDuration = 1e30; m_bottomDuration = m_minDuration = 1e30;
//const auto& profiler_thread = EASY_GLOBALS.profiler_blocks[m_threadId];
Stack stack;
stack.reserve(profiler_thread.depth);
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; typedef ::std::vector<::std::pair<::profiler::block_index_t, ::profiler::block_index_t> > Stack;
if (frame_block.node->id() == m_blockId)
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(); const auto w = frame_block.node->duration();
if (w > m_maxDuration) if (w > m_maxDuration)
m_maxDuration = w; m_maxDuration = w;
if (w < m_minDuration) if (w < m_minDuration)
m_minDuration = w; m_minDuration = w;
}
stack.push_back(::std::make_pair(frame, 0U)); m_blockTotalDuraion += w;
while (!stack.empty()) }
{
if (m_bReady.load(::std::memory_order_acquire))
return;
auto& top = stack.back(); stack.push_back(::std::make_pair(frame, 0U));
const auto& top_children = easyBlock(top.first).tree.children; while (!stack.empty())
const auto stack_size = stack.size();
for (auto end = top_children.size(); top.second < end; ++top.second)
{ {
if (m_bReady.load(::std::memory_order_acquire)) if (m_bReady.load(::std::memory_order_acquire))
return; return;
const auto child_index = top_children[top.second]; auto& top = stack.back();
const auto& child = easyBlock(child_index).tree; const auto& top_children = easyBlock(top.first).tree.children;
if (child.node->id() == m_blockId) 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(); const auto child_index = top_children[top.second];
if (w > m_maxDuration) const auto& child = easyBlock(child_index).tree;
m_maxDuration = w; if (child.node->id() == m_blockId || (!has_selected_block && m_blockId == easyDescriptor(child.node->id()).id()))
if (w < m_minDuration) {
m_minDuration = w; 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.pop_back();
stack.push_back(::std::make_pair(child_index, 0U));
break;
} }
} }
if (stack_size == stack.size())
{
stack.pop_back();
}
} }
}
if (m_selectedBlocks.empty()) 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_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; if (m_minDuration > 0.1)
m_minDuration = 0; {
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_bReady.store(true, ::std::memory_order_release);
m_bottomDuration = m_minDuration;
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(); show();
} }
else else
@ -1077,7 +1102,7 @@ void EasyHistogramItem::validateName()
{ {
if (m_threadName.isEmpty()) if (m_threadName.isEmpty())
return; 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(); m_histogramItem->onModeChanged();
}); });
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, [this]() connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged);
{ connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged);
if (m_histogramItem->isVisible())
{
m_histogramItem->validateName();
scene()->update();
}
});
centerOn(0, 0); centerOn(0, 0);
} }
@ -1731,6 +1750,17 @@ EasyGraphicsScrollbar::~EasyGraphicsScrollbar()
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void EasyGraphicsScrollbar::onThreadViewChanged()
{
if (m_histogramItem->isVisible())
{
m_histogramItem->validateName();
scene()->update();
}
}
//////////////////////////////////////////////////////////////////////////
void EasyGraphicsScrollbar::clear() void EasyGraphicsScrollbar::clear()
{ {
setHistogramSource(0, nullptr); setHistogramSource(0, nullptr);
@ -2003,54 +2033,6 @@ void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
m_histogramItem->updateImage(); 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<QAction*>(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) void EasyGraphicsScrollbar::onWindowWidthChange(qreal _width)

View File

@ -157,9 +157,11 @@ class EasyHistogramItem : public QGraphicsItem
qreal m_workerImageScale; qreal m_workerImageScale;
qreal m_workerTopDuration; qreal m_workerTopDuration;
qreal m_workerBottomDuration; qreal m_workerBottomDuration;
::profiler::timestamp_t m_blockTotalDuraion;
QString m_topDurationStr; QString m_topDurationStr;
QString m_bottomDurationStr; QString m_bottomDurationStr;
QString m_threadName; QString m_threadName;
QString m_blockName;
::profiler::BlocksTree::children_t m_selectedBlocks; ::profiler::BlocksTree::children_t m_selectedBlocks;
QImage m_mainImage; QImage m_mainImage;
EasyQTimer m_timer; EasyQTimer m_timer;
@ -270,7 +272,6 @@ public:
void mouseMoveEvent(QMouseEvent* _event) override; void mouseMoveEvent(QMouseEvent* _event) override;
void wheelEvent(QWheelEvent* _event) override; void wheelEvent(QWheelEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override; void resizeEvent(QResizeEvent* _event) override;
//void contextMenuEvent(QContextMenuEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {} void dragEnterEvent(QDragEnterEvent*) override {}
@ -325,7 +326,7 @@ signals:
private slots: private slots:
void onThreadActionClicked(bool); void onThreadViewChanged();
void onWindowWidthChange(qreal _width); void onWindowWidthChange(qreal _width);
}; // END of class EasyGraphicsScrollbar. }; // END of class EasyGraphicsScrollbar.

View File

@ -84,6 +84,7 @@ namespace profiler_gui {
, connected(false) , connected(false)
, fps_enabled(true) , fps_enabled(true)
, use_decorated_thread_name(false) , use_decorated_thread_name(false)
, hex_thread_id(false)
, enable_event_markers(true) , enable_event_markers(true)
, enable_statistics(true) , enable_statistics(true)
, enable_zero_length(true) , enable_zero_length(true)

View File

@ -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()) if (_root.got_name())
{ {
QString rootname(toUnicode(_root.name())); QString rootname(toUnicode(_root.name()));
if (!_use_decorated_thread_name || rootname.contains(_unicodeThreadWord, Qt::CaseInsensitive)) 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); 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); 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); 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()) if (_root.got_name())
{ {
QString rootname(toUnicode(_root.name())); QString rootname(toUnicode(_root.name()));
if (!_use_decorated_thread_name || rootname.contains(toUnicode("thread"), Qt::CaseInsensitive)) 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); 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); 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); 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 connected; ///< Is connected to source (to be able to capture profiling information)
bool fps_enabled; ///< Is FPS Monitor enabled 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 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_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_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) bool enable_zero_length; ///< Enable zero length blocks (if true, then such blocks will have width == 1 pixel on each scale)

View File

@ -82,6 +82,7 @@ namespace profiler_gui {
void autoAdjustHistogramChanged(); void autoAdjustHistogramChanged();
void hierarchyFlagChanged(bool); void hierarchyFlagChanged(bool);
void threadNameDecorationChanged(); void threadNameDecorationChanged();
void hexThreadIdChanged();
void refreshRequired(); void refreshRequired();
void blocksTreeModeChanged(); void blocksTreeModeChanged();

View File

@ -385,6 +385,16 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("localhost"), m_lastP
emit EASY_GLOBALS.events.threadNameDecorationChanged(); 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(); submenu->addSeparator();
auto actionGroup = new QActionGroup(this); auto actionGroup = new QActionGroup(this);
actionGroup->setExclusive(true); actionGroup->setExclusive(true);
@ -1264,6 +1274,10 @@ void EasyMainWindow::loadSettings()
if (!flag.isNull()) if (!flag.isNull())
EASY_GLOBALS.use_decorated_thread_name = flag.toBool(); 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"); flag = settings.value("fps_timer_interval");
if (!flag.isNull()) if (!flag.isNull())
EASY_GLOBALS.fps_timer_interval = flag.toInt(); 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("enable_event_indicators", EASY_GLOBALS.enable_event_markers);
settings.setValue("auto_adjust_histogram_height", EASY_GLOBALS.auto_adjust_histogram_height); 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("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("enable_statistics", EASY_GLOBALS.enable_statistics);
settings.setValue("fps_timer_interval", EASY_GLOBALS.fps_timer_interval); settings.setValue("fps_timer_interval", EASY_GLOBALS.fps_timer_interval);
settings.setValue("max_fps_history", EASY_GLOBALS.max_fps_history); settings.setValue("max_fps_history", EASY_GLOBALS.max_fps_history);

View File

@ -176,7 +176,7 @@ void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const u
m_mode = _mode; m_mode = _mode;
m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal1, this, m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal1, this,
::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows, ::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) 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_mode = _mode;
m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal2, this, m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal2, this,
_beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows, _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 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; const auto& root = threadTree.second;
auto item = new EasyTreeWidgetItem(); 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; ::profiler::timestamp_t duration = 0;
if (!root.children.empty()) 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; 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; //size_t blocksNumber = 0;
//for (const auto& block : _blocks) //for (const auto& block : _blocks)
@ -309,7 +309,7 @@ void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _begi
else else
{ {
thread_item = new EasyTreeWidgetItem(); 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()) if (!block.root->children.empty())
duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin(); duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin();

View File

@ -122,8 +122,8 @@ private:
void setDone(); void setDone();
void setProgress(int _progress); 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 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, ::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 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); 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);