0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-25 23:40:51 +08:00

[ui] histogram update: added avg, median times, added color square for block name, added borders

This commit is contained in:
Victor Zarubkin 2019-10-26 01:04:21 +03:00
parent c74744fae4
commit 33850d5abf
16 changed files with 759 additions and 205 deletions

View File

@ -727,6 +727,14 @@ void BlocksGraphicsView::onWindowActivationChanged()
}
}
void BlocksGraphicsView::repaintHistogramImage()
{
if (m_pScrollbar != nullptr)
{
m_pScrollbar->repaintHistogramImage();
}
}
void BlocksGraphicsView::removePopup()
{
delete m_popupWidget;
@ -2692,7 +2700,7 @@ void BlocksGraphicsView::onHierarchyFlagChange(bool)
void BlocksGraphicsView::onSelectedThreadChange(profiler::thread_id_t id)
{
if (m_pScrollbar == nullptr || m_pScrollbar->hystThread() == id)
if (m_pScrollbar == nullptr || m_pScrollbar->histThread() == id)
{
return;
}

View File

@ -265,6 +265,7 @@ public:
public slots:
void onWindowActivationChanged();
void repaintHistogramImage();
signals:

View File

@ -81,7 +81,7 @@ inline EASY_CONSTEXPR_FCN uint16_t sizeOf() {
return static_cast<uint16_t>(sizeof(typename profiler::StdType<type>::value_type));
}
QString arrayToString(const profiler::ArbitraryValue& _serializedValue, int _index)
static QString arrayToString(const profiler::ArbitraryValue& _serializedValue, int _index)
{
switch (_serializedValue.type())
{
@ -107,7 +107,7 @@ QString arrayToString(const profiler::ArbitraryValue& _serializedValue, int _ind
}
}
QString singleValueToString(const profiler::ArbitraryValue& _serializedValue)
static QString singleValueToString(const profiler::ArbitraryValue& _serializedValue)
{
switch (_serializedValue.type())
{
@ -128,6 +128,32 @@ QString singleValueToString(const profiler::ArbitraryValue& _serializedValue)
}
}
template <class T>
static QString shortenCountStringUnsigned(T count, int precision)
{
if (count >= 1000000)
return QStringLiteral("%1m").arg(QString::number(count * 1e-6, 'f', precision));
if (count >= 1000)
return QStringLiteral("%1k").arg(QString::number(count * 1e-3, 'f', precision));
return QString::number(count);
}
template <class T>
static QString shortenCountStringSigned(T count, int precision)
{
const auto absCount = std::abs(count);
if (absCount >= 1000000)
return QStringLiteral("%1m").arg(QString::number(count * 1e-6, 'f', precision));
if (absCount >= 1000)
return QStringLiteral("%1k").arg(QString::number(count * 1e-3, 'f', precision));
return QString::number(count);
}
namespace profiler_gui {
//////////////////////////////////////////////////////////////////////////
@ -293,6 +319,28 @@ namespace profiler_gui {
//////////////////////////////////////////////////////////////////////////
QString shortenCountString(size_t count, int precision)
{
return shortenCountStringUnsigned(count, precision);
}
QString shortenCountString(uint32_t count, int precision)
{
return shortenCountStringUnsigned(count, precision);
}
QString shortenCountString(int64_t count, int precision)
{
return shortenCountStringSigned(count, precision);
}
QString shortenCountString(int count, int precision)
{
return shortenCountStringSigned(count, precision);
}
//////////////////////////////////////////////////////////////////////////
QFont EFont(QFont::StyleHint _hint, const char* _family, int _size, int _weight)
{
QFont f(_family, _size, _weight);
@ -479,4 +527,77 @@ namespace profiler_gui {
}
}
//////////////////////////////////////////////////////////////////////////
profiler::timestamp_t calculateMedian(const DurationsCountMap& durations)
{
if (durations.empty())
{
return 0;
}
profiler::timestamp_t median = 0;
size_t total_count = 0;
for (auto& kv : durations)
{
total_count += kv.second.count;
}
if (total_count & 1)
{
const auto index = total_count >> 1;
size_t i = 0;
for (auto& kv : durations)
{
const auto count = kv.second.count;
i += count;
if (i < index)
{
continue;
}
median = kv.first;
break;
}
}
else
{
const auto index2 = total_count >> 1;
const auto index1 = index2 - 1;
size_t i = 0;
bool i1 = false;
for (auto& kv : durations)
{
const auto count = kv.second.count;
i += count;
if (i < index1)
{
continue;
}
if (!i1)
{
i1 = true;
median = kv.first;
}
if (i < index2)
{
continue;
}
median += kv.first;
median >>= 1;
break;
}
}
return median;
}
} // end of namespace profiler_gui.

View File

@ -198,6 +198,13 @@ QString timeStringIntNs(TimeUnits _units, ::profiler::timestamp_t _interval);
//////////////////////////////////////////////////////////////////////////
QString shortenCountString(size_t count, int precision = 1);
QString shortenCountString(uint32_t count, int precision = 1);
QString shortenCountString(int64_t count, int precision = 1);
QString shortenCountString(int count, int precision = 1);
//////////////////////////////////////////////////////////////////////////
inline double percentReal(::profiler::timestamp_t _partial, ::profiler::timestamp_t _total) {
return _total != 0 ? 100. * static_cast<double>(_partial) / static_cast<double>(_total) : 0.;
}
@ -243,6 +250,10 @@ void updateProperty(QWidget* widget, const char* name, T&& property)
void deleteTreeItem(QTreeWidgetItem* item);
///////////////////////////////////////////////////////////////////////
profiler::timestamp_t calculateMedian(const DurationsCountMap& durations);
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////

View File

@ -56,6 +56,7 @@
#ifndef EASY_PROFILER__GUI_COMMON_TYPES_H
#define EASY_PROFILER__GUI_COMMON_TYPES_H
#include <map>
#include <vector>
#include <easy/reader.h>
#include <QObject>
@ -168,6 +169,16 @@ public:
void restore() { m_ref = m_restore; }
};
//////////////////////////////////////////////////////////////////////////
template <class T>
struct Counter
{
T count = 0;
};
using DurationsCountMap = std::map<profiler::timestamp_t, Counter<uint32_t> >;
} // END of namespace profiler_gui.
template <typename ... Args>

View File

@ -108,6 +108,7 @@ Globals::Globals()
, enable_zero_length(true)
, add_zero_blocks_to_hierarchy(false)
, draw_graphics_items_borders(true)
, draw_histogram_borders(true)
, hide_narrow_children(false)
, hide_minsize_blocks(false)
, display_only_relevant_stats(false)

View File

@ -77,6 +77,8 @@ namespace profiler_gui {
const QColor RULER_COLOR2 = QColor::fromRgba(0x40000000 | (::profiler::colors::Dark & 0x00ffffff));// 0x40408040);
const QColor TEXT_COLOR = QColor::fromRgb(0xff504040);
const QColor SYSTEM_BORDER_COLOR = QColor::fromRgb(0xffc4c4c4);
EASY_CONSTEXPR QRgb BLOCK_BORDER_COLOR = profiler::colors::Grey600 & 0x00ffffff;
EASY_CONSTEXPR QRgb SELECTED_THREAD_BACKGROUND = 0xffe0e060;
EASY_CONSTEXPR QRgb SELECTED_THREAD_FOREGROUND = 0xffffffff - (SELECTED_THREAD_BACKGROUND & 0x00ffffff);
@ -240,6 +242,7 @@ namespace profiler_gui {
bool enable_zero_length; ///< Enable zero length blocks (if true, then such blocks will have width == 1 pixel on each scale)
bool add_zero_blocks_to_hierarchy; ///< Enable adding zero blocks into hierarchy tree
bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not
bool draw_histogram_borders; ///< Draw borders for histogram columns or not
bool hide_narrow_children; ///< Hide children for narrow graphics blocks (See blocks_narrow_size)
bool hide_minsize_blocks; ///< Hide blocks which screen size is less than blocks_size_min
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

@ -58,6 +58,8 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace {
enum BlockItemState : int8_t
{
BLOCK_ITEM_DO_PAINT_FIRST = -2,
@ -71,7 +73,7 @@ enum BlockItemState : int8_t
EASY_CONSTEXPR int MIN_SYNC_SPACING = 1;
EASY_CONSTEXPR int MIN_SYNC_SIZE = 3;
EASY_CONSTEXPR int EVENT_HEIGHT = 4;
EASY_CONSTEXPR QRgb BORDERS_COLOR = profiler::colors::Grey600 & 0x00ffffff;// 0x00686868;
EASY_CONSTEXPR auto BORDERS_COLOR = profiler_gui::BLOCK_BORDER_COLOR;
inline QRgb selectedItemBorderColor(profiler::color_t _color) {
return ::profiler_gui::isLightColor(_color, 192) ? profiler::colors::Black : profiler::colors::RichRed;
@ -91,7 +93,14 @@ EASY_FORCE_INLINE void restoreItemFont(QPainter* /*painter*/)
//painter->setFont(EASY_GLOBALS.font.item);
}
const QPen HIGHLIGHTER_PEN = ([]() -> QPen { QPen p(profiler::colors::Black); p.setStyle(Qt::DotLine); p.setWidth(2); return p; })();
const QPen HIGHLIGHTER_PEN = ([]() -> QPen {
QPen p(profiler::colors::Black);
p.setStyle(Qt::DotLine);
p.setWidth(2);
return p;
})();
} // end of namespace <noname>.
#ifdef max
#undef max

View File

@ -61,9 +61,12 @@
#include "graphics_scrollbar.h"
#include "globals.h"
namespace {
//////////////////////////////////////////////////////////////////////////
EASY_CONSTEXPR int HIST_COLUMN_MIN_HEIGHT = 2;
EASY_CONSTEXPR qreal HIST_COLUMN_MIN_WIDTH_WITH_BORDER = 3;
//////////////////////////////////////////////////////////////////////////
@ -78,16 +81,24 @@ inline qreal calculate_color2(qreal, qreal duration, qreal k)
return std::min(sqr(sqr(duration)) * k, 0.9999999);
}
} // end of namespace <noname>.
//////////////////////////////////////////////////////////////////////////
GraphicsHistogramItem::GraphicsHistogramItem() : Parent()
, m_threadDuration(0)
, m_threadProfiledTime(0)
, m_threadWaitTime(0)
, m_pSource(nullptr)
, m_workerTopDuration(0)
, m_workerBottomDuration(0)
, m_blockTotalDuraion(0)
, m_threadDuration(0)
, m_threadProfiledTime(0)
, m_threadWaitTime(0)
, m_medianDuration(0)
, m_avgDuration(0)
, m_medianDurationFull(0)
, m_avgDurationFull(0)
, m_workerMedianDuration(0)
, m_workerAvgDuration(0)
, m_pSource(nullptr)
, m_pProfilerThread(nullptr)
, m_threadId(0)
, m_blockId(profiler_gui::numeric_max<decltype(m_blockId)>())
@ -161,7 +172,6 @@ void GraphicsHistogramItem::paintByPtr(QPainter* _painter)
const auto dtime = m_topValue - m_bottomValue;
const auto coeff = m_boundingRect.height() / (dtime > 1e-3 ? dtime : 1.);
QRectF rect;
QBrush brush(Qt::SolidPattern);
//QRgb previousColor = 0;
@ -178,11 +188,33 @@ void GraphicsHistogramItem::paintByPtr(QPainter* _painter)
qreal top_width = width, bottom_width = width;
const auto font_h = widget->fontHeight();
rect.setRect(0, m_boundingRect.top() - widget->margin(), width - 3, font_h);
_painter->setPen(profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, bindMode ? " Mode: Zoom" : " Mode: Overview");
QRectF bottomRect(3, bottom + 2, width - 3, font_h);
QRectF topRect(3, m_boundingRect.top() - widget->margin(), width - 3, font_h);
QRectF textBounds;
// MODE
{
_painter->setPen(Qt::blue);
_painter->drawText(
topRect,
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip | Qt::TextIncludeTrailingSpaces,
QStringLiteral("MODE: "),
&textBounds
);
topRect.adjust(textBounds.width(), 0, 0, 0);
_painter->setPen(profiler_gui::TEXT_COLOR);
_painter->drawText(
topRect,
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip,
bindMode ? "Zoom" : "Overview",
&textBounds
);
topRect.adjust(textBounds.width() + 3, 0, 0, 0);
}
// TOP & BOTTOM duration
if (!isEmpty() && !m_topDurationStr.isEmpty())
{
if (m_timeUnits != EASY_GLOBALS.time_units)
@ -190,17 +222,24 @@ void GraphicsHistogramItem::paintByPtr(QPainter* _painter)
m_timeUnits = EASY_GLOBALS.time_units;
m_topDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_topValue, 3);
m_bottomDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_bottomValue, 3);
if (m_avgDuration != 0 || m_medianDuration != 0)
{
m_medianDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_medianDuration, 3);
m_avgDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_avgDuration, 3);
}
}
//auto fm = _painter->fontMetrics();
//top_width -= fm.width(m_topDurationStr) + 7;
_painter->setPen(m_topValue < m_maxValue ? QColor(Qt::darkRed) : profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_topDurationStr);
_painter->drawText(topRect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_topDurationStr, &textBounds);
topRect.adjust(0, 0, -textBounds.width() - 3, 0);
rect.setRect(0, bottom + 2, width - 3, font_h);
_painter->setPen(m_bottomValue > m_minValue ? QColor(Qt::darkRed) : profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_bottomDurationStr);
_painter->drawText(bottomRect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_bottomDurationStr, &textBounds);
bottomRect.adjust(0, 0, -textBounds.width() - 3, 0);
}
_painter->setPen(Qt::darkGray);
@ -209,35 +248,70 @@ void GraphicsHistogramItem::paintByPtr(QPainter* _painter)
paintMouseIndicator(_painter, m_boundingRect.top(), bottom, width, m_boundingRect.height(), top_width, m_mousePos.y(), dtime, font_h);
if (!isEmpty() && m_bottomValue < EASY_GLOBALS.frame_time && EASY_GLOBALS.frame_time < m_topValue)
// MEDIAN & EXPECTED FRAME TIME
if (!isEmpty())
{
// Draw marker displaying expected frame_time step
const auto h = bottom - (EASY_GLOBALS.frame_time - m_bottomValue) * coeff;
_painter->setPen(Qt::DashLine);
const qreal mdn = m_medianDuration * 1e-3;
auto w = width;
const auto boundary = widget->margin() - font_h;
if (h < (m_boundingRect.top() - boundary))
w = top_width;
else if (h > (bottom + boundary))
w = bottom_width;
if (m_bottomValue < mdn && mdn < m_topValue)
{
// Draw marker displaying expected frame_time step
const auto h = bottom - (mdn - m_bottomValue) * coeff;
_painter->setPen(Qt::DashDotDotLine);
_painter->drawLine(QLineF(0, h, w, h));
auto w = width;
const auto boundary = widget->margin() - font_h;
if (h < (m_boundingRect.top() - boundary))
w = top_width;
else if (h > (bottom + boundary))
w = bottom_width;
_painter->drawLine(QLineF(0, h, w, h));
}
if (m_bottomValue < EASY_GLOBALS.frame_time && EASY_GLOBALS.frame_time < m_topValue)
{
// Draw marker displaying expected frame_time step
const auto h = bottom - (EASY_GLOBALS.frame_time - m_bottomValue) * coeff;
_painter->setPen(Qt::DashLine);
auto w = width;
const auto boundary = widget->margin() - font_h;
if (h < (m_boundingRect.top() - boundary))
w = top_width;
else if (h > (bottom + boundary))
w = bottom_width;
_painter->drawLine(QLineF(0, h, w, h));
}
}
_painter->setPen(profiler_gui::TEXT_COLOR);
rect.setRect(0, bottom + 2, width, font_h);
const auto eventsSize = m_pProfilerThread->events.size();
_painter->drawText(rect, Qt::AlignCenter | Qt::TextDontClip, QString("%1 | duration: %2 | profiled: %3 (%4%) | wait: %5 (%6%) | %7 frames | %8 blocks | %9 markers")
.arg(m_threadName)
.arg(profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadDuration))
.arg(profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadProfiledTime))
.arg(m_threadDuration ? QString::number(100. * (double)m_threadProfiledTime / (double)m_threadDuration, 'f', 2) : QString("0"))
.arg(profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadWaitTime))
.arg(m_threadDuration ? QString::number(100. * (double)m_threadWaitTime / (double)m_threadDuration, 'f', 2) : QString("0"))
.arg(m_pProfilerThread->frames_number)
.arg(m_pProfilerThread->blocks_number - eventsSize)
.arg(eventsSize));
const auto eventsCount = m_pProfilerThread->events.size();
const auto blocksCount = m_pProfilerThread->blocks_number - eventsCount;
QString durationsStr;
if (!m_medianDurationStr.isEmpty() || !m_avgDurationStr.isEmpty())
{
durationsStr = QString("avg: %1 | mdn: %2 | ").arg(m_avgDurationStr).arg(m_medianDurationStr);
}
_painter->drawText(topRect, Qt::AlignCenter, m_threadName);
_painter->drawText(bottomRect, Qt::AlignCenter,
QStringLiteral("time: %1 | profiled: %2 (%3%) | wait: %4 (%5%) | %6%7 frames | %8 blocks | %9 markers")
.arg(profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadDuration))
.arg(profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadProfiledTime))
.arg(m_threadDuration ? QString::number(100. * (double) m_threadProfiledTime / (double) m_threadDuration, 'f', 2)
: QString("0"))
.arg(profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadWaitTime))
.arg(m_threadDuration ? QString::number(100. * (double) m_threadWaitTime / (double) m_threadDuration, 'f', 2)
: QString("0"))
.arg(durationsStr)
.arg(profiler_gui::shortenCountString(m_pProfilerThread->frames_number))
.arg(profiler_gui::shortenCountString(blocksCount))
.arg(profiler_gui::shortenCountString(eventsCount))
);
_painter->restore();
}
@ -252,7 +326,6 @@ void GraphicsHistogramItem::paintById(QPainter* _painter)
const auto dtime = m_topValue - m_bottomValue;
const auto coeff = m_boundingRect.height() / (dtime > 1e-3 ? dtime : 1.);
QRectF rect;
QBrush brush(Qt::SolidPattern);
//QRgb previousColor = 0;
@ -270,11 +343,33 @@ void GraphicsHistogramItem::paintById(QPainter* _painter)
qreal top_width = width, bottom_width = width;
const auto font_h = widget->fontHeight();
rect.setRect(0, m_boundingRect.top() - widget->margin(), width - 3, font_h);
_painter->setPen(profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, bindMode ? " Mode: Zoom" : " Mode: Overview");
QRectF bottomRect(3, bottom + 2, width - 3, font_h);
QRectF topRect(3, m_boundingRect.top() - widget->margin(), width - 3, font_h);
QRectF textBounds;
// MODE
{
_painter->setPen(Qt::blue);
_painter->drawText(
topRect,
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip | Qt::TextIncludeTrailingSpaces,
QStringLiteral("MODE: "),
&textBounds
);
topRect.adjust(textBounds.width(), 0, 0, 0);
_painter->setPen(profiler_gui::TEXT_COLOR);
_painter->drawText(
topRect,
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip,
bindMode ? "Zoom" : "Overview",
&textBounds
);
topRect.adjust(textBounds.width() + 3, 0, 0, 0);
}
// TOP & BOTTOM duration
if (!isEmpty() && !m_topDurationStr.isEmpty())
{
if (m_timeUnits != EASY_GLOBALS.time_units)
@ -282,17 +377,24 @@ void GraphicsHistogramItem::paintById(QPainter* _painter)
m_timeUnits = EASY_GLOBALS.time_units;
m_topDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_topValue, 3);
m_bottomDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_bottomValue, 3);
if (m_avgDuration != 0 || m_medianDuration != 0)
{
m_medianDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_medianDuration, 3);
m_avgDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_avgDuration, 3);
}
}
//auto fm = _painter->fontMetrics();
//top_width -= fm.width(m_topDurationStr) + 7;
_painter->setPen(m_topValue < m_maxValue ? QColor(Qt::darkRed) : profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_topDurationStr);
_painter->drawText(topRect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_topDurationStr, &textBounds);
topRect.adjust(0, 0, -textBounds.width() - 3, 0);
rect.setRect(0, bottom + 2, width - 3, font_h);
_painter->setPen(m_bottomValue > m_minValue ? QColor(Qt::darkRed) : profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_bottomDurationStr);
_painter->drawText(bottomRect, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, m_bottomDurationStr, &textBounds);
bottomRect.adjust(0, 0, -textBounds.width() - 3, 0);
}
_painter->setPen(Qt::darkGray);
@ -301,44 +403,89 @@ void GraphicsHistogramItem::paintById(QPainter* _painter)
paintMouseIndicator(_painter, m_boundingRect.top(), bottom, width, m_boundingRect.height(), top_width, m_mousePos.y(), dtime, font_h);
if (!isEmpty() && m_bottomValue < EASY_GLOBALS.frame_time && EASY_GLOBALS.frame_time < m_topValue)
// MEDIAN & EXPECTED FRAME TIME
if (!isEmpty())
{
// Draw marker displaying required frame_time step
const auto h = bottom - (EASY_GLOBALS.frame_time - m_bottomValue) * coeff;
_painter->setPen(Qt::DashLine);
const qreal mdn = m_medianDuration * 1e-3;
auto w = width;
const auto boundary = widget->margin() - font_h;
if (h < (m_boundingRect.top() - boundary))
w = top_width;
else if (h >(bottom + boundary))
w = bottom_width;
if (m_bottomValue < mdn && mdn < m_topValue)
{
// Draw marker displaying expected frame_time step
const auto h = bottom - (mdn - m_bottomValue) * coeff;
_painter->setPen(Qt::DashDotDotLine);
_painter->drawLine(QLineF(0, h, w, h));
auto w = width;
const auto boundary = widget->margin() - font_h;
if (h < (m_boundingRect.top() - boundary))
w = top_width;
else if (h > (bottom + boundary))
w = bottom_width;
_painter->drawLine(QLineF(0, h, w, h));
}
if (m_bottomValue < EASY_GLOBALS.frame_time && EASY_GLOBALS.frame_time < m_topValue)
{
// Draw marker displaying required frame_time step
const auto h = bottom - (EASY_GLOBALS.frame_time - m_bottomValue) * coeff;
_painter->setPen(Qt::DashLine);
auto w = width;
const auto boundary = widget->margin() - font_h;
if (h < (m_boundingRect.top() - boundary))
w = top_width;
else if (h > (bottom + boundary))
w = bottom_width;
_painter->drawLine(QLineF(0, h, w, h));
}
}
const auto colorIndicatorSize = font_h * 2 / 3;
_painter->setBrush(QColor::fromRgba(easyDescriptor(m_blockId).color()));
_painter->setPen(profiler_gui::BLOCK_BORDER_COLOR);
_painter->drawRect(QRectF(bottomRect.left(), bottomRect.top() + 1 + font_h / 6., colorIndicatorSize, colorIndicatorSize));
bottomRect.adjust(colorIndicatorSize + 3, 0, 0, 0);
_painter->setPen(profiler_gui::TEXT_COLOR);
rect.setRect(0, bottom + 2, width, font_h);
_painter->drawText(topRect, Qt::AlignCenter, m_threadName);
_painter->drawText(bottomRect, Qt::AlignLeft, m_blockName, &textBounds);
bottomRect.adjust(textBounds.width() + 3, 0, 0, 0);
_painter->drawText(bottomRect, Qt::AlignLeft, QStringLiteral("| %1").arg(m_blockType), &textBounds);
bottomRect.adjust(textBounds.width() + 3, 0, 0, 0);
if (!items.empty())
{
QString durationsStr;
if (!m_medianDurationStr.isEmpty() || !m_avgDurationStr.isEmpty())
{
durationsStr = QString("avg: %1 | mdn: %2 | ").arg(m_avgDurationStr).arg(m_medianDurationStr);
}
if (m_threadProfiledTime != 0)
{
_painter->drawText(rect, Qt::AlignCenter | Qt::TextDontClip,
QString("%1 | %2 | %3 calls | %4% of thread profiled time")
.arg(m_threadName).arg(m_blockName).arg(items.size())
.arg(QString::number(100. * (double)m_blockTotalDuraion / (double)m_threadProfiledTime, 'f', 2)));
_painter->drawText(bottomRect, Qt::AlignCenter,
QStringLiteral("%1 calls | %2%3% of thread profiled time")
.arg(items.size())
.arg(durationsStr)
.arg(QString::number(100. * (double) m_blockTotalDuraion / (double) m_threadProfiledTime, 'f', 2))
);
}
else
{
_painter->drawText(rect, Qt::AlignCenter | Qt::TextDontClip,
QString("%1 | %2 | %3 calls | 100% of thread profiled time")
.arg(m_threadName).arg(m_blockName).arg(items.size()));
_painter->drawText(bottomRect, Qt::AlignCenter,
QStringLiteral("%1 calls | %2100% of thread profiled time")
.arg(items.size())
.arg(durationsStr)
);
}
}
else
{
_painter->drawText(rect, Qt::AlignCenter | Qt::TextDontClip, QString("%1 | %2 | 0 calls").arg(m_threadName).arg(m_blockName));
_painter->drawText(bottomRect, Qt::AlignCenter, QStringLiteral("0 calls"));
}
_painter->restore();
@ -379,7 +526,12 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, const pr
m_boundaryTimer.stop();
m_blockName.clear();
m_blockType = QStringLiteral("Thread");
m_blockTotalDuraion = 0;
m_medianDuration = 0;
m_avgDuration = 0;
m_medianDurationFull = 0;
m_avgDurationFull = 0;
m_imageOriginUpdate = m_imageOrigin = 0;
m_imageScaleUpdate = m_imageScale = 1;
@ -388,6 +540,11 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, const pr
setEmpty(true);
{ profiler::BlocksTree::children_t().swap(m_selectedBlocks); }
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_medianDurationStr.clear();
m_avgDurationStr.clear();
setImageUpdatePermitted(false);
m_regime = Hist_Pointer;
m_pSource = _items;
@ -423,15 +580,25 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, const pr
m_maxValue = 0;
m_minValue = 1e30;
size_t totalCount = 0;
profiler_gui::DurationsCountMap durations;
bool empty = true;
for (const auto& item : *source)
{
if (isReady())
return;
if (easyDescriptor(easyBlock(item.block).tree.node->id()).type() == profiler::BlockType::Event)
auto& block = easyBlock(item.block).tree;
auto& desc = easyDescriptor(block.node->id());
if (desc.type() != profiler::BlockType::Block)
continue;
const auto duration = block.node->duration();
++totalCount;
++durations[duration].count;
m_avgDuration += duration;
const auto w = item.width();
if (w > m_maxValue)
@ -443,6 +610,12 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, const pr
empty = false;
}
if (!empty)
{
m_avgDuration /= totalCount;
m_medianDuration = profiler_gui::calculateMedian(durations);
}
if ((m_maxValue - m_minValue) < 1e-3)
{
if (m_minValue > 0.1)
@ -464,10 +637,13 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, const pr
m_topDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_topValue, 3);
m_bottomDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_bottomValue, 3);
}
else
if (m_avgDuration != 0 || m_medianDuration != 0)
{
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_avgDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_avgDuration, 3);
m_medianDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_medianDuration, 3);
m_medianDurationFull = m_medianDuration;
m_avgDurationFull = m_avgDuration;
}
setEmpty(empty);
@ -483,8 +659,6 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, const pr
if (m_pSource == nullptr)
{
m_pProfilerThread = nullptr;
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_threadName.clear();
hide();
}
@ -505,8 +679,15 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
m_pSource = nullptr;
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_medianDurationStr.clear();
m_avgDurationStr.clear();
m_blockName.clear();
m_blockType.clear();
m_blockTotalDuraion = 0;
m_medianDuration = 0;
m_avgDuration = 0;
m_medianDurationFull = 0;
m_avgDurationFull = 0;
m_imageOriginUpdate = m_imageOrigin = 0;
m_imageScaleUpdate = m_imageScale = 1;
@ -520,7 +701,31 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
if (m_threadId != 0 && !profiler_gui::is_max(m_blockId))
{
m_blockName = profiler_gui::toUnicode(easyDescriptor(m_blockId).name());
auto& desc = easyDescriptor(m_blockId);
m_blockName = profiler_gui::toUnicode(desc.name());
switch (desc.type())
{
case profiler::BlockType::Block:
{
m_blockType = QStringLiteral("Block");
break;
}
case profiler::BlockType::Event:
{
m_blockType = QStringLiteral("Event");
break;
}
case profiler::BlockType::Value:
{
m_blockType = QStringLiteral("Value");
break;
}
default: break;
}
const auto& root = EASY_GLOBALS.profiler_blocks[_thread_id];
m_threadName = profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root, EASY_GLOBALS.hex_thread_id);
@ -564,6 +769,8 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
const bool has_selected_block = !profiler_gui::is_max(selected_block);
size_t totalCount = 0;
profiler_gui::DurationsCountMap durations;
for (auto frame : profiler_thread.children)
{
const auto& frame_block = easyBlock(frame).tree;
@ -578,6 +785,8 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
if (w < m_minValue)
m_minValue = w;
++totalCount;
++durations[w].count;
m_blockTotalDuraion += w;
}
@ -611,6 +820,8 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
if (w < m_minValue)
m_minValue = w;
++totalCount;
++durations[w].count;
m_blockTotalDuraion += w;
}
@ -633,6 +844,8 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
{
m_topDurationStr.clear();
m_bottomDurationStr.clear();
m_medianDurationStr.clear();
m_avgDurationStr.clear();
}
else
{
@ -659,8 +872,20 @@ void GraphicsHistogramItem::setSource(profiler::thread_id_t _thread_id, profiler
}
}
m_avgDuration = m_blockTotalDuraion / totalCount;
m_medianDuration = profiler_gui::calculateMedian(durations);
m_medianDurationFull = m_medianDuration;
m_avgDurationFull = m_avgDuration;
m_topDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_maxValue, 3);
m_bottomDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_minValue, 3);
if (m_avgDuration != 0 || m_medianDuration != 0)
{
m_avgDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_avgDuration, 3);
m_medianDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_medianDuration, 3);
}
}
m_topValue = m_maxValue;
@ -831,9 +1056,10 @@ bool GraphicsHistogramItem::updateImage()
const auto frameTime = EASY_GLOBALS.frame_time;
const auto beginTime = EASY_GLOBALS.begin_time;
const auto autoHeight = EASY_GLOBALS.auto_adjust_histogram_height;
const auto drawBorders = EASY_GLOBALS.draw_histogram_borders;
m_worker.enqueue([=] {
updateImageAsync(rect, regime, scale, left, right, right - left, value, window, top, bottom, bindMode,
frameTime, beginTime, autoHeight);
frameTime, beginTime, autoHeight, drawBorders);
}, m_bReady);
return true;
@ -849,12 +1075,29 @@ void GraphicsHistogramItem::onImageUpdated()
m_topDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_topValue, 3);
m_bottomDurationStr = profiler_gui::timeStringReal(m_timeUnits, m_bottomValue, 3);
}
if (static_cast<const GraphicsSliderArea*>(scene()->parent())->bindMode())
{
m_medianDuration = m_workerMedianDuration;
m_avgDuration = m_workerAvgDuration;
}
else
{
m_medianDuration = m_medianDurationFull;
m_avgDuration = m_avgDurationFull;
}
if (m_avgDuration != 0 || m_medianDuration != 0)
{
m_medianDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_medianDuration, 3);
m_avgDurationStr = profiler_gui::timeStringRealNs(m_timeUnits, m_avgDuration, 3);
}
}
void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _regime, qreal _current_scale,
qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, qreal _top_duration, qreal _bottom_duration,
bool _bindMode, float _frame_time, profiler::timestamp_t _begin_time, bool _autoAdjustHist)
bool _bindMode, float _frame_time, profiler::timestamp_t _begin_time, bool _autoAdjustHist, bool _drawBorders)
{
const auto bottom = _boundingRect.height();//_boundingRect.bottom();
const auto screenWidth = _boundingRect.width() * _current_scale;
@ -899,6 +1142,11 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1;
auto const k = gotFrame ? sqr(sqr(frameCoeff)) : 1.0 / _boundingRect.height();
size_t totalCount = 0;
m_workerMedianDuration = 0;
m_workerAvgDuration = 0;
profiler_gui::DurationsCountMap durations;
if (_regime == Hist_Pointer)
{
const auto& items = *m_pSource;
@ -914,7 +1162,7 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
realScale *= viewScale;
offset = _minimum * realScale;
first = std::lower_bound(items.begin(), items.end(), _minimum, [](const profiler_gui::EasyBlockItem& _item, qreal _value)
first = std::lower_bound(items.begin(), items.end(), _minimum, [] (const profiler_gui::EasyBlockItem& _item, qreal _value)
{
return _item.left() < _value;
});
@ -977,6 +1225,10 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
const auto dtime = _top_duration - _bottom_duration;
const auto coeff = _boundingRect.height() / (dtime > 1e-3 ? dtime : 1.);
const qreal minWidth = _drawBorders ? HIST_COLUMN_MIN_WIDTH_WITH_BORDER : 1.;
if (_drawBorders)
p.setPen(profiler_gui::BLOCK_BORDER_COLOR);
for (auto it = first, end = items.end(); it != end; ++it)
{
// Draw rectangle
@ -986,16 +1238,97 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
if (it->right() < _minimum)
continue;
const qreal item_x = it->left() * realScale - offset;
const qreal item_w = std::max(it->width() * realScale, 1.0);
const qreal item_r = item_x + item_w;
const qreal h = it->width() <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
(it->width() > _top_duration ? maxColumnHeight : (it->width() - _bottom_duration) * coeff);
if (_bindMode)
{
// calculate avg and median
const auto duration = easyBlock(it->block).tree.node->duration();
m_workerAvgDuration += duration;
++totalCount;
++durations[duration].count;
}
auto maxItemWidth = it->width();
// calculate column width and height
qreal item_x = it->left() * realScale - offset;
qreal item_w = it->width() * realScale;
qreal item_r = item_x + item_w;
const auto width = it->width();
qreal h = width <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
(width > _top_duration ? maxColumnHeight : (width - _bottom_duration) * coeff);
if (_drawBorders)
{
if (item_r < previous_x)
{
item_w -= previous_x - item_r;
item_x = previous_x;
item_r = item_x + item_w;
}
// if column width < minWidth then try to merge several columns together
auto jt = it;
while (item_w < minWidth && jt != end)
{
if (jt->left() > _maximum)
break;
const qreal jx = jt->left() * realScale - offset;
auto dx = jx - item_r;
if (dx > std::max(item_w, minWidth))
{
item_w = minWidth;
break;
}
const qreal jw = jt->width() * realScale;
if (jw > (minWidth + item_w))
{
item_w = minWidth;
break;
}
const auto jwidth = jt->width();
const qreal jh = jwidth <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
(jwidth > _top_duration ? maxColumnHeight : (jwidth - _bottom_duration) * coeff);
item_w += jw;
h = std::max(h, jh);
maxItemWidth = std::max(maxItemWidth, jwidth);
++jt;
}
item_r = item_x + item_w;
if (_bindMode)
{
// if merged several columns then avg and median should be calculated for these columns too
for (auto it2 = it; it2 != jt; ++it2)
{
const auto duration = easyBlock(it2->block).tree.node->duration();
m_workerAvgDuration += duration;
++totalCount;
++durations[duration].count;
}
}
if (jt != it)
{
// bypass merged columns
it = jt;
--it;
}
}
else if (item_w < 1)
{
item_w = 1;
item_r = item_x + 1;
}
if (h < previous_h && item_r < previous_x)
continue;
const auto col = calculate_color(h, it->width(), k);
const auto col = calculate_color(h, maxItemWidth, k);
const auto color = 0x00ffffff & QColor::fromHsvF((1.0 - col) * 0.375, 0.85, 0.85).rgb();
if (previousColor != color)
@ -1100,6 +1433,10 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
const auto dtime = _top_duration - _bottom_duration;
const auto coeff = _boundingRect.height() / (dtime > 1e-3 ? dtime : 1.);
const qreal minWidth = _drawBorders ? HIST_COLUMN_MIN_WIDTH_WITH_BORDER : 1.;
if (_drawBorders)
p.setPen(profiler_gui::BLOCK_BORDER_COLOR);
for (auto it = first, end = m_selectedBlocks.end(); it != end; ++it)
{
// Draw rectangle
@ -1113,17 +1450,100 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
if (endTime < _minimum)
continue;
if (_bindMode)
{
// calculate avg and median
const auto duration = item->duration();
m_workerAvgDuration += duration;
++totalCount;
++durations[duration].count;
}
const qreal duration = item->duration() * 1e-3;
const qreal item_x = (beginTime * realScale - offset) * 1e-3;
const qreal item_w = std::max(duration * realScale, 1.0);
const qreal item_r = item_x + item_w;
const auto h = duration <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
auto maxItemDuration = duration;
// calculate column width and height
qreal item_x = (beginTime * realScale - offset) * 1e-3;
qreal item_w = duration * realScale;
qreal item_r = item_x + item_w;
auto h = duration <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
(duration > _top_duration ? maxColumnHeight : (duration - _bottom_duration) * coeff);
if (_drawBorders)
{
if (item_r < previous_x)
{
item_w -= previous_x - item_r;
item_x = previous_x;
item_r = item_x + item_w;
}
// if column width < minWidth then try to merge several columns together
auto jt = it;
while (item_w < minWidth && jt != end)
{
const auto jtem = easyBlock(*jt).tree.node;
const auto jbeginTime = jtem->begin() - _begin_time;
if (jbeginTime > _maximum)
break;
const qreal jduration = jtem->duration() * 1e-3;
const qreal jx = ((jtem->begin() - _begin_time) * realScale - offset) * 1e-3;
auto dx = jx - item_r;
if (dx > std::max(item_w, minWidth))
{
item_w = minWidth;
break;
}
const qreal jw = jduration * realScale;
if (jw > (minWidth + item_w))
{
item_w = minWidth;
break;
}
const qreal jh = jduration <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
(jduration > _top_duration ? maxColumnHeight : (jduration - _bottom_duration) * coeff);
item_w += jw;
h = std::max(h, jh);
maxItemDuration = std::max(maxItemDuration, jduration);
++jt;
}
item_r = item_x + item_w;
if (_bindMode)
{
// if merged several columns then avg and median should be calculated for these columns too
for (auto it2 = it; it2 != jt; ++it2)
{
const auto duration = easyBlock(*it2).tree.node->duration();
m_workerAvgDuration += duration;
++totalCount;
++durations[duration].count;
}
}
if (jt != it)
{
// bypass merged columns
it = jt;
--it;
}
}
else if (item_w < 1)
{
item_w = 1;
item_r = item_x + 1;
}
if (h < previous_h && item_r < previous_x)
continue;
const auto col = calculate_color(h, duration, k);
const auto col = calculate_color(h, maxItemDuration, k);
const auto color = 0x00ffffff & QColor::fromHsvF((1.0 - col) * 0.375, 0.85, 0.85).rgb();
if (previousColor != color)
@ -1145,6 +1565,12 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
m_workerTopDuration = _top_duration;
m_workerBottomDuration = _bottom_duration;
if (_bindMode)
{
m_workerAvgDuration /= totalCount;
m_workerMedianDuration = profiler_gui::calculateMedian(durations);
}
setReady(true);
}
@ -1166,7 +1592,7 @@ GraphicsScrollbar::GraphicsScrollbar(int _initialHeight, QWidget* _parent)
m_histogramItem->hide();
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged,
this, &This::onExpectedFrameTimeChanged);
this, &This::repaintHistogramImage);
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::autoAdjustHistogramChanged,
this, &This::onAutoAdjustHistogramChanged);
@ -1187,6 +1613,15 @@ GraphicsScrollbar::~GraphicsScrollbar()
//////////////////////////////////////////////////////////////////////////
void GraphicsScrollbar::repaintHistogramImage()
{
if (m_histogramItem->isVisible())
{
m_histogramItem->updateImage();
scene()->update();
}
}
void GraphicsScrollbar::onThreadViewChanged()
{
if (m_histogramItem->isVisible())
@ -1196,15 +1631,6 @@ void GraphicsScrollbar::onThreadViewChanged()
}
}
void GraphicsScrollbar::onExpectedFrameTimeChanged()
{
if (m_histogramItem->isVisible())
{
m_histogramItem->updateImage();
scene()->update();
}
}
void GraphicsScrollbar::onAutoAdjustHistogramChanged()
{
if (m_histogramItem->isVisible())
@ -1225,7 +1651,7 @@ void GraphicsScrollbar::clear()
Parent::clear();
}
profiler::thread_id_t GraphicsScrollbar::hystThread() const
profiler::thread_id_t GraphicsScrollbar::histThread() const
{
return m_histogramItem->threadId();
}

