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

(GUI) Added flag for enabling zero length blocks on diagram (if NOT enabled then such blocks would be resized to minimum length which is 250 ns. Otherwise you probably will not see blocks with zero length on diagram, but such blocks are still available at hierarchy window)

This commit is contained in:
Victor Zarubkin 2016-11-23 22:54:59 +03:00
parent 53fd4df281
commit a7ac056021
7 changed files with 142 additions and 42 deletions

View File

@ -166,6 +166,9 @@ void EasyBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte
if (dh > 0)
rect.setHeight(rect.height() - dh);
if (rect.top() < 0)
rect.setTop(0);
_painter->drawRect(rect);
}
}
@ -559,10 +562,10 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, ::profiler::block_index
// xbegin -= dt;
//}
if (duration < MIN_DURATION)
{
duration = MIN_DURATION;
}
//if (duration < MIN_DURATION)
//{
// duration = MIN_DURATION;
//}
auto i = _item->addItem(level);
auto& b = _item->getItem(level, i);
@ -868,7 +871,7 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
}
}
const ::profiler_gui::EasyBlockItem* selectedBlock = nullptr;
const ::profiler_gui::EasyBlock* selectedBlock = nullptr;
const auto previouslySelectedBlock = EASY_GLOBALS.selected_block;
if (m_mouseButtons & Qt::LeftButton)
{
@ -900,12 +903,13 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
// Try to select one of item blocks
for (auto item : m_items)
{
auto block = item->intersect(mouseClickPos);
::profiler::block_index_t i = ~0U;
auto block = item->intersect(mouseClickPos, i);
if (block)
{
changedSelectedItem = true;
selectedBlock = block;
EASY_GLOBALS.selected_block = block->block;
EASY_GLOBALS.selected_block = i;
break;
}
}
@ -934,7 +938,7 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
if (changedSelectedItem)
{
m_bUpdatingRect = true;
if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !blocksTree(selectedBlock->block).children.empty())
if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !selectedBlock->tree.children.empty())
{
EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
emit EASY_GLOBALS.events.itemsExpandStateChanged();
@ -1293,30 +1297,44 @@ void EasyGraphicsView::onIdleTimeout()
// Try to select one of context switches or items
for (auto item : m_items)
{
auto block = item->intersect(pos);
::profiler::block_index_t i = ~0U;
auto block = item->intersect(pos, i);
if (block)
{
const auto& itemBlock = blocksTree(block->block);
auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : easyDescriptor(itemBlock.node->id()).name();
const auto& itemBlock = block->tree;
const auto& itemDesc = easyDescriptor(itemBlock.node->id());
auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : itemDesc.name();
auto widget = new QWidget();
auto lay = new QFormLayout(widget);
lay->setLabelAlignment(Qt::AlignRight);
lay->addRow("Name:", new QLabel(name));
lay->addRow("Duration:", new QLabel(::profiler_gui::timeStringReal(PROF_MICROSECONDS(itemBlock.node->duration()), 3)));
if (itemDesc.type() == ::profiler::BLOCK_TYPE_BLOCK)
{
lay->addRow("Block:", new QLabel(name));
lay->addRow("Duration:", new QLabel(::profiler_gui::timeStringReal(PROF_MICROSECONDS(itemBlock.node->duration()), 3)));
}
else
{
lay->addRow("Event:", new QLabel(name));
}
if (itemBlock.per_thread_stats)
{
lay->addRow("%/Thread:", new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration, item->root()->active_time))));
lay->addRow("N/Thread:", new QLabel(QString::number(itemBlock.per_thread_stats->calls_number)));
if (itemBlock.per_parent_stats->parent_block == item->threadId())
if (itemDesc.type() == ::profiler::BLOCK_TYPE_BLOCK)
{
auto percent = ::profiler_gui::percentReal(itemBlock.node->duration(), item->root()->active_time);
lay->addRow("%:", new QLabel(percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent))));
}
else
{
auto percent = ::profiler_gui::percentReal(itemBlock.node->duration(), blocksTree(itemBlock.per_parent_stats->parent_block).node->duration());
lay->addRow("%:", new QLabel(percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent))));
lay->addRow("%/Thread:", new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration, item->root()->active_time))));
if (itemBlock.per_parent_stats->parent_block == item->threadId())
{
auto percent = ::profiler_gui::percentReal(itemBlock.node->duration(), item->root()->active_time);
lay->addRow("%:", new QLabel(percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent))));
}
else
{
auto percent = ::profiler_gui::percentReal(itemBlock.node->duration(), blocksTree(itemBlock.per_parent_stats->parent_block).node->duration());
lay->addRow("%:", new QLabel(percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent))));
}
}
}

