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

(profiler reader) Gathering per frame statistics + refactoring;

(profiler GUI) Lightening profiler::colors to be more bright;
(ProfTreeWidget) Displaying per frame and per thread statistics;
(ProfGraphicsView) Draw chronometer item text in Difference mode to be more readable.
This commit is contained in:
Victor Zarubkin 2016-08-07 19:38:31 +03:00
parent 888ea2e61c
commit 3017be305a
8 changed files with 308 additions and 153 deletions

View File

@ -94,19 +94,21 @@ namespace profiler {
typedef ::std::list<BlocksTree> children_t;
children_t children; ///< List of children blocks. May be empty.
::profiler::SerilizedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
::profiler::BlockStatistics* frame_statistics; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
::profiler::BlockStatistics* total_statistics; ///< Pointer to statistics for this block within the bounds of all frames per current thread
children_t children; ///< List of children blocks. May be empty.
::profiler::SerilizedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
unsigned int block_index; ///< Index of this block
unsigned int total_children_number; ///< Number of all children including number of grandchildren (and so on)
unsigned short depth; ///< Maximum number of sublevels (maximum children depth)
unsigned int block_index; ///< Index of this block
unsigned int total_children_number; ///< Number of all children including number of grandchildren (and so on)
unsigned short depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree()
: node(nullptr)
, frame_statistics(nullptr)
, total_statistics(nullptr)
, per_parent_stats(nullptr)
, per_frame_stats(nullptr)
, per_thread_stats(nullptr)
, block_index(0)
, total_children_number(0)
, depth(0)
@ -132,8 +134,9 @@ namespace profiler {
delete node;
}
release(total_statistics);
release(frame_statistics);
release(per_thread_stats);
release(per_parent_stats);
release(per_frame_stats);
}
bool operator < (const This& other) const
@ -157,28 +160,35 @@ namespace profiler {
delete node;
}
if (total_statistics != that.total_statistics)
if (per_thread_stats != that.per_thread_stats)
{
release(total_statistics);
release(per_thread_stats);
}
if (frame_statistics != that.frame_statistics)
if (per_parent_stats != that.per_parent_stats)
{
release(frame_statistics);
release(per_parent_stats);
}
if (per_frame_stats != that.per_frame_stats)
{
release(per_frame_stats);
}
children = ::std::move(that.children);
node = that.node;
frame_statistics = that.frame_statistics;
total_statistics = that.total_statistics;
per_parent_stats = that.per_parent_stats;
per_frame_stats = that.per_frame_stats;
per_thread_stats = that.per_thread_stats;
block_index = that.block_index;
total_children_number = that.total_children_number;
depth = that.depth;
that.node = nullptr;
that.frame_statistics = nullptr;
that.total_statistics = nullptr;
that.per_parent_stats = nullptr;
that.per_frame_stats = nullptr;
that.per_thread_stats = nullptr;
}
}; // END of class BlocksTree.

View File