View File

@ -80,12 +80,21 @@ private:
profiler::timestamp_t m_blockTotalDuraion;
QString m_topDurationStr;
QString m_bottomDurationStr;
QString m_medianDurationStr;
QString m_avgDurationStr;
QString m_threadName;
QString m_blockName;
QString m_blockType;
profiler::BlocksTree::children_t m_selectedBlocks;
profiler::timestamp_t m_threadDuration;
profiler::timestamp_t m_threadProfiledTime;
profiler::timestamp_t m_threadWaitTime;
profiler::timestamp_t m_medianDuration;
profiler::timestamp_t m_avgDuration;
profiler::timestamp_t m_medianDurationFull;
profiler::timestamp_t m_avgDurationFull;
profiler::timestamp_t m_workerMedianDuration;
profiler::timestamp_t m_workerAvgDuration;
const profiler_gui::EasyItems* m_pSource;
const profiler::BlocksTreeRoot* m_pProfilerThread;
profiler::thread_id_t m_threadId;
@ -136,7 +145,7 @@ private:
void updateImageAsync(QRectF _boundingRect, HistRegime _regime, qreal _current_scale,
qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, qreal _top_duration, qreal _bottom_duration, bool _bindMode,
float _frame_time, profiler::timestamp_t _begin_time, bool _autoAdjustHist);
float _frame_time, profiler::timestamp_t _begin_time, bool _autoAdjustHist, bool _drawBorders);
}; // END of class GraphicsHistogramItem.
@ -165,7 +174,7 @@ public:
// Public non-virtual methods
profiler::thread_id_t hystThread() const;
profiler::thread_id_t histThread() const;
void setHistogramSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems* _items);
void setHistogramSource(profiler::thread_id_t _thread_id, profiler::block_id_t _block_id);
@ -173,10 +182,13 @@ public:
setHistogramSource(_thread_id, &_items);
}
public slots:
void repaintHistogramImage();
private slots:
void onThreadViewChanged();
void onExpectedFrameTimeChanged();
void onAutoAdjustHistogramChanged();
void onDisplayOnlyFramesOnHistogramChanged();