View File

@ -197,6 +197,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
}
const auto MIN_WIDTH = EASY_GLOBALS.enable_zero_length ? 0.f : 0.25f;
// Iterate through layers and draw visible items
if (gotItems)
@ -299,8 +301,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
continue;
}
const auto item_width = ::std::max(item.width(), MIN_WIDTH);
auto x = item.left() * currentScale - dx;
auto w = item.width() * currentScale;
auto w = item_width * currentScale;
if (x + w <= prevRight)
{
// This item is not visible
@ -468,8 +471,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
if (item.left() < sceneRight && item.right() > sceneLeft)
{
const auto& itemBlock = easyBlock(item.block);
const auto item_width = ::std::max(item.width(), MIN_WIDTH);
auto top = levelY(guiblock.graphics_item_level);
auto w = ::std::max(item.width() * currentScale, 1.0);
auto w = ::std::max(item_width * currentScale, 1.0);
decltype(top) h = (!itemBlock.expanded ||
(w < EASY_GLOBALS.blocks_narrow_size && EASY_GLOBALS.hide_narrow_children))
? (itemBlock.tree.depth * ::profiler_gui::GRAPHICS_ROW_SIZE_FULL + ::profiler_gui::GRAPHICS_ROW_SIZE)
@ -652,13 +656,15 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
if (left > sceneRight)
break; // This is first totally invisible item. No need to check other items.
decltype(left) width = 0.25;
decltype(left) width = MIN_WIDTH;
if (left + width < sceneLeft) // This item is not visible
continue;
left *= currentScale;
left -= dx;
width *= currentScale;
if (width < 2) width = 2;
if (left + width <= prevRight) // This item is not visible
continue;
@ -757,7 +763,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree
//////////////////////////////////////////////////////////////////////////
const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const
const ::profiler_gui::EasyBlock* EasyGraphicsItem::intersect(const QPointF& _pos, ::profiler::block_index_t& _blockIndex) const
{
if (m_levels.empty() || m_levels.front().empty())
{
@ -772,7 +778,8 @@ const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF&
return nullptr;
}
const auto bottom = top + m_levels.size() * ::profiler_gui::GRAPHICS_ROW_SIZE_FULL;
static const auto OVERLAP = ::profiler_gui::THREADS_ROW_SPACING >> 1;
const auto bottom = top + m_levels.size() * ::profiler_gui::GRAPHICS_ROW_SIZE_FULL + OVERLAP;
if (bottom < _pos.y())
{
return nullptr;
@ -781,10 +788,58 @@ const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF&
const unsigned int levelIndex = static_cast<unsigned int>(_pos.y() - top) / ::profiler_gui::GRAPHICS_ROW_SIZE_FULL;
if (levelIndex >= m_levels.size())
{
// The Y position is out of blocks range
if (EASY_GLOBALS.enable_event_indicators && !m_pRoot->events.empty())
{
// If event indicators are enabled then try to intersect with one of event indicators
const auto& sceneView = view();
auto first = ::std::lower_bound(m_pRoot->events.begin(), m_pRoot->events.end(), _pos.x(), [&sceneView](::profiler::block_index_t _index, qreal _value)
{
return sceneView->time2position(blocksTree(_index).node->begin()) < _value;
});
if (first != m_pRoot->events.end())
{
if (first != m_pRoot->events.begin())
--first;
}
else if (!m_pRoot->events.empty())
{
first = m_pRoot->events.begin() + m_pRoot->events.size() - 1;
}
const auto MIN_WIDTH = EASY_GLOBALS.enable_zero_length ? 0.f : 0.25f;
const auto currentScale = sceneView->scale();
const auto dw = 5. / currentScale;
for (auto it = first, end = m_pRoot->events.end(); it != end; ++it)
{
_blockIndex = *it;
const auto& item = easyBlock(_blockIndex);
auto left = sceneView->time2position(item.tree.node->begin());
if (left - dw > _pos.x())
break; // This is first totally invisible item. No need to check other items.
decltype(left) width = MIN_WIDTH;
if (left + width + dw < _pos.x()) // This item is not visible
continue;
return &item;
}
}
return nullptr;
}
// The Y position is inside blocks range
const auto MIN_WIDTH = EASY_GLOBALS.enable_zero_length ? 0.f : 0.25f;
const auto currentScale = view()->scale();
const auto dw = 5. / currentScale;
unsigned int i = 0;
size_t itemIndex = ::std::numeric_limits<size_t>::max();
size_t firstItem = 0, lastItem = static_cast<unsigned int>(level0.size());
@ -814,20 +869,23 @@ const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF&
const auto& item = level[itemIndex];
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max(item.children_begin);
if (item.left() > _pos.x())
if (item.left() - dw > _pos.x())
{
return nullptr;
}
if (item.right() < _pos.x())
const auto item_width = ::std::max(item.width(), MIN_WIDTH);
if (item.left() + item_width + dw < _pos.x())
{
continue;
}
const auto w = item.width() * currentScale;
if (i == levelIndex || (w < EASY_GLOBALS.blocks_narrow_size && EASY_GLOBALS.hide_narrow_children) || !easyBlock(item.block).expanded)
const auto w = item_width * currentScale;
const auto& guiItem = easyBlock(item.block);
if (i == levelIndex || (w < EASY_GLOBALS.blocks_narrow_size && EASY_GLOBALS.hide_narrow_children) || !guiItem.expanded)
{
return &item;
_blockIndex = item.block;
return &guiItem;
}
if (item.children_begin == MAX_CHILD_INDEX)
@ -909,15 +967,16 @@ const ::profiler_gui::EasyBlock* EasyGraphicsItem::intersectEvent(const QPointF&
else if (firstSync != m_pRoot->sync.begin())
--firstSync;
const auto dw = 4. / view()->scale();
for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it)
{
const auto& item = easyBlock(*it);
const auto left = sceneView->time2position(item.tree.node->begin()) - 2;
const auto left = sceneView->time2position(item.tree.node->begin()) - dw;
if (left > _pos.x())
break;
const auto right = sceneView->time2position(item.tree.node->end()) + 2;
const auto right = sceneView->time2position(item.tree.node->end()) + dw;
if (right < _pos.x())
continue;

View File

@ -148,7 +148,7 @@ public:
\param _blocks Reference to the array of selected blocks */
void getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const;
const ::profiler_gui::EasyBlockItem* intersect(const QPointF& _pos) const;
const ::profiler_gui::EasyBlock* intersect(const QPointF& _pos, ::profiler::block_index_t& _blockIndex) const;
const ::profiler_gui::EasyBlock* intersectEvent(const QPointF& _pos) const;
private:

View File

@ -68,6 +68,7 @@ namespace profiler_gui {
, connected(false)
, enable_event_indicators(true)
, enable_statistics(true)
, enable_zero_length(true)
, draw_graphics_items_borders(true)
, hide_narrow_children(false)
, display_only_relevant_stats(true)

View File

@ -118,6 +118,7 @@ namespace profiler_gui {
bool connected; ///< Is connected to source (to be able to capture profiling information)
bool enable_event_indicators; ///< 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)
bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not
bool hide_narrow_children; ///< Hide children for narrow graphics blocks
bool display_only_relevant_stats; ///< Display only relevant information in ProfTreeWidget (excludes min, max, average times if there are only 1 calls number)

View File

@ -261,6 +261,11 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("127.0.0.1"), m_lastP
action->setChecked(EASY_GLOBALS.only_current_thread_hierarchy);
connect(action, &QAction::triggered, this, &This::onHierarchyFlagChange);
action = submenu->addAction("Enable zero length blocks");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.enable_zero_length);
connect(action, &QAction::triggered, [this](bool _checked){ EASY_GLOBALS.enable_zero_length = _checked; refreshDiagram(); });
action = submenu->addAction("Collapse items on tree reset");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.collapse_items_on_tree_close);
@ -608,6 +613,15 @@ void EasyMainWindow::clear()
m_bNetworkFileRegime = false;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow::refreshDiagram()
{
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow::onDeleteClicked(bool)
{
auto button = QMessageBox::question(this, "Clear all profiled data", "All profiled data is going to be deleted!\nContinue?", QMessageBox::Yes, QMessageBox::No);
@ -636,13 +650,13 @@ void EasyMainWindow::onChronoTextPosChanged(bool)
{
auto _sender = qobject_cast<QAction*>(sender());
EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(_sender->data().toInt());
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
void EasyMainWindow::onEventIndicatorsChange(bool _checked)
{
EASY_GLOBALS.enable_event_indicators = _checked;
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
void EasyMainWindow::onEnableDisableStatistics(bool _checked)
@ -672,13 +686,13 @@ void EasyMainWindow::onEnableDisableStatistics(bool _checked)
void EasyMainWindow::onDrawBordersChanged(bool _checked)
{
EASY_GLOBALS.draw_graphics_items_borders = _checked;
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
void EasyMainWindow::onHideNarrowChildrenChanged(bool _checked)
{
EASY_GLOBALS.hide_narrow_children = _checked;
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
void EasyMainWindow::onCollapseItemsAfterCloseChanged(bool _checked)
@ -733,19 +747,19 @@ void EasyMainWindow::onCollapseAllClicked(bool)
void EasyMainWindow::onSpacingChange(int _value)
{
EASY_GLOBALS.blocks_spacing = _value;
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
void EasyMainWindow::onMinSizeChange(int _value)
{
EASY_GLOBALS.blocks_size_min = _value;
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
void EasyMainWindow::onNarrowSizeChange(int _value)
{
EASY_GLOBALS.blocks_narrow_size = _value;
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->scene()->update();
refreshDiagram();
}
//////////////////////////////////////////////////////////////////////////
@ -858,6 +872,10 @@ void EasyMainWindow::loadSettings()
if (!flag.isNull())
EASY_GLOBALS.only_current_thread_hierarchy = flag.toBool();
flag = settings.value("enable_zero_length");
if (!flag.isNull())
EASY_GLOBALS.enable_zero_length = flag.toBool();
flag = settings.value("bind_scene_and_tree_expand_status");
if (!flag.isNull())
EASY_GLOBALS.bind_scene_and_tree_expand_status = flag.toBool();
@ -914,6 +932,7 @@ void EasyMainWindow::saveSettingsAndGeometry()
settings.setValue("collapse_items_on_tree_close", EASY_GLOBALS.collapse_items_on_tree_close);
settings.setValue("all_items_expanded_by_default", EASY_GLOBALS.all_items_expanded_by_default);
settings.setValue("only_current_thread_hierarchy", EASY_GLOBALS.only_current_thread_hierarchy);
settings.setValue("enable_zero_length", EASY_GLOBALS.enable_zero_length);
settings.setValue("bind_scene_and_tree_expand_status", EASY_GLOBALS.bind_scene_and_tree_expand_status);
settings.setValue("enable_event_indicators", EASY_GLOBALS.enable_event_indicators);
settings.setValue("enable_statistics", EASY_GLOBALS.enable_statistics);

View File

@ -264,6 +264,8 @@ private:
void clear();
void refreshDiagram();
void loadFile(const QString& filename);
void readStream(::std::stringstream& data);