@ -52,7 +52,7 @@ const unsigned short ROW_SPACING = 4;
const QRgb BORDERS_COLOR = 0x00a07050;
const QRgb BACKGROUND_1 = 0x00dddddd;
const QRgb BACKGROUND_2 = 0x00ffffff;
const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x40408040);
const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x20408040);
const unsigned int TEST_PROGRESSION_BASE = 4;
@ -589,6 +589,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
_painter->drawRect(rect);
// draw text
_painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background
_painter->setPen(0xffffffff - m_color.rgb());
_painter->setFont(m_font);
@ -604,7 +605,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
if (!m_bMain)
{
rect.setTop(rect.top() + textRect.height() * 1.33);
rect.setTop(rect.top() + textRect.height() * 1.5);
}
if (textRect.width() < rect.width())
@ -979,7 +980,7 @@ void ProfGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
}
// Calculating scene rect
const qreal endX = time2position(finish) + 1.0;
const qreal endX = time2position(finish) + 1500.0;
scene()->setSceneRect(0, 0, endX, y);
// Stub! :O
@ -1074,7 +1075,7 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block
const auto color = child.node->block()->getColor();
b.block = &child;
b.color = ::profiler_gui::toRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
b.setRect(xbegin, _y, duration, GRAPHICS_ROW_SIZE);
b.totalHeight = GRAPHICS_ROW_SIZE + h;
@ -1113,6 +1114,10 @@ void ProfGraphicsView::setScrollbar(ProfGraphicsScrollbar* _scrollbar)
void ProfGraphicsView::updateVisibleSceneRect()
{
m_visibleSceneRect = mapToScene(rect()).boundingRect();
auto vbar = verticalScrollBar();
if (vbar && vbar->isVisible())
m_visibleSceneRect.setWidth(m_visibleSceneRect.width() - vbar->width() - 2);
}
void ProfGraphicsView::updateScene()
@ -1375,7 +1380,7 @@ void ProfGraphicsView::mouseMoveEvent(QMouseEvent* _event)
updateVisibleSceneRect(); // Update scene visible rect only once
// Update flicker speed
m_flickerSpeedX += delta.x() >> 2;
m_flickerSpeedX += delta.x() >> 1;
m_flickerSpeedY += delta.y() >> 1;
if (!m_flickerTimer.isActive())
{

View File

@ -39,21 +39,38 @@ enum ColumnsIndexes
COL_UNKNOWN = -1,
COL_NAME = 0,
COL_BEGIN,
COL_DURATION,
COL_SELF_DURATION,
COL_DURATION_SUM_PER_PARENT,
COL_DURATION_SUM_PER_FRAME,
COL_DURATION_SUM_PER_THREAD,
COL_SELF_DURATION_PERCENT,
COL_PERCENT_OF_PARENT,
COL_PERCENT_OF_FRAME,
COL_PERCENT_PER_PARENT,
COL_PERCENT_PER_FRAME,
COL_PERCENT_SUM_PER_PARENT,
COL_PERCENT_SUM_PER_FRAME,
COL_PERCENT_SUM_PER_THREAD,
COL_END,
COL_MIN,
COL_MAX,
COL_AVERAGE,
COL_NCALLS,
COL_MIN_TOTAL,
COL_MAX_TOTAL,
COL_AVERAGE_TOTAL,
COL_NCALLS_TOTAL,
COL_MIN_PER_FRAME,
COL_MAX_PER_FRAME,
COL_AVERAGE_PER_FRAME,
COL_NCALLS_PER_FRAME,
COL_MIN_PER_PARENT,
COL_MAX_PER_PARENT,
COL_AVERAGE_PER_PARENT,
COL_NCALLS_PER_PARENT,
COL_MIN_PER_THREAD,
COL_MAX_PER_THREAD,
COL_AVERAGE_PER_THREAD,
COL_NCALLS_PER_THREAD,
COL_COLUMNS_NUMBER
};
@ -87,15 +104,19 @@ bool ProfTreeWidgetItem::operator < (const Parent& _other) const
return Parent::operator < (_other);
}
case COL_NCALLS_TOTAL:
case COL_NCALLS:
case COL_NCALLS_PER_THREAD:
case COL_NCALLS_PER_PARENT:
case COL_NCALLS_PER_FRAME:
{
return data(col, Qt::UserRole).toUInt() < _other.data(col, Qt::UserRole).toUInt();
}
case COL_SELF_DURATION_PERCENT:
case COL_PERCENT_OF_PARENT:
case COL_PERCENT_OF_FRAME:
case COL_PERCENT_PER_PARENT:
case COL_PERCENT_PER_FRAME:
case COL_PERCENT_SUM_PER_PARENT:
case COL_PERCENT_SUM_PER_FRAME:
case COL_PERCENT_SUM_PER_THREAD:
{
return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt();
}
@ -122,6 +143,11 @@ const ::profiler::BlocksTree* ProfTreeWidgetItem::block() const
return data(COL_DURATION, Qt::UserRole).toULongLong();
}
::profiler::timestamp_t ProfTreeWidgetItem::selfDuration() const
{
return data(COL_SELF_DURATION, Qt::UserRole).toULongLong();
}
void ProfTreeWidgetItem::setTimeSmart(int _column, const ::profiler::timestamp_t& _time)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
@ -219,40 +245,46 @@ ProfTreeWidget::ProfTreeWidget(QWidget* _parent) : Parent(_parent), m_beginTime(
setColumnCount(COL_COLUMNS_NUMBER);
auto header = new QTreeWidgetItem();
header->setText(COL_NAME, "Name");
header->setText(COL_BEGIN, "Begin, ms");
header->setText(COL_DURATION, "Duration");
header->setText(COL_SELF_DURATION, "Self Dur.");
header->setText(COL_DURATION_SUM_PER_PARENT, "Tot. Dur./Parent");
header->setText(COL_DURATION_SUM_PER_FRAME, "Tot. Dur./Frame");
header->setText(COL_DURATION_SUM_PER_THREAD, "Tot. Dur./Thread");
header->setText(COL_SELF_DURATION_PERCENT, "Self %");
header->setText(COL_PERCENT_OF_PARENT, "Parent %");
header->setText(COL_PERCENT_OF_FRAME, "Frame %");
header->setText(COL_PERCENT_PER_PARENT, "% / Parent");
header->setText(COL_PERCENT_PER_FRAME, "% / Frame");
header->setText(COL_PERCENT_SUM_PER_FRAME, "Tot. % / Frame");
header->setText(COL_PERCENT_SUM_PER_PARENT, "Tot. % / Parent");
header->setText(COL_PERCENT_SUM_PER_THREAD, "Tot. % / Thread");
header->setText(COL_END, "End, ms");
header->setText(COL_MIN_TOTAL, "Min dur. total");
header->setText(COL_MAX_TOTAL, "Max dur. total");
header->setText(COL_AVERAGE_TOTAL, "Average dur. total");
header->setText(COL_MIN, "Min dur.");
header->setText(COL_MAX, "Max dur.");
header->setText(COL_AVERAGE, "Average dur.");
header->setText(COL_NCALLS, "N Calls");
header->setText(COL_NCALLS_TOTAL, "N Calls total");
header->setText(COL_MIN_PER_FRAME, "Min dur./Frame");
header->setText(COL_MAX_PER_FRAME, "Max dur./Frame");
header->setText(COL_AVERAGE_PER_FRAME, "Average dur./Frame");
header->setText(COL_NCALLS_PER_FRAME, "N Calls/Frame");
header->setText(COL_MIN_PER_PARENT, "Min dur./Parent");
header->setText(COL_MAX_PER_PARENT, "Max dur./Parent");
header->setText(COL_AVERAGE_PER_PARENT, "Average dur./Parent");
header->setText(COL_NCALLS_PER_PARENT, "N Calls/Parent");
header->setText(COL_MIN_PER_THREAD, "Min dur./Thread");
header->setText(COL_MAX_PER_THREAD, "Max dur./Thread");
header->setText(COL_AVERAGE_PER_THREAD, "Average dur./Thread");
header->setText(COL_NCALLS_PER_THREAD, "N Calls/Thread");
setHeaderItem(header);
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::ProfGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);
settings.beginGroup("tree_widget");
auto color_rows_set = settings.value("color_rows");
if (!color_rows_set.isNull())
m_bColorRows = color_rows_set.toBool();
for (int i = 0; i < columnCount(); i++)
{
if (settings.value(QString("Column") + QString::number(i)).toBool())
hideColumn(i);
}
settings.endGroup();
loadSettings();
}
ProfTreeWidget::ProfTreeWidget(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, QWidget* _parent) : This(_parent)
@ -320,6 +352,7 @@ void ProfTreeWidget::clearSilent(bool _global)
}
m_items.clear();
m_roots.clear();
const QSignalBlocker b(this);
clear();
@ -376,8 +409,14 @@ size_t ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const :
item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND);
m_items.push_back(item);
// TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now)
::profiler::timestamp_t children_duration = 0;
const auto children_items_number = setTreeInternal(block.children, item, nullptr, m_beginTime, finishtime + 1000000000ULL, false, children_duration);
for (const auto& child : block.children)
children_duration += child.node->block()->duration();
item->setTimeSmart(COL_SELF_DURATION, children_duration);
children_duration = 0;
const auto children_items_number = setTreeInternal(block.children, item, nullptr, item, m_beginTime, finishtime + 1000000000ULL, false, children_duration);
if (children_items_number > 0)
{
@ -390,11 +429,6 @@ size_t ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const :
}
m_roots[threadTree.first] = item;
if (children_duration > 0)
{
item->setTimeSmart(COL_SELF_DURATION, children_duration);
}
}
else
{
@ -463,6 +497,13 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
thread_item->setTimeSmart(COL_DURATION, duration);
thread_item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND);
thread_item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND);
// Calculate clean duration (sum of all children durations)
::profiler::timestamp_t children_duration = 0;
for (const auto& child : block.root->tree.children)
children_duration += child.node->block()->duration();
thread_item->setTimeSmart(COL_SELF_DURATION, children_duration);
threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item));
}
@ -478,34 +519,56 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
item->setTimeMs(COL_BEGIN, startTime - m_beginTime);
item->setTimeMs(COL_END, endTime - m_beginTime);
item->setData(COL_PERCENT_OF_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_OF_PARENT, "");
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_PARENT, "");
item->setData(COL_PERCENT_OF_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_OF_FRAME, "");
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_FRAME, "");
if (block.tree->total_statistics)
if (block.tree->per_thread_stats)
{
item->setTimeSmart(COL_MIN_TOTAL, block.tree->total_statistics->min_duration);
item->setTimeSmart(COL_MAX_TOTAL, block.tree->total_statistics->max_duration);
item->setTimeSmart(COL_AVERAGE_TOTAL, block.tree->total_statistics->average_duration());
item->setTimeSmart(COL_MIN_PER_THREAD, block.tree->per_thread_stats->min_duration);
item->setTimeSmart(COL_MAX_PER_THREAD, block.tree->per_thread_stats->max_duration);
item->setTimeSmart(COL_AVERAGE_PER_THREAD, block.tree->per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, block.tree->per_thread_stats->total_duration);
item->setData(COL_NCALLS_TOTAL, Qt::UserRole, block.tree->total_statistics->calls_number);
item->setText(COL_NCALLS_TOTAL, QString::number(block.tree->total_statistics->calls_number));
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, block.tree->per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(block.tree->per_thread_stats->calls_number));
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(block.tree->per_thread_stats->total_duration) / static_cast<double>(thread_item->selfDuration()));
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
}
else
{
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_THREAD, "");
}
if (block.tree->frame_statistics)
if (block.tree->per_parent_stats)
{
item->setTimeSmart(COL_MIN, block.tree->frame_statistics->min_duration);
item->setTimeSmart(COL_MAX, block.tree->frame_statistics->max_duration);
item->setTimeSmart(COL_AVERAGE, block.tree->frame_statistics->average_duration());
item->setTimeSmart(COL_MIN_PER_PARENT, block.tree->per_parent_stats->min_duration);
item->setTimeSmart(COL_MAX_PER_PARENT, block.tree->per_parent_stats->max_duration);
item->setTimeSmart(COL_AVERAGE_PER_PARENT, block.tree->per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, block.tree->per_parent_stats->total_duration);
item->setData(COL_NCALLS, Qt::UserRole, block.tree->frame_statistics->calls_number);
item->setText(COL_NCALLS, QString::number(block.tree->frame_statistics->calls_number));
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, block.tree->per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(block.tree->per_parent_stats->calls_number));
}
if (block.tree->per_frame_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, block.tree->per_frame_stats->min_duration);
item->setTimeSmart(COL_MAX_PER_FRAME, block.tree->per_frame_stats->max_duration);
item->setTimeSmart(COL_AVERAGE_PER_FRAME, block.tree->per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, block.tree->per_frame_stats->total_duration);
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, block.tree->per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(block.tree->per_frame_stats->calls_number));
}
const auto color = block.tree->node->block()->getColor();
const auto bgColor = ::profiler_gui::toRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto fgColor = 0x00ffffff - bgColor;
item->setBackgroundColor(bgColor);
item->setTextColor(fgColor);
@ -516,7 +579,7 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
::profiler::timestamp_t children_duration = 0;
if (!block.tree->children.empty())
{
children_items_number = setTreeInternal(block.tree->children, item, item, _left, _right, _strict, children_duration);
children_items_number = setTreeInternal(block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration);
}
int percentage = 100;
@ -563,16 +626,6 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
m_roots[it.first] = item;
m_items.push_back(item);
++total_items;
// Calculate clean duration (sum of all children durations)
::profiler::timestamp_t children_duration = 0;
auto itemBlock = item->block();
for (const auto& child : itemBlock->children)
{
children_duration += child.node->block()->duration();
}
item->setTimeSmart(COL_SELF_DURATION, children_duration);
}
else
{
@ -583,7 +636,7 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
return total_items;
}
size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ProfTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration)
size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ProfTreeWidgetItem* _frame, ProfTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration)
{
size_t total_items = 0;
for (const auto& child : _children)
@ -607,49 +660,78 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
item->setTimeSmart(COL_DURATION, duration);
item->setTimeMs(COL_BEGIN, startTime - m_beginTime);
item->setTimeMs(COL_END, endTime - m_beginTime);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
auto percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_parent->duration()));
auto percentage_sum = child.per_parent_stats ? static_cast<int>(0.5 + 100. * static_cast<double>(child.per_parent_stats->total_duration) / static_cast<double>(_parent->duration())) : 0;
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum));
if (_frame != nullptr)
{
auto percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_parent->duration()));
item->setData(COL_PERCENT_OF_PARENT, Qt::UserRole, percentage);
item->setText(COL_PERCENT_OF_PARENT, QString::number(percentage));
if (_parent != _frame)
{
percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_frame->duration()));
item->setData(COL_PERCENT_OF_FRAME, Qt::UserRole, percentage);
item->setText(COL_PERCENT_OF_FRAME, QString::number(percentage));
percentage_sum = child.per_frame_stats ? static_cast<int>(0.5 + 100. * static_cast<double>(child.per_frame_stats->total_duration) / static_cast<double>(_frame->duration())) : 0;
}
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum));
}
else
{
item->setData(COL_PERCENT_OF_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_OF_PARENT, "");
item->setData(COL_PERCENT_OF_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_OF_FRAME, "");
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_FRAME, "");
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_FRAME, "");
}
if (child.total_statistics)
if (child.per_thread_stats)
{
item->setTimeSmart(COL_MIN_TOTAL, child.total_statistics->min_duration);
item->setTimeSmart(COL_MAX_TOTAL, child.total_statistics->max_duration);
item->setTimeSmart(COL_AVERAGE_TOTAL, child.total_statistics->average_duration());
item->setTimeSmart(COL_MIN_PER_THREAD, child.per_thread_stats->min_duration);
item->setTimeSmart(COL_MAX_PER_THREAD, child.per_thread_stats->max_duration);
item->setTimeSmart(COL_AVERAGE_PER_THREAD, child.per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, child.per_thread_stats->total_duration);
item->setData(COL_NCALLS_TOTAL, Qt::UserRole, child.total_statistics->calls_number);
item->setText(COL_NCALLS_TOTAL, QString::number(child.total_statistics->calls_number));
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, child.per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(child.per_thread_stats->calls_number));
if (_thread)
{
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(child.per_thread_stats->total_duration) / static_cast<double>(_thread->selfDuration()));
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
}
}
if (child.frame_statistics)
if (child.per_parent_stats)
{
item->setTimeSmart(COL_MIN, child.frame_statistics->min_duration);
item->setTimeSmart(COL_MAX, child.frame_statistics->max_duration);
item->setTimeSmart(COL_AVERAGE, child.frame_statistics->average_duration());
item->setTimeSmart(COL_MIN_PER_PARENT, child.per_parent_stats->min_duration);
item->setTimeSmart(COL_MAX_PER_PARENT, child.per_parent_stats->max_duration);
item->setTimeSmart(COL_AVERAGE_PER_PARENT, child.per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, child.per_parent_stats->total_duration);
item->setData(COL_NCALLS, Qt::UserRole, child.frame_statistics->calls_number);
item->setText(COL_NCALLS, QString::number(child.frame_statistics->calls_number));
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, child.per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(child.per_parent_stats->calls_number));
}
if (child.per_frame_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, child.per_frame_stats->min_duration);
item->setTimeSmart(COL_MAX_PER_FRAME, child.per_frame_stats->max_duration);
item->setTimeSmart(COL_AVERAGE_PER_FRAME, child.per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, child.per_frame_stats->total_duration);
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, child.per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(child.per_frame_stats->calls_number));
}
const auto color = child.node->block()->getColor();
const auto bgColor = ::profiler_gui::toRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto fgColor = 0x00ffffff - bgColor;
item->setBackgroundColor(bgColor);
item->setTextColor(fgColor);
@ -660,10 +742,10 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
::profiler::timestamp_t children_duration = 0;
if (!child.children.empty())
{
children_items_number = setTreeInternal(child.children, item, _frame ? _frame : item, _left, _right, _strict, children_duration);
children_items_number = setTreeInternal(child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration);
}
int percentage = 100;
percentage = 100;
auto self_duration = duration - children_duration;
if (children_duration > 0 && duration > 0)
{
@ -735,8 +817,9 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
{
switch (col)
{
case COL_MIN_TOTAL:
case COL_MIN:
case COL_MIN_PER_THREAD:
case COL_MIN_PER_PARENT:
case COL_MIN_PER_FRAME:
{
menu.addSeparator();
auto itemAction = new ProfItemAction("Jump to such item", item);
@ -745,8 +828,9 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
break;
}
case COL_MAX_TOTAL:
case COL_MAX:
case COL_MAX_PER_THREAD:
case COL_MAX_PER_PARENT:
case COL_MAX_PER_FRAME:
{
menu.addSeparator();
auto itemAction = new ProfItemAction("Jump to such item", item);
@ -780,7 +864,7 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
void ProfTreeWidget::onJumpToMinItemClicked(ProfTreeWidgetItem* _item)
{
auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_item->block()->total_statistics->min_duration_block].tree_item;
auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_item->block()->per_thread_stats->min_duration_block].tree_item;
if (item != nullptr)
{
scrollToItem(item, QAbstractItemView::PositionAtCenter);
@ -790,7 +874,7 @@ void ProfTreeWidget::onJumpToMinItemClicked(ProfTreeWidgetItem* _item)
void ProfTreeWidget::onJumpToMaxItemClicked(ProfTreeWidgetItem* _item)
{
auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_item->block()->total_statistics->max_duration_block].tree_item;
auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_item->block()->per_thread_stats->max_duration_block].tree_item;
if (item != nullptr)
{
scrollToItem(item, QAbstractItemView::PositionAtCenter);
@ -900,9 +984,27 @@ void ProfTreeWidget::onHideShowColumn(int _column)
//////////////////////////////////////////////////////////////////////////
void ProfTreeWidget::loadSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("tree_widget");
auto color_rows_set = settings.value("color_rows");
if (!color_rows_set.isNull())
m_bColorRows = color_rows_set.toBool();
for (int i = 0; i < columnCount(); i++)
{
if (settings.value(QString("Column") + QString::number(i)).toBool())
hideColumn(i);
}
settings.endGroup();
}
void ProfTreeWidget::saveSettings()
{
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("tree_widget");
settings.setValue("color_rows", m_bColorRows);
@ -914,3 +1016,5 @@ void ProfTreeWidget::saveSettings()
settings.endGroup();
}
//////////////////////////////////////////////////////////////////////////

View File

@ -60,6 +60,7 @@ public:
const ::profiler::BlocksTree* block() const;
::profiler::timestamp_t duration() const;
::profiler::timestamp_t selfDuration() const;
void setTimeSmart(int _column, const ::profiler::timestamp_t& _time);
@ -137,7 +138,7 @@ protected:
size_t setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
size_t setTreeInternal(const ::profiler::BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ProfTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration);
size_t setTreeInternal(const ::profiler::BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ProfTreeWidgetItem* _frame, ProfTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration);
void contextMenuEvent(QContextMenuEvent* _event) override;
@ -167,6 +168,7 @@ private slots:
protected:
void loadSettings();
void saveSettings();
}; // END of class ProfTreeWidget.

View File

@ -87,13 +87,18 @@ struct do_no_hash {
//////////////////////////////////////////////////////////////////////////
const QRgb DEFAULT_COLOR = 0x00f0e094;
const QRgb DEFAULT_COLOR = 0x00d4b494;//0x00f0e094;
inline QRgb toRgb(unsigned int _red, unsigned int _green, unsigned int _blue)
{
return (_red << 16) + (_green << 8) + _blue;
}
inline QRgb fromProfilerRgb(unsigned int _red, unsigned int _green, unsigned int _blue)
{
if (_red == 0 && _green == 0 && _blue == 0)
return DEFAULT_COLOR;
return (_red << 16) + (_green << 8) + _blue;
return toRgb(_red, _green, _blue) | 0x00141414;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -36,8 +36,8 @@ namespace profiler_gui {
const QString ORGANAZATION_NAME = "EasyProfiler";
const QString APPLICATION_NAME = "Easy profiler gui application";
const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x402020c0);
const QRgb SELECTED_THREAD_BACKGROUND = 0x00d8d840;
const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x202020c0);
const QRgb SELECTED_THREAD_BACKGROUND = 0x00e0e060;
const QRgb SELECTED_THREAD_FOREGROUND = 0x00ffffff - SELECTED_THREAD_BACKGROUND;
//////////////////////////////////////////////////////////////////////////

View File

@ -167,13 +167,14 @@ void ProfMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
const auto h = ::std::max((item.width() - m_minDuration) * coeff, 5.0);
const auto col = h * heightRevert;
const auto color = ::profiler_gui::toRgb(col * 255, (1.0 - col) * 255, 0); // item.color;
//const auto color = ::profiler_gui::toRgb(col * 255, (1.0 - col) * 255, 0); // item.color;
const auto color = 0x00ffffff & QColor::fromHsvF((1.0 - col) * 0.35, 0.85, 0.85).rgb();
if (previousColor != color)
{
// Set background color brush for rectangle
previousColor = color;
brush.setColor(QColor::fromRgba(0x80000000 | color));
brush.setColor(QColor::fromRgba(0xc0000000 | color));
_painter->setBrush(brush);
}
@ -274,7 +275,7 @@ ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent)
m_chronometerIndicator = new ProfGraphicsSliderItem();
m_chronometerIndicator->setPos(0, 0);
m_chronometerIndicator->setZValue(10);
m_chronometerIndicator->setColor(::profiler_gui::CHRONOMETER_COLOR);
m_chronometerIndicator->setColor(0x40000000 | ::profiler_gui::CHRONOMETER_COLOR.rgba());
selfScene->addItem(m_chronometerIndicator);
m_chronometerIndicator->hide();

View File

@ -171,7 +171,7 @@ void update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _curr
{
// Update already existing statistics
_stats = it->second; // write pointer to statistics into output (this is BlocksTree::total_statistics or BlocksTree::frame_statistics)
_stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats)
++_stats->calls_number; // update calls number of this block
_stats->total_duration += duration; // update summary duration of all block calls
@ -205,22 +205,39 @@ void update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _curr
//////////////////////////////////////////////////////////////////////////
void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current)
{
update_statistics(_stats_map, _current, _current.per_frame_stats);
for (auto& child : _current.children)
{
update_statistics_recursive(_stats_map, child);
}
}
//////////////////////////////////////////////////////////////////////////
typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats;
extern "C"{
unsigned int fillTreesFromFile(const char* filename, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(::profiler::colors::Cyan)
::std::ifstream inFile(filename, ::std::fstream::binary);
if (!inFile.is_open()){
return 0;
}
StatsMap overall_statistics, frame_statistics;
//StatsMap overall_statistics;
PerThreadStats thread_statistics, parent_statistics, frame_statistics;
unsigned int blocks_counter = 0;
while (!inFile.eof()){
PROFILER_BEGIN_BLOCK("Read block from file")
PROFILER_BEGIN_BLOCK_GROUPED("Read block from file", ::profiler::colors::Green)
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
@ -234,7 +251,10 @@ extern "C"{
inFile.read((char*)&data[0], sz);
::profiler::BaseBlockData* baseData = (::profiler::BaseBlockData*)data;
auto& root = threaded_trees[baseData->getThreadId()];
auto block_thread_id = baseData->getThreadId();
auto& root = threaded_trees[block_thread_id];
auto& per_parent_statistics = parent_statistics[block_thread_id];
auto& per_thread_statistics = thread_statistics[block_thread_id];
::profiler::BlocksTree tree;
tree.node = new ::profiler::SerilizedBlock(sz, data);
@ -254,7 +274,7 @@ extern "C"{
{
//auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree);
/**/
PROFILER_BEGIN_BLOCK("Find children")
PROFILER_BEGIN_BLOCK_GROUPED("Find children", ::profiler::colors::Blue)
auto rlower1 = ++root.tree.children.rbegin();
for(; rlower1 != root.tree.children.rend(); ++rlower1){
if(mt0 > rlower1->node->block()->getBegin())
@ -270,16 +290,16 @@ extern "C"{
::profiler::timestamp_t children_duration = 0;
if (gather_statistics)
{
PROFILER_BEGIN_BLOCK("Gather statistic for frame")
frame_statistics.clear();
PROFILER_BEGIN_BLOCK_GROUPED("Gather statistic within parent", ::profiler::colors::Magenta)
per_parent_statistics.clear();
//frame_statistics.reserve(tree.children.size()); // this gives slow-down on Windows
//frame_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows
//per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows
//per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows
// TODO: check this behavior on Linux
for (auto& child : tree.children)
{
update_statistics(frame_statistics, child, child.frame_statistics);
update_statistics(per_parent_statistics, child, child.per_parent_stats);
children_duration += child.node->block()->duration();
tree.total_children_number += child.total_children_number;
@ -312,14 +332,14 @@ extern "C"{
if (gather_statistics)
{
PROFILER_BEGIN_BLOCK("Gather statistics")
PROFILER_BEGIN_BLOCK_GROUPED("Gather per thread statistics", ::profiler::colors::Coral)
auto& current = root.tree.children.back();
update_statistics(overall_statistics, current, current.total_statistics);
update_statistics(per_thread_statistics, current, current.per_thread_stats);
}
}
PROFILER_BEGIN_BLOCK("Gather statistics for roots")
PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple)
if (gather_statistics)
{
for (auto& it : threaded_trees)
@ -327,11 +347,19 @@ extern "C"{
auto& root = it.second;
root.thread_id = it.first;
frame_statistics.clear();
auto& per_parent_statistics = parent_statistics[it.first];
auto& per_frame_statistics = frame_statistics[it.first];
per_parent_statistics.clear();
for (auto& frame : root.tree.children)
{
update_statistics(per_parent_statistics, frame, frame.per_parent_stats);
// TODO: Optimize per frame stats gathering
per_frame_statistics.clear();
update_statistics_recursive(per_frame_statistics, frame);
root.tree.total_children_number += frame.total_children_number;
update_statistics(frame_statistics, frame, frame.frame_statistics);
if (root.tree.depth < frame.depth)
root.tree.depth = frame.depth;
}