View File

@ -360,10 +360,10 @@ int GraphicsSliderArea::margins() const
//////////////////////////////////////////////////////////////////////////
void GraphicsSliderArea::setValue(qreal _value)
bool GraphicsSliderArea::setValue(qreal _value)
{
if (m_bUpdatingPos)
return;
return false;
const profiler_gui::BoolFlagGuard guard(m_bUpdatingPos, true);
@ -371,7 +371,7 @@ void GraphicsSliderArea::setValue(qreal _value)
if (fabs(m_value - newValue) < 2 * std::numeric_limits<decltype(m_value)>::epsilon())
{
m_slider->setX(m_value + m_slider->halfwidth());
return;
return false;
}
m_value = newValue;
@ -384,6 +384,8 @@ void GraphicsSliderArea::setValue(qreal _value)
if (m_imageItem->isVisible())
m_imageItem->onValueChanged();
return true;
}
void GraphicsSliderArea::setRange(qreal _minValue, qreal _maxValue)
@ -413,7 +415,11 @@ void GraphicsSliderArea::setRange(qreal _minValue, qreal _maxValue)
void GraphicsSliderArea::setSliderWidth(qreal _width)
{
m_slider->setWidth(_width);
setValue(m_value);
if (!setValue(m_value))
{
if (m_imageItem->isVisible())
m_imageItem->onValueChanged();
}
}
//////////////////////////////////////////////////////////////////////////

