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

(profiler Reader) Added block_index field and replaced pointers SerilizedBlock* to block indexes;

(profiler GUI) Added plain vector of ProfBlocks (additional information for gui) for fast access;
(ProfGraphicsView) Removed unnecessary methods; small refactoring;
(ProfTreeWidget) Removed unnecessary map of tree items;
(ProfGraphicsScrollbar) Added colorizing of minimap (green = low duration, red = long duration);
This commit is contained in:
Victor Zarubkin 2016-08-04 22:38:45 +03:00
parent 55cd5a5751
commit 4f0fabdfd6
12 changed files with 216 additions and 152 deletions

View File

@ -31,14 +31,14 @@ namespace profiler {
typedef uint32_t calls_number_t;
struct BlockStatistics
struct BlockStatistics final
{
::profiler::timestamp_t total_duration; ///< Summary duration of all block calls
::profiler::timestamp_t min_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high
::profiler::timestamp_t max_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high
const ::profiler::SerilizedBlock* min_duration_block; ///< Will be used in GUI to jump to the block with min duration
const ::profiler::SerilizedBlock* max_duration_block; ///< Will be used in GUI to jump to the block with max duration
::profiler::calls_number_t calls_number; ///< Block calls number
::profiler::timestamp_t total_duration; ///< Summary duration of all block calls
::profiler::timestamp_t min_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high
::profiler::timestamp_t max_duration; ///< Cached block->duration() value. TODO: Remove this if memory consumption will be too high
unsigned int min_duration_block; ///< Will be used in GUI to jump to the block with min duration
unsigned int max_duration_block; ///< Will be used in GUI to jump to the block with max duration
::profiler::calls_number_t calls_number; ///< Block calls number
// TODO: It is better to replace SerilizedBlock* with BlocksTree*, but this requires to store pointers in children list.
@ -46,18 +46,18 @@ namespace profiler {
: total_duration(0)
, min_duration(0)
, max_duration(0)
, min_duration_block(nullptr)
, max_duration_block(nullptr)
, min_duration_block(0)
, max_duration_block(0)
, calls_number(1)
{
}
BlockStatistics(::profiler::timestamp_t _duration, const ::profiler::SerilizedBlock* _block)
BlockStatistics(::profiler::timestamp_t _duration, unsigned int _block_index)
: total_duration(_duration)
, min_duration(_duration)
, max_duration(_duration)
, min_duration_block(_block)
, max_duration_block(_block)
, min_duration_block(_block_index)
, max_duration_block(_block_index)
, calls_number(1)
{
}
@ -95,19 +95,19 @@ namespace profiler {
typedef ::std::list<BlocksTree> children_t;
children_t children; ///< List of children blocks. May be empty.
::profiler::timestamp_t self_duration; ///< Self time (excluding children blocks). This is time which was not measured by children blocks.
::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
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()
: self_duration(0)
, node(nullptr)
: node(nullptr)
, frame_statistics(nullptr)
, total_statistics(nullptr)
, block_index(0)
, total_children_number(0)
, depth(0)
{
@ -168,11 +168,11 @@ namespace profiler {
}
children = ::std::move(that.children);
self_duration = that.self_duration;
node = that.node;
frame_statistics = that.frame_statistics;
total_statistics = that.total_statistics;
block_index = that.block_index;
total_children_number = that.total_children_number;
depth = that.depth;
@ -185,7 +185,7 @@ namespace profiler {
//////////////////////////////////////////////////////////////////////////
class BlocksTreeRoot
class BlocksTreeRoot final
{
typedef BlocksTreeRoot This;

View File

@ -53,7 +53,7 @@ const QRgb BACKGROUND_2 = 0x00ffffff;
const QColor CHRONOMETER_COLOR = QColor(64, 64, 64, 64);
const QRgb CHRONOMETER_TEXT_COLOR = 0xff302010;
const int TEST_PROGRESSION_BASE = 4;
const unsigned int TEST_PROGRESSION_BASE = 4;
//////////////////////////////////////////////////////////////////////////
@ -168,7 +168,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
}
else
{
m_levelsIndexes[0] = level0.size() - 1;
m_levelsIndexes[0] = static_cast<unsigned int>(level0.size() - 1);
}
@ -208,7 +208,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
char state = 1;
//bool changebrush = false;
for (unsigned int i = m_levelsIndexes[l], end = level.size(); i < end; ++i)
for (unsigned int i = m_levelsIndexes[l], end = static_cast<unsigned int>(level.size()); i < end; ++i)
{
auto& item = level[i];
@ -455,7 +455,7 @@ void ProfGraphicsItem::setLevels(unsigned short _levels)
m_levelsIndexes.resize(_levels, -1);
}
void ProfGraphicsItem::reserve(unsigned short _level, size_t _items)
void ProfGraphicsItem::reserve(unsigned short _level, unsigned int _items)
{
m_levels[_level].reserve(_items);
}
@ -467,34 +467,22 @@ const ProfGraphicsItem::Children& ProfGraphicsItem::items(unsigned short _level)
return m_levels[_level];
}
const ::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned short _level, size_t _index) const
const ::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned short _level, unsigned int _index) const
{
return m_levels[_level][_index];
}
::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned short _level, size_t _index)
::profiler_gui::ProfBlockItem& ProfGraphicsItem::getItem(unsigned short _level, unsigned int _index)
{
return m_levels[_level][_index];
}
size_t ProfGraphicsItem::addItem(unsigned short _level)
unsigned int ProfGraphicsItem::addItem(unsigned short _level)
{
m_levels[_level].emplace_back();
return m_levels[_level].size() - 1;
return static_cast<unsigned int>(m_levels[_level].size() - 1);
}
size_t ProfGraphicsItem::addItem(unsigned short _level, const ::profiler_gui::ProfBlockItem& _item)
{
m_levels[_level].emplace_back(_item);
return m_levels[_level].size() - 1;
}
size_t ProfGraphicsItem::addItem(unsigned short _level, ::profiler_gui::ProfBlockItem&& _item)
{
m_levels[_level].emplace_back(::std::forward<::profiler_gui::ProfBlockItem&&>(_item));
return m_levels[_level].size() - 1;
}
//////////////////////////////////////////////////////////////////////////
ProfChronometerItem::ProfChronometerItem() : QGraphicsItem(), m_left(0), m_right(0), m_font(QFont("CourierNew", 16, 2))
@ -677,14 +665,14 @@ ProfGraphicsView::~ProfGraphicsView()
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, size_t _childrenNumber, size_t& _total_items)
void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, unsigned int _childrenNumber, unsigned int& _total_items)
{
size_t nchildren = _childrenNumber;
unsigned int nchildren = _childrenNumber;
_childrenNumber = TEST_PROGRESSION_BASE;
for (size_t i = 0; i < nchildren; ++i)
for (unsigned int i = 0; i < nchildren; ++i)
{
size_t j = _item->addItem(_level);
auto j = _item->addItem(_level);
auto& b = _item->getItem(_level, j);
b.color = ::profiler_gui::toRgb(30 + rand() % 225, 30 + rand() % 225, 30 + rand() % 225);
b.state = 0;
@ -712,7 +700,7 @@ void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxl
}
}
void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_estimate, int _rows)
void ProfGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, int _rows)
{
static const qreal X_BEGIN = 50;
static const qreal Y_BEGIN = 0;
@ -721,9 +709,9 @@ void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_es
// Calculate items number for first level
_rows = ::std::max(1, _rows);
const size_t children_per_frame = static_cast<size_t>(0.5 + static_cast<double>(_total_items_number_estimate) / static_cast<double>(_rows * _frames_number));
const auto children_per_frame = static_cast<unsigned int>(0.5 + static_cast<double>(_total_items_number_estimate) / static_cast<double>(_rows * _frames_number));
const int max_depth = logn<TEST_PROGRESSION_BASE>(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1);
const size_t first_level_children_count = children_per_frame * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5;
const auto first_level_children_count = static_cast<unsigned int>(static_cast<double>(children_per_frame) * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5);
::std::vector<ProfGraphicsItem*> thread_items(_rows);
for (int i = 0; i < _rows; ++i)
@ -738,7 +726,7 @@ void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_es
}
// Calculate items number for each sublevel
size_t chldrn = first_level_children_count;
auto chldrn = first_level_children_count;
for (int i = 1; i <= max_depth; ++i)
{
for (int i = 0; i < _rows; ++i)
@ -751,7 +739,7 @@ void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_es
}
// Create required number of items
size_t total_items = 0;
unsigned int total_items = 0;
qreal maxX = 0;
const ProfGraphicsItem* longestItem = nullptr;
for (int i = 0; i < _rows; ++i)
@ -760,7 +748,7 @@ void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_es
qreal x = X_BEGIN, y = item->y();
for (unsigned int i = 0; i < _frames_number; ++i)
{
size_t j = item->addItem(0);
auto j = item->addItem(0);
auto& b = item->getItem(0, j);
b.color = ::profiler_gui::toRgb(30 + rand() % 225, 30 + rand() % 225, 30 + rand() % 225);
b.state = 0;
@ -796,7 +784,7 @@ void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_es
}
}
printf("TOTAL ITEMS = %llu\n", total_items);
printf("TOTAL ITEMS = %u\n", total_items);
// Calculate scene rect
auto item = thread_items.back();
@ -950,7 +938,7 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block
return 0;
}
_item->reserve(_level, _children.size());
_item->reserve(_level, static_cast<unsigned int>(_children.size()));
const auto next_level = _level + 1;
qreal total_duration = 0, prev_end = 0, maxh = 0;
@ -980,6 +968,11 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const ::profiler::Block
auto i = _item->addItem(_level);
auto& b = _item->getItem(_level, i);
auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index];
gui_block.graphics_item = _item;
gui_block.graphics_item_level = _level;
gui_block.graphics_item_index = i;
if (next_level < _item->levels() && !child.children.empty())
{
b.children_begin = static_cast<unsigned int>(_item->items(next_level).size());

View File

@ -92,7 +92,7 @@ public:
\param _level Index of the level
\param _items Desired number of items on this level */
void reserve(unsigned short _level, size_t _items);
void reserve(unsigned short _level, unsigned int _items);
/**\brief Returns reference to the array of items of specified level.
@ -103,40 +103,20 @@ public:
\param _level Index of the level
\param _index Index of required item */
const ::profiler_gui::ProfBlockItem& getItem(unsigned short _level, size_t _index) const;
const ::profiler_gui::ProfBlockItem& getItem(unsigned short _level, unsigned int _index) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
::profiler_gui::ProfBlockItem& getItem(unsigned short _level, size_t _index);
::profiler_gui::ProfBlockItem& getItem(unsigned short _level, unsigned int _index);
/** \brief Adds new item to required level.
\param _level Index of the level
\retval Index of the new created item */
size_t addItem(unsigned short _level);
/** \brief Adds new item to required level.
Constructs new item using copy constructor.
\param _level Index of the level
\param _item Reference to the source item to copy from
\retval Index of the new created item */
size_t addItem(unsigned short _level, const ::profiler_gui::ProfBlockItem& _item);
/** \brief Adds new item to required level.
Constructs new item using move constructor.
\param _level Index of the level
\param _item Reference to the source item to move from
\retval Index of the new created item */
size_t addItem(unsigned short _level, ::profiler_gui::ProfBlockItem&& _item);
unsigned int addItem(unsigned short _level);
/** \brief Finds top-level blocks which are intersects with required selection zone.
@ -251,7 +231,7 @@ public:
void setScrollbar(ProfGraphicsScrollbar* _scrollbar);
void clearSilent();
void test(size_t _frames_number, size_t _total_items_number_estimate, int _rows);
void test(unsigned int _frames_number, unsigned int _total_items_number_estimate, int _rows);
void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree);
signals:
@ -269,7 +249,7 @@ private:
void updateScene();
void scaleTo(qreal _scale);
qreal setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, unsigned short _level);
void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, size_t _childrenNumber, size_t& _total_items);
void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, unsigned int _childrenNumber, unsigned int& _total_items);
private slots:

View File

@ -287,16 +287,22 @@ void ProfTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ProfTreeWidget::clearSilent()
void ProfTreeWidget::clearSilent(bool _global)
{
m_beginTime = -1;
setSortingEnabled(false);
disconnect(this, &Parent::itemExpanded, this, &This::onItemExpand);
if (!_global)
{
for (auto item : m_items)
{
::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item = nullptr;
}
}
m_items.clear();
m_itemblocks.clear();
m_roots.clear();
const QSignalBlocker b(this);
clear();
@ -353,7 +359,8 @@ size_t ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const :
item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND);
m_items.push_back(item);
const auto children_items_number = setTreeInternal(block.children, item, nullptr, m_beginTime, finishtime + 1000000000ULL, false);
::profiler::timestamp_t children_duration = 0;
const auto children_items_number = setTreeInternal(block.children, item, nullptr, m_beginTime, finishtime + 1000000000ULL, false, children_duration);
if (children_items_number > 0)
{
@ -366,6 +373,11 @@ 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
{
@ -438,18 +450,13 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
}
auto item = new ProfTreeWidgetItem(block.tree, thread_item);
duration = block.tree->node->block()->duration();
duration = endTime - startTime;
item->setText(COL_NAME, block.tree->node->getBlockName());
item->setTimeSmart(COL_DURATION, duration);
item->setTimeSmart(COL_SELF_DURATION, block.tree->self_duration);
item->setTimeMs(COL_BEGIN, startTime - m_beginTime);
item->setTimeMs(COL_END, endTime - m_beginTime);
auto percentage = duration == 0 ? 100 : static_cast<int>(0.5 + 100. * static_cast<double>(block.tree->self_duration) / static_cast<double>(duration));
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
item->setData(COL_PERCENT_OF_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_OF_PARENT, "");
@ -485,15 +492,27 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
m_items.push_back(item);
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!block.tree->children.empty())
{
children_items_number = setTreeInternal(block.tree->children, item, item, _left, _right, _strict);
children_items_number = setTreeInternal(block.tree->children, item, item, _left, _right, _strict, children_duration);
}
int percentage = 100;
auto self_duration = duration - children_duration;
if (children_duration > 0 && duration > 0)
{
percentage = static_cast<int>(0.5 + 100. * static_cast<double>(self_duration) / static_cast<double>(duration));
}
item->setTimeSmart(COL_SELF_DURATION, self_duration);
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
total_items += children_items_number + 1;
m_itemblocks[block.tree->node] = item;
::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item;
if (m_bColorRows)
{
@ -509,56 +528,64 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler_gui::TreeBlocks& _blocks
for (auto& it : threadsMap)
{
if (it.second->childCount() > 0)
auto item = it.second;
if (item->childCount() > 0)
{
addTopLevelItem(it.second);
addTopLevelItem(item);
if (it.first == ::profiler_gui::EASY_GLOBALS.selected_thread)
{
it.second->colorize(true);
item->colorize(true);
}
m_roots[it.first] = it.second;
m_items.push_back(it.second);
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
{
delete it.second;
delete item;
}
}
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)
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 total_items = 0;
for (const auto& child : _children)
{
const auto startTime = child.node->block()->getBegin();
const auto endTime = child.node->block()->getEnd();
const auto duration = endTime - startTime;
_duration += duration;
if (startTime > _right || endTime < _left)
{
continue;
}
auto item = new ProfTreeWidgetItem(&child, _parent);
auto duration = child.node->block()->duration();
item->setText(COL_NAME, child.node->getBlockName());
item->setTimeSmart(COL_DURATION, duration);
item->setTimeSmart(COL_SELF_DURATION, child.self_duration);
item->setTimeMs(COL_BEGIN, startTime - m_beginTime);
item->setTimeMs(COL_END, endTime - m_beginTime);
auto percentage = duration == 0 ? 100 : static_cast<int>(0.5 + 100. * static_cast<double>(child.self_duration) / static_cast<double>(duration));
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
if (_frame != nullptr)
{
percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_parent->duration()));
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));
@ -605,15 +632,27 @@ size_t ProfTreeWidget::setTreeInternal(const ::profiler::BlocksTree::children_t&
m_items.push_back(item);
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!child.children.empty())
{
children_items_number = setTreeInternal(child.children, item, _frame ? _frame : item, _left, _right, _strict);
children_items_number = setTreeInternal(child.children, item, _frame ? _frame : item, _left, _right, _strict, children_duration);
}
int percentage = 100;
auto self_duration = duration - children_duration;
if (children_duration > 0 && duration > 0)
{
percentage = static_cast<int>(0.5 + 100. * static_cast<double>(self_duration) / static_cast<double>(duration));
}
item->setTimeSmart(COL_SELF_DURATION, self_duration);
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
total_items += children_items_number + 1;
m_itemblocks[child.node] = item;
::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item;
if (m_bColorRows)
{
@ -715,21 +754,21 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
void ProfTreeWidget::onJumpToMinItemClicked(ProfTreeWidgetItem* _item)
{
auto it = m_itemblocks.find(_item->block()->total_statistics->min_duration_block);
if (it != m_itemblocks.end())
auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_item->block()->total_statistics->min_duration_block].tree_item;
if (item != nullptr)
{
scrollToItem(it->second, QAbstractItemView::PositionAtCenter);
setCurrentItem(it->second);
scrollToItem(item, QAbstractItemView::PositionAtCenter);
setCurrentItem(item);
}
}
void ProfTreeWidget::onJumpToMaxItemClicked(ProfTreeWidgetItem* _item)
{
auto it = m_itemblocks.find(_item->block()->total_statistics->max_duration_block);
if (it != m_itemblocks.end())
auto item = ::profiler_gui::EASY_GLOBALS.gui_blocks[_item->block()->total_statistics->max_duration_block].tree_item;
if (item != nullptr)
{
scrollToItem(it->second, QAbstractItemView::PositionAtCenter);
setCurrentItem(it->second);
scrollToItem(item, QAbstractItemView::PositionAtCenter);
setCurrentItem(item);
}
}

View File

@ -110,11 +110,9 @@ class ProfTreeWidget : public QTreeWidget
protected:
typedef ::std::vector<ProfTreeWidgetItem*> Items;
typedef ::std::unordered_map<const ::profiler::SerilizedBlock*, ProfTreeWidgetItem*, ::profiler_gui::do_no_hash<const ::profiler::SerilizedBlock*>::hasher_t> BlockItemMap;
typedef ::std::unordered_map<::profiler::thread_id_t, ProfTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap;
Items m_items;
BlockItemMap m_itemblocks;
RootsMap m_roots;
::profiler::timestamp_t m_beginTime;
bool m_bColorRows;
@ -125,7 +123,7 @@ public:
ProfTreeWidget(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, QWidget* _parent = nullptr);
virtual ~ProfTreeWidget();
void clearSilent();
void clearSilent(bool _global = false);
public slots:
@ -139,7 +137,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);
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);
void contextMenuEvent(QContextMenuEvent* _event) override;

View File

@ -101,7 +101,7 @@ inline QRgb toRgb(unsigned int _red, unsigned int _green, unsigned int _blue)
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
struct ProfBlockItem
struct ProfBlockItem final
{
const ::profiler::BlocksTree* block; ///< Pointer to profiler block
qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene)
@ -134,24 +134,24 @@ typedef ::std::vector<ProfBlockItem> ProfItems;
//////////////////////////////////////////////////////////////////////////
struct ProfBlock
struct ProfSelectedBlock final
{
const ::profiler::BlocksTreeRoot* root;
const ::profiler::BlocksTree* tree;
ProfBlock() : root(nullptr), tree(nullptr)
ProfSelectedBlock() : root(nullptr), tree(nullptr)
{
}
ProfBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::BlocksTree* _tree)
ProfSelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::BlocksTree* _tree)
: root(_root)
, tree(_tree)
{
}
}; // END of struct ProfBlock.
}; // END of struct ProfSelectedBlock.
typedef ::std::vector<ProfBlock> TreeBlocks;
typedef ::std::vector<ProfSelectedBlock> TreeBlocks;
} // END of namespace profiler_gui.

View File

@ -38,6 +38,7 @@ namespace profiler_gui {
ProfGlobals::ProfGlobals()
: selected_thread(0)
, selected_block(0)
{
}

View File

@ -25,9 +25,16 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsItem;
class ProfTreeWidgetItem;
//////////////////////////////////////////////////////////////////////////
namespace profiler_gui {
class ProfGlobalSignals : public QObject
//////////////////////////////////////////////////////////////////////////
class ProfGlobalSignals final : public QObject
{
Q_OBJECT
@ -39,15 +46,32 @@ namespace profiler_gui {
signals:
void selectedThreadChanged(::profiler::thread_id_t _id);
void selectedBlockChanged(unsigned int _block_index);
};
struct ProfGlobals
//////////////////////////////////////////////////////////////////////////
struct ProfBlock final
{
ProfGraphicsItem* graphics_item;
ProfTreeWidgetItem* tree_item;
unsigned short graphics_item_level;
unsigned int graphics_item_index;
};
typedef ::std::vector<ProfBlock> ProfBlocks;
//////////////////////////////////////////////////////////////////////////
struct ProfGlobals final
{
static ProfGlobals& instance();
ProfGlobalSignals events;
::profiler::thread_blocks_tree_t profiler_blocks;
::profiler::thread_id_t selected_thread;
ProfBlocks gui_blocks;
::profiler::thread_id_t selected_thread;
unsigned int selected_block;
private:
@ -56,6 +80,8 @@ namespace profiler_gui {
static ProfGlobals& EASY_GLOBALS = ProfGlobals::instance();
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////

View File

@ -104,7 +104,7 @@ void ProfGraphicsSliderItem::setColor(QRgb _color)
//////////////////////////////////////////////////////////////////////////
ProfMinimapItem::ProfMinimapItem() : Parent(), m_pSource(nullptr), m_maxDuration(0), m_threadId(0)
ProfMinimapItem::ProfMinimapItem() : Parent(), m_pSource(nullptr), m_maxDuration(0), m_minDuration(0), m_threadId(0)
{
}
@ -128,32 +128,37 @@ void ProfMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
const auto currentScale = static_cast<const ProfGraphicsScrollbar*>(scene()->parent())->getWindowScale();
const auto bottom = m_boundingRect.bottom();
const auto coeff = (m_boundingRect.height() - 5) / m_maxDuration;
const auto coeff = m_boundingRect.height() / (m_maxDuration - m_minDuration);
const auto heightRevert = 1.0 / m_boundingRect.height();
QRectF rect;
QBrush brush(Qt::SolidPattern);
QRgb previousColor = 0;
brush.setColor(QColor::fromRgba(0x80808080));
//brush.setColor(QColor::fromRgba(0x80808080));
_painter->save();
_painter->setPen(Qt::NoPen);
_painter->setBrush(brush);
//_painter->setBrush(brush);
_painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
auto& items = *m_pSource;
for (const auto& item : items)
{
//if (previousColor != item.color)
//{
// // Set background color brush for rectangle
// previousColor = item.color;
// brush.setColor(QColor::fromRgba(0x40000000 | item.color));
// _painter->setBrush(brush);
//}
// Draw rectangle
auto h = 5 + item.width() * coeff;
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;
if (previousColor != color)
{
// Set background color brush for rectangle
previousColor = color;
brush.setColor(QColor::fromRgba(0x80000000 | color));
_painter->setBrush(brush);
}
rect.setRect(item.left() * currentScale, bottom - h, ::std::max(item.width() * currentScale, 1.0), h);
_painter->drawRect(rect);
}
@ -184,12 +189,20 @@ void ProfMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::prof
}
m_maxDuration = 0;
m_minDuration = 1e30;
for (const auto& item : *m_pSource)
{
if (item.width() > m_maxDuration)
auto w = item.width();
if (w > m_maxDuration)
{
m_maxDuration = item.width();
}
if (w < m_minDuration)
{
m_minDuration = w;
}
}
}

View File

@ -63,6 +63,7 @@ class ProfMinimapItem : public QGraphicsItem
QRectF m_boundingRect;
qreal m_maxDuration;
qreal m_minDuration;
const ::profiler_gui::ProfItems* m_pSource;
::profiler::thread_id_t m_threadId;

View File

@ -113,8 +113,14 @@ void ProfMainWindow::loadFile(const std::string& stdfilename)
if (nblocks != 0)
{
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
m_lastFile = stdfilename;
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks);
::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks);
memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::ProfBlock) * nblocks);
static_cast<ProfGraphicsViewWidget*>(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks);
}
}
@ -133,7 +139,13 @@ void ProfMainWindow::onReloadFileClicked(bool)
if (nblocks != 0)
{
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
::profiler_gui::EASY_GLOBALS.profiler_blocks.swap(prof_blocks);
::profiler_gui::EASY_GLOBALS.gui_blocks.resize(nblocks);
memset(::profiler_gui::EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::ProfBlock) * nblocks);
static_cast<ProfGraphicsViewWidget*>(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks);
}
}
@ -149,11 +161,14 @@ void ProfMainWindow::onExitClicked(bool)
void ProfMainWindow::onTestViewportClicked(bool)
{
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent();
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
auto view = static_cast<ProfGraphicsViewWidget*>(m_graphicsView->widget())->view();
view->clearSilent();
::profiler_gui::EASY_GLOBALS.gui_blocks.clear();
::profiler_gui::EASY_GLOBALS.profiler_blocks.clear();
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
view->test(18000, 40000000, 2);
//view->test(3, 300, 1);

View File

@ -162,10 +162,10 @@ typedef ::std::unordered_map<::std::string, ::profiler::BlockStatistics*> StatsM
automatically receive statistics update.
*/
void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _current, ::profiler::BlockStatistics*& _stats)
void update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::BlockStatistics*& _stats)
{
auto duration = _current->block()->duration();
StatsMap::key_type key(_current->getBlockName());
auto duration = _current.node->block()->duration();
StatsMap::key_type key(_current.node->getBlockName());
auto it = _stats_map.find(key);
if (it != _stats_map.end())
{
@ -180,7 +180,7 @@ void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _curren
if (duration > _stats->max_duration)
{
// update max duration
_stats->max_duration_block = _current;
_stats->max_duration_block = _current.block_index;
_stats->max_duration = duration;
}
@ -188,7 +188,7 @@ void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _curren
if (duration < _stats->min_duration)
{
// update min duraton
_stats->min_duration_block = _current;
_stats->min_duration_block = _current.block_index;
_stats->min_duration = duration;
}
@ -198,7 +198,7 @@ void update_statistics(StatsMap& _stats_map, ::profiler::SerilizedBlock* _curren
{
// This is first time the block appear in the file.
// Create new statistics.
_stats = new ::profiler::BlockStatistics(duration, _current);
_stats = new ::profiler::BlockStatistics(duration, _current.block_index);
_stats_map.insert(::std::make_pair(key, _stats));
}
}
@ -238,8 +238,7 @@ extern "C"{
::profiler::BlocksTree tree;
tree.node = new ::profiler::SerilizedBlock(sz, data);
tree.self_duration = tree.node->block()->duration();
++blocks_counter;
tree.block_index = ++blocks_counter;
if (::profiler::BLOCK_TYPE_THREAD_SIGN == baseData->getType())
{
@ -280,7 +279,7 @@ extern "C"{
for (auto& child : tree.children)
{
update_statistics(frame_statistics, child.node, child.frame_statistics);
update_statistics(frame_statistics, child, child.frame_statistics);
children_duration += child.node->block()->duration();
tree.total_children_number += child.total_children_number;
@ -299,7 +298,6 @@ extern "C"{
}
}
tree.self_duration -= children_duration;
tree.total_children_number += static_cast<unsigned int>(tree.children.size());
++tree.depth;
}
@ -316,7 +314,7 @@ extern "C"{
{
PROFILER_BEGIN_BLOCK("Gather statistics")
auto& current = root.tree.children.back();
update_statistics(overall_statistics, current.node, current.total_statistics);
update_statistics(overall_statistics, current, current.total_statistics);
}
}
@ -333,7 +331,7 @@ extern "C"{
for (auto& frame : root.tree.children)
{
root.tree.total_children_number += frame.total_children_number;
update_statistics(frame_statistics, frame.node, frame.frame_statistics);
update_statistics(frame_statistics, frame, frame.frame_statistics);
if (root.tree.depth < frame.depth)
root.tree.depth = frame.depth;
}