View File

@ -145,7 +145,7 @@ public:
int margin() const;
int margins() const;
void setValue(qreal _value);
bool setValue(qreal _value);
void setRange(qreal _minValue, qreal _maxValue);
void setSliderWidth(qreal _width);
void setSelectionPos(qreal _left, qreal _right);

View File

@ -518,11 +518,24 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
menu->addSeparator();
auto submenu = menu->addMenu("View");
submenu->setToolTipsVisible(true);
action = submenu->addAction("Draw borders");
action = submenu->addAction("Diagram borders");
action->setToolTip("Draw borders for blocks on diagram.\nThis slightly reduces performance.");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.draw_graphics_items_borders);
connect(action, &QAction::triggered, [this](bool _checked){ EASY_GLOBALS.draw_graphics_items_borders = _checked; refreshDiagram(); });
connect(action, &QAction::triggered, [this] (bool _checked) {
EASY_GLOBALS.draw_graphics_items_borders = _checked;
refreshDiagram();
});
action = submenu->addAction("Histogram borders");
action->setToolTip("Draw borders for histogram columns.");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.draw_histogram_borders);
connect(action, &QAction::triggered, [this] (bool _checked) {
EASY_GLOBALS.draw_histogram_borders = _checked;
refreshHistogramImage();
});
action = submenu->addAction("Overlap narrow children");
action->setToolTip("Children blocks will be overlaped by narrow\nparent blocks. See also \'Blocks narrow size\'.\nThis improves performance.");
@ -929,12 +942,13 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
toolbar->addWidget(lbl);
m_frameTimeEdit = new QLineEdit();
m_frameTimeEdit->setFixedWidth(px(70));
m_frameTimeEdit->setFixedWidth(px(80));
auto val = new QDoubleValidator(m_frameTimeEdit);
val->setLocale(QLocale::c());
val->setBottom(0);
val->setDecimals(3);
m_frameTimeEdit->setValidator(val);
m_frameTimeEdit->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3));
m_frameTimeEdit->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3, 'f', 3));
connect(m_frameTimeEdit, &QLineEdit::editingFinished, this, &This::onFrameTimeEditFinish);
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged, this, &This::onFrameTimeChanged);
toolbar->addWidget(m_frameTimeEdit);
@ -1349,6 +1363,11 @@ void MainWindow::refreshDiagram()
static_cast<DiagramWidget*>(m_graphicsView->widget())->view()->scene()->update();
}
void MainWindow::refreshHistogramImage()
{
static_cast<DiagramWidget*>(m_graphicsView->widget())->view()->repaintHistogramImage();
}
//////////////////////////////////////////////////////////////////////////
void MainWindow::onDeleteClicked(bool)
@ -1579,7 +1598,7 @@ void MainWindow::validateLineEdits()
{
m_addressEdit->setFixedWidth((m_addressEdit->fontMetrics().width(QString("255.255.255.255")) * 3) / 2);
m_portEdit->setFixedWidth(m_portEdit->fontMetrics().width(QString("000000")) + 10);
m_frameTimeEdit->setFixedWidth(m_frameTimeEdit->fontMetrics().width(QString("000000")));
m_frameTimeEdit->setFixedWidth(m_frameTimeEdit->fontMetrics().width(QString("000.000")) + 5);
}
//////////////////////////////////////////////////////////////////////////
@ -1723,6 +1742,10 @@ void MainWindow::loadSettings()
if (!flag.isNull())
EASY_GLOBALS.draw_graphics_items_borders = flag.toBool();
flag = settings.value("draw_histogram_borders");
if (!flag.isNull())
EASY_GLOBALS.draw_histogram_borders = flag.toBool();
flag = settings.value("hide_narrow_children");
if (!flag.isNull())
EASY_GLOBALS.hide_narrow_children = flag.toBool();
@ -1888,6 +1911,7 @@ void MainWindow::saveSettingsAndGeometry()
settings.setValue("blocks_size_min", EASY_GLOBALS.blocks_size_min);
settings.setValue("blocks_narrow_size", EASY_GLOBALS.blocks_narrow_size);
settings.setValue("draw_graphics_items_borders", EASY_GLOBALS.draw_graphics_items_borders);
settings.setValue("draw_histogram_borders", EASY_GLOBALS.draw_histogram_borders);
settings.setValue("hide_narrow_children", EASY_GLOBALS.hide_narrow_children);
settings.setValue("hide_minsize_blocks", EASY_GLOBALS.hide_minsize_blocks);
settings.setValue("collapse_items_on_tree_close", EASY_GLOBALS.collapse_items_on_tree_close);
@ -2571,19 +2595,12 @@ void MainWindow::onFrameTimeEditFinish()
}
EASY_GLOBALS.frame_time = text.toFloat() * 1e3f;
disconnect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged,
this, &This::onFrameTimeChanged);
emit EASY_GLOBALS.events.expectedFrameTimeChanged();
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged,
this, &This::onFrameTimeChanged);
}
void MainWindow::onFrameTimeChanged()
{
m_frameTimeEdit->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3));
m_frameTimeEdit->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3, 'f', 3));
}
//////////////////////////////////////////////////////////////////////////

View File

@ -393,6 +393,7 @@ private:
void clear();
void refreshDiagram();
void refreshHistogramImage();
void addFileToList(const QString& filename, bool changeWindowTitle = true);
void loadFile(const QString& filename);

View File

@ -89,7 +89,7 @@ struct ThreadData
using ThreadDataMap = std::unordered_map<profiler::thread_id_t, ThreadData, estd::hash<profiler::thread_id_t> >;
void calculate_medians(StatsMap::iterator begin, StatsMap::iterator end)
void calculateMedians(StatsMap::iterator begin, StatsMap::iterator end)
{
for (auto it = begin; it != end; ++it)
{
@ -99,65 +99,7 @@ void calculate_medians(StatsMap::iterator begin, StatsMap::iterator end)
continue;
}
size_t total_count = 0;
for (auto& kv : durations)
{
total_count += kv.second.count;
}
auto& stats = it->second.stats;
if (total_count & 1)
{
const auto index = total_count >> 1;
size_t i = 0;
for (auto& kv : durations)
{
const auto count = kv.second.count;
i += count;
if (i < index)
{
continue;
}
stats.median_duration = kv.first;
break;
}
}
else
{
const auto index2 = total_count >> 1;
const auto index1 = index2 - 1;
size_t i = 0;
bool i1 = false;
for (auto& kv : durations)
{
const auto count = kv.second.count;
i += count;
if (i < index1)
{
continue;
}
if (!i1)
{
i1 = true;
stats.median_duration = kv.first;
}
if (i < index2)
{
continue;
}
stats.median_duration += kv.first;
stats.median_duration >>= 1;
break;
}
}
it->second.stats.median_duration = profiler_gui::calculateMedian(durations);
decltype(it->second.durations) dummy;
dummy.swap(durations);
@ -502,29 +444,16 @@ void TreeWidgetLoader::setTreeInternalTop(
if (total_count > _maxCount)
{
if (_maxCount > 10000)
{
m_error = QString(
"Exceeded maximum rows count = %1k.\n"
"Actual rows count: %2k (%3%).\n"
"Please, reduce selected area width\n"
"or increase maximum count in settings\n"
"or change the tree mode."
).arg(_maxCount / 1000).arg(total_count / 1000).arg(profiler_gui::percent(total_count, _maxCount));
}
else
{
m_error = QString(
"Exceeded maximum rows count = %1.\n"
"Actual rows count: %2 (%3%).\n"
"Please, reduce selected area width\n"
"or increase maximum count in settings\n"
"or change the tree mode."
).arg(_maxCount).arg(total_count).arg(profiler_gui::percent(total_count, _maxCount));
}
m_error = QString(
"Exceeded maximum rows count = %1.\n"
"Actual rows count: %2 (%3%).\n"
"Please, reduce selected area width\n"
"or increase maximum count in settings\n"
"or change the tree mode."
).arg(profiler_gui::shortenCountString(_maxCount))
.arg(profiler_gui::shortenCountString(total_count))
.arg(profiler_gui::percent(total_count, _maxCount));
setDone();
return;
}
@ -1879,7 +1808,7 @@ void TreeWidgetLoader::fillStatsForTree(TreeWidgetItem* root, StatsMap& stats, p
return;
}
calculate_medians(stats.begin(), stats.end());
calculateMedians(stats.begin(), stats.end());
std::deque<TreeWidgetItem*> queue;

View File

@ -72,10 +72,8 @@ namespace loader {
struct Stats
{
struct Counter { uint32_t count = 0; };
profiler::BlockStatistics stats;
std::map<profiler::timestamp_t, Counter> durations;
profiler_gui::DurationsCountMap durations;
Stats(profiler::timestamp_t duration, profiler::block_index_t block_index, profiler::block_index_t parent_index)
: stats(duration, block_index, parent_index)