0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 16:11:02 +08:00

(profiler_gui) Reading file (MainWindow) and building blocks hierarchy (TreeWidget) in separate threads + displaying read progress;

(profiler_gui) Moving sources into separate files;
(profiler_gui) Rename Prof* classes into Easy*;
(EasyGraphicsView) Optimized performance by not painting items which were not expanded in TreeWidget. While there are no range selected for TreeWidget, only top-level blocks are painted on scene.
This commit is contained in:
Victor Zarubkin 2016-08-18 23:26:41 +03:00
parent 197a585307
commit 8f30948105
21 changed files with 2208 additions and 1552 deletions

View File

@ -23,6 +23,7 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
#include <map>
#include <vector>
#include <atomic>
#include "profiler/profiler.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -87,8 +88,8 @@ namespace profiler {
children_t children; ///< List of children blocks. May be empty.
::profiler::SerializedBlock* 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_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
::profiler::block_index_t block_index; ///< Index of this block
@ -288,6 +289,13 @@ namespace profiler {
m_data = _data;
}
void swap(SerializedData& other)
{
auto temp = other.m_data;
other.m_data = m_data;
m_data = temp;
}
private:
SerializedData(const SerializedData&) = delete;
@ -300,9 +308,13 @@ namespace profiler {
} // END of namespace profiler.
extern "C"{
unsigned int PROFILER_API fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false);
unsigned int PROFILER_API fillTreesFromFile(::std::atomic<int>& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false);
}
inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) {
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, gather_statistics);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -22,6 +22,10 @@ add_executable(${PROJECT_NAME}
graphics_scrollbar.cpp
main_window.h
main_window.cpp
tree_widget_item.h
tree_widget_item.cpp
tree_widget_loader.h
tree_widget_loader.cpp
#treemodel.h
#treemodel.cpp
#treeitem.h

File diff suppressed because it is too large Load Diff

View File

@ -21,13 +21,11 @@
* license : TODO: add license text
************************************************************************/
#ifndef MY____GRAPHICS___VIEW_H
#define MY____GRAPHICS___VIEW_H
#ifndef EASY__GRAPHICS_VIEW__H_
#define EASY__GRAPHICS_VIEW__H_
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QFont>
#include <QPoint>
#include <QTimer>
#include <QLabel>
@ -40,7 +38,7 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsView;
class EasyGraphicsView;
//////////////////////////////////////////////////////////////////////////
@ -58,7 +56,7 @@ inline qreal microseconds2units(qreal _value)
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsItem : public QGraphicsItem
class EasyGraphicsItem : public QGraphicsItem
{
typedef ::profiler_gui::ProfItems Children;
typedef ::std::vector<unsigned int> DrawIndexes;
@ -69,14 +67,12 @@ class ProfGraphicsItem : public QGraphicsItem
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
const bool m_bTest; ///< If true then we are running test()
unsigned char m_index; ///< This item's index in the list of items of ProfGraphicsView
unsigned char m_index; ///< This item's index in the list of items of EasyGraphicsView
public:
ProfGraphicsItem(unsigned char _index, bool _test);
ProfGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root);
virtual ~ProfGraphicsItem();
EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root);
virtual ~EasyGraphicsItem();
// Public virtual methods
@ -150,38 +146,37 @@ public:
private:
///< Returns pointer to the ProfGraphicsView widget.
const ProfGraphicsView* view() const;
///< Returns pointer to the EasyGraphicsView widget.
const EasyGraphicsView* view() const;
public:
// Public inline methods
///< Returns this item's index in the list of graphics items of ProfGraphicsView
///< Returns this item's index in the list of graphics items of EasyGraphicsView
inline unsigned char index() const
{
return m_index;
}
}; // END of class ProfGraphicsItem.
}; // END of class EasyGraphicsItem.
//////////////////////////////////////////////////////////////////////////
class ProfChronometerItem : public QGraphicsItem
class EasyChronometerItem : public QGraphicsItem
{
QFont m_font; ///< Font which is used to draw text
QPolygonF m_indicator; ///< Indicator displayed when this chrono item is out of screen (displaying only for main item)
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
QColor m_color; ///< Color of the item
qreal m_left, m_right; ///< Left and right bounds of the selection zone
bool m_bMain; ///< Is this chronometer main (true, by default)
bool m_bReverse;
bool m_bHover; ///< Mouse hover above indicator
bool m_bReverse; ///<
bool m_bHoverIndicator; ///< Mouse hover above indicator
public:
ProfChronometerItem(bool _main = true);
virtual ~ProfChronometerItem();
EasyChronometerItem(bool _main = true);
virtual ~EasyChronometerItem();
// Public virtual methods
@ -205,9 +200,9 @@ public:
bool contains(const QPointF& _pos) const;
inline bool hover() const
inline bool hoverIndicator() const
{
return m_bHover;
return m_bHoverIndicator;
}
inline bool reverse() const
@ -232,10 +227,10 @@ public:
private:
///< Returns pointer to the ProfGraphicsView widget.
const ProfGraphicsView* view() const;
///< Returns pointer to the EasyGraphicsView widget.
const EasyGraphicsView* view() const;
}; // END of class ProfChronometerItem.
}; // END of class EasyChronometerItem.
//////////////////////////////////////////////////////////////////////////
@ -251,24 +246,24 @@ public: \
void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } \
}
EASY_QGRAPHICSITEM(ProfBackgroundItem);
EASY_QGRAPHICSITEM(ProfTimelineIndicatorItem);
EASY_QGRAPHICSITEM(EasyBackgroundItem);
EASY_QGRAPHICSITEM(EasyTimelineIndicatorItem);
#undef EASY_QGRAPHICSITEM
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsView : public QGraphicsView
class EasyGraphicsView : public QGraphicsView
{
Q_OBJECT
private:
typedef ProfGraphicsView This;
typedef ::std::vector<ProfGraphicsItem*> Items;
typedef EasyGraphicsView This;
typedef ::std::vector<EasyGraphicsItem*> Items;
Items m_items; ///< Array of all ProfGraphicsItem items
::profiler_gui::TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (ProfChronometerItem)
Items m_items; ///< Array of all EasyGraphicsItem items
::profiler_gui::TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (EasyChronometerItem)
QTimer m_flickerTimer; ///< Timer for flicking behavior
QRectF m_visibleSceneRect; ///< Visible scene rectangle
::profiler::timestamp_t m_beginTime; ///< Begin time of profiler session. Used to reduce values of all begin and end times of profiler blocks.
@ -278,20 +273,19 @@ private:
QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent)
QPoint m_mouseMovePath; ///< Mouse move path between press and release of any button
Qt::MouseButtons m_mouseButtons; ///< Pressed mouse buttons
ProfGraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget
ProfChronometerItem* m_chronometerItem; ///< Pointer to the ProfChronometerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget.
ProfChronometerItem* m_chronometerItemAux; ///< Pointer to the ProfChronometerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time.
EasyGraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget
EasyChronometerItem* m_chronometerItem; ///< Pointer to the EasyChronometerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget.
EasyChronometerItem* m_chronometerItemAux; ///< Pointer to the EasyChronometerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time.
int m_flickerSpeedX; ///< Current flicking speed x
int m_flickerSpeedY; ///< Current flicking speed y
bool m_bDoubleClick; ///< Is mouse buttons double clicked
bool m_bUpdatingRect; ///< Stub flag which is used to avoid excess calculations on some scene update (flicking, scaling and so on)
bool m_bTest; ///< Testing flag (true when test() is called)
bool m_bEmpty; ///< Indicates whether scene is empty and has no items
public:
ProfGraphicsView(QWidget* _parent = nullptr);
virtual ~ProfGraphicsView();
EasyGraphicsView(QWidget* _parent = nullptr);
virtual ~EasyGraphicsView();
// Public virtual methods
@ -306,10 +300,9 @@ public:
// Public non-virtual methods
void setScrollbar(ProfGraphicsScrollbar* _scrollbar);
void setScrollbar(EasyGraphicsScrollbar* _scrollbar);
void clearSilent();
void test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows);
void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree);
const Items& getItems() const;
@ -324,15 +317,14 @@ private:
// Private non-virtual methods
ProfChronometerItem* createChronometer(bool _main = true);
bool moveChrono(ProfChronometerItem* _chronometerItem, qreal _mouseX);
EasyChronometerItem* createChronometer(bool _main = true);
bool moveChrono(EasyChronometerItem* _chronometerItem, qreal _mouseX);
void initMode();
void updateVisibleSceneRect();
void updateTimelineStep(qreal _windowWidth);
void updateScene();
void scaleTo(qreal _scale);
qreal setTree(ProfGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level);
void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, unsigned int _childrenNumber, unsigned int& _total_items);
qreal setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, qreal _y, short _level);
private slots:
@ -343,6 +335,7 @@ private slots:
void onFlickerTimeout();
void onSelectedThreadChange(::profiler::thread_id_t _id);
void onSelectedBlockChange(unsigned int _block_index);
void onItemsEspandStateChange();
public:
@ -384,53 +377,53 @@ private:
//return PROF_FROM_MILLISECONDS(_pos);
}
}; // END of class ProfGraphicsView.
}; // END of class EasyGraphicsView.
class ProfThreadViewWidget : public QWidget
//////////////////////////////////////////////////////////////////////////
class EasyThreadViewWidget : public QWidget
{
Q_OBJECT
private:
ProfGraphicsView* m_view;
EasyGraphicsView* m_view;
QLabel* m_label;
typedef ProfThreadViewWidget This;
typedef EasyThreadViewWidget This;
QHBoxLayout *m_layout;
public:
ProfThreadViewWidget(QWidget *parent, ProfGraphicsView* view);
virtual ~ProfThreadViewWidget();
EasyThreadViewWidget(QWidget *parent, EasyGraphicsView* view);
virtual ~EasyThreadViewWidget();
public slots:
void onSelectedThreadChange(::profiler::thread_id_t _id);
};
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsViewWidget : public QWidget
class EasyGraphicsViewWidget : public QWidget
{
Q_OBJECT
private:
ProfGraphicsView* m_view;
ProfGraphicsScrollbar* m_scrollbar;
//ProfThreadViewWidget* m_threadWidget;
EasyGraphicsView* m_view;
EasyGraphicsScrollbar* m_scrollbar;
//EasyThreadViewWidget* m_threadWidget;
public:
ProfGraphicsViewWidget(QWidget* _parent = nullptr);
virtual ~ProfGraphicsViewWidget();
EasyGraphicsViewWidget(QWidget* _parent = nullptr);
virtual ~EasyGraphicsViewWidget();
ProfGraphicsView* view();
EasyGraphicsView* view();
private:
void initWidget();
}; // END of class ProfGraphicsViewWidget.
}; // END of class EasyGraphicsViewWidget.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // MY____GRAPHICS___VIEW_H
#endif // EASY__GRAPHICS_VIEW__H_

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,8 @@
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of TreeWidget and it's auxiliary classes
* : for displyaing easy_profiler blocks tree.
* description : The file contains declaration of EasyTreeWidget and it's auxiliary classes
* : for displyaing EasyProfiler blocks tree.
* ----------------- :
* change log : * 2016/06/26 Victor Zarubkin: moved sources from tree_view.h
* : and renamed classes from My* to Prof*.
@ -17,66 +17,20 @@
* :
* : * 2016/06/29 Victor Zarubkin: Added clearSilent() method.
* :
* : *
* : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread;
* : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp
* ----------------- :
* license : TODO: add license text
************************************************************************/
#ifndef MY____TREE___VIEW_H
#define MY____TREE___VIEW_H
#ifndef EASY__TREE_WIDGET__H_
#define EASY__TREE_WIDGET__H_
#include <QTreeWidget>
#include <QAction>
#include <stdlib.h>
#include <unordered_map>
#include <vector>
#include <QTimer>
#include "tree_widget_loader.h"
#include "profiler/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
class ProfTreeWidgetItem : public QTreeWidgetItem
{
typedef QTreeWidgetItem Parent;
typedef ProfTreeWidgetItem This;
const ::profiler::BlocksTree* m_block;
QRgb m_customBGColor;
QRgb m_customTextColor;
public:
using Parent::setBackgroundColor;
using Parent::setTextColor;
ProfTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr);
virtual ~ProfTreeWidgetItem();
bool operator < (const Parent& _other) const override;
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, const QString& _prefix = "");
void setTimeMs(int _column, const ::profiler::timestamp_t& _time);
void setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix);
void setBackgroundColor(QRgb _color);
void setTextColor(QRgb _color);
void colorize(bool _colorize);
void collapseAll();
void expandAll();
}; // END of class ProfTreeWidgetItem.
//////////////////////////////////////////////////////////////////////////
@ -90,38 +44,40 @@ public: \
connect(this, &QAction::triggered, this, &ClassName::onToggle); } \
ClassName(const QString& _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \
connect(this, &QAction::triggered, this, &ClassName::onToggle); } \
virtual ~ClassName() {}\
virtual ~ClassName() {} \
private: \
void onToggle(bool) { emit clicked(m_item); }
DECLARE_QACTION(ProfItemAction, unsigned int) signals: void clicked(unsigned int _item); };
DECLARE_QACTION(ProfHideShowColumnAction, int) signals: void clicked(int _item); };
DECLARE_QACTION(EasyItemAction, unsigned int) signals: void clicked(unsigned int _item); };
DECLARE_QACTION(EasyHideShowColumnAction, int) signals: void clicked(int _item); };
#undef DECLARE_QACTION
//////////////////////////////////////////////////////////////////////////
class ProfTreeWidget : public QTreeWidget
class EasyTreeWidget : public QTreeWidget
{
Q_OBJECT
typedef QTreeWidget Parent;
typedef ProfTreeWidget This;
typedef EasyTreeWidget This;
protected:
typedef ::std::vector<ProfTreeWidgetItem*> Items;
typedef ::std::unordered_map<::profiler::thread_id_t, ProfTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap;
Items m_items;
RootsMap m_roots;
::profiler::timestamp_t m_beginTime;
bool m_bColorRows;
EasyTreeWidgetLoader m_hierarchyBuilder;
Items m_items;
RootsMap m_roots;
::profiler_gui::TreeBlocks m_inputBlocks;
QTimer m_fillTimer;
::profiler::timestamp_t m_beginTime;
class QProgressDialog* m_progress;
bool m_bColorRows;
bool m_bLocked;
public:
ProfTreeWidget(QWidget* _parent = nullptr);
virtual ~ProfTreeWidget();
EasyTreeWidget(QWidget* _parent = nullptr);
virtual ~EasyTreeWidget();
void clearSilent(bool _global = false);
@ -133,13 +89,9 @@ public slots:
protected:
size_t setTreeInternal(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree);
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, ProfTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration);
void contextMenuEvent(QContextMenuEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override;
void moveEvent(QMoveEvent* _event) override;
private slots:
@ -153,7 +105,8 @@ private slots:
void onExpandAllChildrenClicked(bool);
void onItemExpand(QTreeWidgetItem*);
void onItemExpand(QTreeWidgetItem* _item);
void onItemCollapse(QTreeWidgetItem* _item);
void onColorizeRowsTriggered(bool _colorize);
@ -165,13 +118,16 @@ private slots:
void onHideShowColumn(int _column);
void onFillTimerTimeout();
protected:
void loadSettings();
void saveSettings();
void alignProgressBar();
}; // END of class ProfTreeWidget.
}; // END of class EasyTreeWidget.
//////////////////////////////////////////////////////////////////////////
#endif // MY____TREE___VIEW_H
#endif // EASY__TREE_WIDGET__H_

View File

@ -24,13 +24,13 @@
namespace profiler_gui {
ProfGlobals& ProfGlobals::instance()
EasyGlobals& EasyGlobals::instance()
{
static ProfGlobals globals;
static EasyGlobals globals;
return globals;
}
ProfGlobals::ProfGlobals()
EasyGlobals::EasyGlobals()
: selected_thread(0)
, selected_block(-1)
, draw_graphics_items_borders(true)

View File

@ -28,11 +28,6 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsItem;
class ProfTreeWidgetItem;
//////////////////////////////////////////////////////////////////////////
namespace profiler_gui {
const QString ORGANAZATION_NAME = "EasyProfiler";
@ -45,16 +40,17 @@ namespace profiler_gui {
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
struct ProfBlock final
struct EasyBlock final
{
unsigned int tree_item;
unsigned int graphics_item_index;
unsigned char graphics_item_level;
unsigned char graphics_item;
bool expanded;
};
#pragma pack(pop)
typedef ::std::vector<ProfBlock> ProfBlocks;
typedef ::std::vector<EasyBlock> EasyBlocks;
template <class T>
inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString))
@ -64,13 +60,13 @@ namespace profiler_gui {
//////////////////////////////////////////////////////////////////////////
struct ProfGlobals final
struct EasyGlobals final
{
static ProfGlobals& instance();
static EasyGlobals& instance();
ProfGlobalSignals events; ///< Global signals
EasyGlobalSignals events; ///< Global signals
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file
ProfBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
::profiler::thread_id_t selected_thread; ///< Current selected thread id
unsigned int selected_block; ///< Current selected profiler block index
bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not
@ -78,10 +74,10 @@ namespace profiler_gui {
private:
ProfGlobals();
EasyGlobals();
};
#ifndef IGNORE_GLOBALS_DECLARATION
static ProfGlobals& EASY_GLOBALS = ProfGlobals::instance();
static EasyGlobals& EASY_GLOBALS = EasyGlobals::instance();
#endif
//////////////////////////////////////////////////////////////////////////

View File

@ -6,7 +6,7 @@
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of ProfGlobalSignals QObject class.
* description : The file contains implementation of EasyGlobalSignals QObject class.
* ----------------- :
* change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.cpp
* :
@ -22,11 +22,11 @@
namespace profiler_gui {
ProfGlobalSignals::ProfGlobalSignals() : QObject()
EasyGlobalSignals::EasyGlobalSignals() : QObject()
{
}
ProfGlobalSignals::~ProfGlobalSignals()
EasyGlobalSignals::~EasyGlobalSignals()
{
}

View File

@ -5,21 +5,24 @@
#include "profiler/profiler.h"
namespace profiler_gui {
class ProfGlobalSignals final : public QObject
class EasyGlobalSignals final : public QObject
{
Q_OBJECT
public:
ProfGlobalSignals();
virtual ~ProfGlobalSignals();
EasyGlobalSignals();
virtual ~EasyGlobalSignals();
signals:
void selectedThreadChanged(::profiler::thread_id_t _id);
void selectedBlockChanged(unsigned int _block_index);
};
void itemsExpandStateChanged();
}
}; // END of class EasyGlobalSignals.
} // END of namespace profiler_gui.
#endif // GLOBALS_QOBJECTS_H

View File

@ -16,6 +16,7 @@
************************************************************************/
#include <algorithm>
#include <QGraphicsScene>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QResizeEvent>
@ -41,33 +42,33 @@ auto const clamp = [](qreal _minValue, qreal _value, qreal _maxValue)
//////////////////////////////////////////////////////////////////////////
ProfGraphicsSliderItem::ProfGraphicsSliderItem(bool _main) : Parent(), m_halfwidth(0)
EasyGraphicsSliderItem::EasyGraphicsSliderItem(bool _main) : Parent(), m_halfwidth(0)
{
m_leftIndicator.reserve(3);
m_rightIndicator.reserve(3);
const auto vcenter = DEFAULT_TOP + (_main ? INDICATOR_SIZE : DEFAULT_HEIGHT - INDICATOR_SIZE);
m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter - INDICATOR_SIZE));
m_leftIndicator.push_back(QPointF(0, vcenter));
m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter + INDICATOR_SIZE));
m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter - INDICATOR_SIZE));
m_rightIndicator.push_back(QPointF(0, vcenter));
m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter + INDICATOR_SIZE));
// m_leftIndicator.reserve(3);
// m_rightIndicator.reserve(3);
//
// const auto vcenter = DEFAULT_TOP + (_main ? INDICATOR_SIZE : DEFAULT_HEIGHT - INDICATOR_SIZE);
// m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter - INDICATOR_SIZE));
// m_leftIndicator.push_back(QPointF(0, vcenter));
// m_leftIndicator.push_back(QPointF(-INDICATOR_SIZE, vcenter + INDICATOR_SIZE));
//
// m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter - INDICATOR_SIZE));
// m_rightIndicator.push_back(QPointF(0, vcenter));
// m_rightIndicator.push_back(QPointF(INDICATOR_SIZE, vcenter + INDICATOR_SIZE));
setWidth(1);
setBrush(Qt::SolidPattern);
}
ProfGraphicsSliderItem::~ProfGraphicsSliderItem()
EasyGraphicsSliderItem::~EasyGraphicsSliderItem()
{
}
void ProfGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget)
void EasyGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget)
{
//Parent::paint(_painter, _option, _widget);
const auto currentScale = static_cast<const ProfGraphicsScrollbar*>(scene()->parent())->getWindowScale();
const auto currentScale = static_cast<const EasyGraphicsScrollbar*>(scene()->parent())->getWindowScale();
const auto br = rect();
qreal w = width() * currentScale;
@ -80,59 +81,67 @@ void ProfGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphic
}
QRectF r(dx + br.left() * currentScale, br.top(), w, br.height());
const auto r_right = r.right();
const auto r_bottom = r.bottom();
auto b = brush();
_painter->save();
_painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
_painter->setBrush(brush());
_painter->setBrush(b);
_painter->setPen(Qt::NoPen);
_painter->drawRect(r);
if (w < INDICATOR_SIZE)
{
m_leftIndicator[0].setX(r.left() - INDICATOR_SIZE);
m_leftIndicator[1].setX(r.left());
m_leftIndicator[2].setX(r.left() - INDICATOR_SIZE);
// Draw left and right borders
_painter->setPen(QColor::fromRgba(0xe0000000 | b.color().rgb()));
_painter->drawLine(QPointF(r.left(), r.top()), QPointF(r.left(), r_bottom));
_painter->drawLine(QPointF(r_right, r.top()), QPointF(r_right, r_bottom));
const auto r_right = r.right();
m_rightIndicator[0].setX(r_right + INDICATOR_SIZE);
m_rightIndicator[1].setX(r_right);
m_rightIndicator[2].setX(r_right + INDICATOR_SIZE);
_painter->drawPolygon(m_leftIndicator);
_painter->drawPolygon(m_rightIndicator);
}
// // Draw triangle indicators for small slider
// if (w < INDICATOR_SIZE)
// {
// m_leftIndicator[0].setX(r.left() - INDICATOR_SIZE);
// m_leftIndicator[1].setX(r.left());
// m_leftIndicator[2].setX(r.left() - INDICATOR_SIZE);
//
// m_rightIndicator[0].setX(r_right + INDICATOR_SIZE);
// m_rightIndicator[1].setX(r_right);
// m_rightIndicator[2].setX(r_right + INDICATOR_SIZE);
//
// _painter->drawPolygon(m_leftIndicator);
// _painter->drawPolygon(m_rightIndicator);
// }
_painter->restore();
}
qreal ProfGraphicsSliderItem::width() const
qreal EasyGraphicsSliderItem::width() const
{
return m_halfwidth * 2.0;
}
qreal ProfGraphicsSliderItem::halfwidth() const
qreal EasyGraphicsSliderItem::halfwidth() const
{
return m_halfwidth;
}
void ProfGraphicsSliderItem::setWidth(qreal _width)
void EasyGraphicsSliderItem::setWidth(qreal _width)
{
m_halfwidth = _width * 0.5;
setRect(-m_halfwidth, DEFAULT_TOP, _width, DEFAULT_HEIGHT);
}
void ProfGraphicsSliderItem::setHalfwidth(qreal _halfwidth)
void EasyGraphicsSliderItem::setHalfwidth(qreal _halfwidth)
{
m_halfwidth = _halfwidth;
setRect(-m_halfwidth, DEFAULT_TOP, m_halfwidth * 2.0, DEFAULT_HEIGHT);
}
void ProfGraphicsSliderItem::setColor(QRgb _color)
void EasyGraphicsSliderItem::setColor(QRgb _color)
{
setColor(QColor::fromRgba(_color));
}
void ProfGraphicsSliderItem::setColor(const QColor& _color)
void EasyGraphicsSliderItem::setColor(const QColor& _color)
{
auto b = brush();
b.setColor(_color);
@ -141,29 +150,29 @@ void ProfGraphicsSliderItem::setColor(const QColor& _color)
//////////////////////////////////////////////////////////////////////////
ProfMinimapItem::ProfMinimapItem() : Parent(), m_pSource(nullptr), m_maxDuration(0), m_minDuration(0), m_threadId(0)
EasyMinimapItem::EasyMinimapItem() : Parent(), m_pSource(nullptr), m_maxDuration(0), m_minDuration(0), m_threadId(0)
{
}
ProfMinimapItem::~ProfMinimapItem()
EasyMinimapItem::~EasyMinimapItem()
{
}
QRectF ProfMinimapItem::boundingRect() const
QRectF EasyMinimapItem::boundingRect() const
{
return m_boundingRect;
}
void ProfMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget)
void EasyMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget)
{
if (m_pSource == nullptr)
{
return;
}
const auto currentScale = static_cast<const ProfGraphicsScrollbar*>(scene()->parent())->getWindowScale();
const auto currentScale = static_cast<const EasyGraphicsScrollbar*>(scene()->parent())->getWindowScale();
const auto bottom = m_boundingRect.bottom();
const auto coeff = m_boundingRect.height() / (m_maxDuration - m_minDuration);
const auto heightRevert = 1.0 / m_boundingRect.height();
@ -204,17 +213,17 @@ void ProfMinimapItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
_painter->restore();
}
::profiler::thread_id_t ProfMinimapItem::threadId() const
::profiler::thread_id_t EasyMinimapItem::threadId() const
{
return m_threadId;
}
void ProfMinimapItem::setBoundingRect(const QRectF& _rect)
void EasyMinimapItem::setBoundingRect(const QRectF& _rect)
{
m_boundingRect = _rect;
}
void ProfMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
{
m_pSource = _items;
m_threadId = _thread_id;
@ -258,7 +267,7 @@ void ProfMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::prof
//////////////////////////////////////////////////////////////////////////
ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent)
EasyGraphicsScrollbar::EasyGraphicsScrollbar(QWidget* _parent)
: Parent(_parent)
, m_minimumValue(0)
, m_maximumValue(500)
@ -287,20 +296,20 @@ ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent)
selfScene->setSceneRect(0, DEFAULT_TOP, 500, DEFAULT_HEIGHT);
setScene(selfScene);
m_slider = new ProfGraphicsSliderItem(true);
m_slider = new EasyGraphicsSliderItem(true);
m_slider->setPos(0, 0);
m_slider->setZValue(5);
m_slider->setColor(0x80e00000);
m_slider->setColor(0x40c0c0c0);
selfScene->addItem(m_slider);
m_chronometerIndicator = new ProfGraphicsSliderItem(false);
m_chronometerIndicator = new EasyGraphicsSliderItem(false);
m_chronometerIndicator->setPos(0, 0);
m_chronometerIndicator->setZValue(10);
m_chronometerIndicator->setColor(0x40000000 | ::profiler_gui::CHRONOMETER_COLOR.rgba());
selfScene->addItem(m_chronometerIndicator);
m_chronometerIndicator->hide();
m_minimap = new ProfMinimapItem();
m_minimap = new EasyMinimapItem();
m_minimap->setPos(0, 0);
m_minimap->setBoundingRect(selfScene->sceneRect());
selfScene->addItem(m_minimap);
@ -309,63 +318,63 @@ ProfGraphicsScrollbar::ProfGraphicsScrollbar(QWidget* _parent)
centerOn(0, 0);
}
ProfGraphicsScrollbar::~ProfGraphicsScrollbar()
EasyGraphicsScrollbar::~EasyGraphicsScrollbar()
{
}
//////////////////////////////////////////////////////////////////////////
qreal ProfGraphicsScrollbar::getWindowScale() const
qreal EasyGraphicsScrollbar::getWindowScale() const
{
return m_windowScale;
}
::profiler::thread_id_t ProfGraphicsScrollbar::minimapThread() const
::profiler::thread_id_t EasyGraphicsScrollbar::minimapThread() const
{
return m_minimap->threadId();
}
qreal ProfGraphicsScrollbar::minimum() const
qreal EasyGraphicsScrollbar::minimum() const
{
return m_minimumValue;
}
qreal ProfGraphicsScrollbar::maximum() const
qreal EasyGraphicsScrollbar::maximum() const
{
return m_maximumValue;
}
qreal ProfGraphicsScrollbar::range() const
qreal EasyGraphicsScrollbar::range() const
{
return m_maximumValue - m_minimumValue;
}
qreal ProfGraphicsScrollbar::value() const
qreal EasyGraphicsScrollbar::value() const
{
return m_value;
}
qreal ProfGraphicsScrollbar::sliderWidth() const
qreal EasyGraphicsScrollbar::sliderWidth() const
{
return m_slider->width();
}
qreal ProfGraphicsScrollbar::sliderHalfWidth() const
qreal EasyGraphicsScrollbar::sliderHalfWidth() const
{
return m_slider->halfwidth();
}
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::setValue(qreal _value)
void EasyGraphicsScrollbar::setValue(qreal _value)
{
m_value = clamp(m_minimumValue, _value, ::std::max(m_minimumValue, m_maximumValue - m_slider->width()));
m_slider->setX(m_value + m_slider->halfwidth());
emit valueChanged(m_value);
}
void ProfGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue)
void EasyGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue)
{
const auto oldRange = range();
const auto oldValue = oldRange < 1e-3 ? 0.0 : m_value / oldRange;
@ -380,7 +389,7 @@ void ProfGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue)
onWindowWidthChange(width());
}
void ProfGraphicsScrollbar::setSliderWidth(qreal _width)
void EasyGraphicsScrollbar::setSliderWidth(qreal _width)
{
m_slider->setWidth(_width);
setValue(m_value);
@ -388,25 +397,25 @@ void ProfGraphicsScrollbar::setSliderWidth(qreal _width)
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::setChronoPos(qreal _left, qreal _right)
void EasyGraphicsScrollbar::setChronoPos(qreal _left, qreal _right)
{
m_chronometerIndicator->setWidth(_right - _left);
m_chronometerIndicator->setX(_left + m_chronometerIndicator->halfwidth());
}
void ProfGraphicsScrollbar::showChrono()
void EasyGraphicsScrollbar::showChrono()
{
m_chronometerIndicator->show();
}
void ProfGraphicsScrollbar::hideChrono()
void EasyGraphicsScrollbar::hideChrono()
{
m_chronometerIndicator->hide();
}
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
{
m_minimap->setSource(_thread_id, _items);
scene()->update();
@ -414,7 +423,7 @@ void ProfGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, c
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::mousePressEvent(QMouseEvent* _event)
void EasyGraphicsScrollbar::mousePressEvent(QMouseEvent* _event)
{
m_mouseButtons = _event->buttons();
@ -429,7 +438,7 @@ void ProfGraphicsScrollbar::mousePressEvent(QMouseEvent* _event)
//QGraphicsView::mousePressEvent(_event);
}
void ProfGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event)
void EasyGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event)
{
m_mouseButtons = _event->buttons();
m_bScrolling = false;
@ -437,7 +446,7 @@ void ProfGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event)
//QGraphicsView::mouseReleaseEvent(_event);
}
void ProfGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
{
if (m_mouseButtons & Qt::LeftButton)
{
@ -452,14 +461,14 @@ void ProfGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
}
}
void ProfGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
{
onWindowWidthChange(_event->size().width());
}
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
{
if (::profiler_gui::EASY_GLOBALS.profiler_blocks.empty())
{
@ -480,10 +489,10 @@ void ProfGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
label = ::std::move(QString("Thread %1").arg(it.first));
}
auto action = new ProfIdAction(label, it.first);
auto action = new EasyIdAction(label, it.first);
action->setCheckable(true);
action->setChecked(it.first == ::profiler_gui::EASY_GLOBALS.selected_thread);
connect(action, &ProfIdAction::clicked, this, &This::onThreadActionClicked);
connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked);
menu.addAction(action);
}
@ -494,7 +503,7 @@ void ProfGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id)
void EasyGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id)
{
if (_id != m_minimap->threadId())
{
@ -505,7 +514,7 @@ void ProfGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id)
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsScrollbar::onWindowWidthChange(qreal _width)
void EasyGraphicsScrollbar::onWindowWidthChange(qreal _width)
{
const auto oldScale = m_windowScale;
const auto scrollingRange = range();

View File

@ -15,33 +15,32 @@
* license : TODO: add license text
************************************************************************/
#ifndef EASY_PROFILER__GRAPHICS_SCROLLBAR__H
#define EASY_PROFILER__GRAPHICS_SCROLLBAR__H
#ifndef EASY__GRAPHICS_SCROLLBAR__H
#define EASY__GRAPHICS_SCROLLBAR__H
#include <stdlib.h>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QAction>
#include <QPolygonF>
//#include <QPolygonF>
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsSliderItem : public QGraphicsRectItem
class EasyGraphicsSliderItem : public QGraphicsRectItem
{
typedef QGraphicsRectItem Parent;
typedef ProfGraphicsSliderItem This;
typedef EasyGraphicsSliderItem This;
private:
QPolygonF m_leftIndicator, m_rightIndicator;
//QPolygonF m_leftIndicator, m_rightIndicator;
qreal m_halfwidth;
public:
ProfGraphicsSliderItem(bool _main);
virtual ~ProfGraphicsSliderItem();
EasyGraphicsSliderItem(bool _main);
virtual ~EasyGraphicsSliderItem();
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
@ -54,14 +53,14 @@ public:
void setColor(QRgb _color);
void setColor(const QColor& _color);
}; // END of class ProfGraphicsSliderItem.
}; // END of class EasyGraphicsSliderItem.
//////////////////////////////////////////////////////////////////////////
class ProfMinimapItem : public QGraphicsItem
class EasyMinimapItem : public QGraphicsItem
{
typedef QGraphicsItem Parent;
typedef ProfMinimapItem This;
typedef EasyMinimapItem This;
QRectF m_boundingRect;
qreal m_maxDuration;
@ -71,8 +70,8 @@ class ProfMinimapItem : public QGraphicsItem
public:
ProfMinimapItem();
virtual ~ProfMinimapItem();
EasyMinimapItem();
virtual ~EasyMinimapItem();
// Public virtual methods
@ -89,34 +88,34 @@ public:
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items);
}; // END of class ProfMinimapItem.
}; // END of class EasyMinimapItem.
//////////////////////////////////////////////////////////////////////////
class ProfIdAction : public QAction
class EasyIdAction : public QAction
{
Q_OBJECT
private:
typedef QAction Parent;
typedef ProfIdAction This;
typedef EasyIdAction This;
::profiler::thread_id_t m_id;
public:
ProfIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
EasyIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
{
connect(this, &Parent::triggered, this, &This::onToggle);
}
ProfIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
EasyIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
{
connect(this, &Parent::triggered, this, &This::onToggle);
}
virtual ~ProfIdAction()
virtual ~EasyIdAction()
{
}
@ -134,14 +133,14 @@ signals:
//////////////////////////////////////////////////////////////////////////
class ProfGraphicsScrollbar : public QGraphicsView
class EasyGraphicsScrollbar : public QGraphicsView
{
Q_OBJECT
private:
typedef QGraphicsView Parent;
typedef ProfGraphicsScrollbar This;
typedef EasyGraphicsScrollbar This;
qreal m_minimumValue;
qreal m_maximumValue;
@ -149,15 +148,15 @@ private:
qreal m_windowScale;
QPoint m_mousePressPos;
Qt::MouseButtons m_mouseButtons;
ProfGraphicsSliderItem* m_slider;
ProfGraphicsSliderItem* m_chronometerIndicator;
ProfMinimapItem* m_minimap;
EasyGraphicsSliderItem* m_slider;
EasyGraphicsSliderItem* m_chronometerIndicator;
EasyMinimapItem* m_minimap;
bool m_bScrolling;
public:
ProfGraphicsScrollbar(QWidget* _parent = nullptr);
virtual ~ProfGraphicsScrollbar();
EasyGraphicsScrollbar(QWidget* _parent = nullptr);
virtual ~EasyGraphicsScrollbar();
// Public virtual methods
@ -205,8 +204,8 @@ private slots:
void onThreadActionClicked(::profiler::thread_id_t _id);
void onWindowWidthChange(qreal _width);
}; // END of class ProfGraphicsScrollbar.
}; // END of class EasyGraphicsScrollbar.
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__GRAPHICS_SCROLLBAR__H
#endif // EASY__GRAPHICS_SCROLLBAR__H

View File

@ -37,7 +37,7 @@ int main(int argc, char **argv)
auto now = ::std::chrono::duration_cast<std::chrono::seconds>(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1;
srand((unsigned int)now);
ProfMainWindow window;
EasyMainWindow window;
window.show();
return app.exec();

View File

@ -10,7 +10,7 @@
* ----------------- :
* change log : * 2016/06/26 Victor Zarubkin: Initial commit.
* :
* : * 2016/06/27 Victor Zarubkin: Passing blocks number to ProfTreeWidget::setTree().
* : * 2016/06/27 Victor Zarubkin: Passing blocks number to EasyTreeWidget::setTree().
* :
* : * 2016/06/29 Victor Zarubkin: Added menu with tests.
* :
@ -30,29 +30,31 @@
#include <QCoreApplication>
#include <QCloseEvent>
#include <QSettings>
#include <QTextCodec>
#include <QProgressDialog>
#include "main_window.h"
#include "blocks_tree_widget.h"
#include "blocks_graphics_view.h"
#include "globals.h"
#include <QTextCodec>
//////////////////////////////////////////////////////////////////////////
ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graphicsView(nullptr)
EasyMainWindow::EasyMainWindow() : Parent(), m_treeWidget(nullptr), m_graphicsView(nullptr), m_progress(nullptr)
{
setObjectName("ProfilerGUI_MainWindow");
setWindowTitle("easy_profiler reader");
setWindowTitle("EasyProfiler Reader v0.2.0");
setDockNestingEnabled(true);
resize(800, 600);
setStatusBar(new QStatusBar());
auto graphicsView = new ProfGraphicsViewWidget();
auto graphicsView = new EasyGraphicsViewWidget();
m_graphicsView = new QDockWidget("Blocks diagram");
m_graphicsView->setMinimumHeight(50);
m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas);
m_graphicsView->setWidget(graphicsView);
auto treeWidget = new ProfTreeWidget();
auto treeWidget = new EasyTreeWidget();
m_treeWidget = new QDockWidget("Blocks hierarchy");
m_treeWidget->setMinimumHeight(50);
m_treeWidget->setAllowedAreas(Qt::AllDockWidgetAreas);
@ -70,9 +72,6 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph
auto actionExit = new QAction("Exit", nullptr);
connect(actionExit, &QAction::triggered, this, &This::onExitClicked);
auto actionTestView = new QAction("Test viewport", nullptr);
connect(actionTestView, &QAction::triggered, this, &This::onTestViewportClicked);
auto menu = new QMenu("File");
menu->addAction(actionOpen);
menu->addAction(actionReload);
@ -80,10 +79,6 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph
menu->addAction(actionExit);
menuBar()->addMenu(menu);
menu = new QMenu("Tests");
menu->addAction(actionTestView);
menuBar()->addMenu(menu);
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("main");
@ -113,15 +108,27 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph
}
encodingMenu->addAction(action);
connect(action, &QAction::triggered, this, &This::onEncodingChanged);
}
menu->addSeparator();
auto actionBorders = menu->addAction("Draw items' borders");
actionBorders->setCheckable(true);
actionBorders->setChecked(::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders);
connect(actionBorders, &QAction::triggered, this, &This::onDrawBordersChanged);
menuBar()->addMenu(menu);
connect(graphicsView->view(), &ProfGraphicsView::intervalChanged, treeWidget, &ProfTreeWidget::setTreeBlocks);
connect(graphicsView->view(), &EasyGraphicsView::intervalChanged, treeWidget, &EasyTreeWidget::setTreeBlocks);
connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout);
loadSettings();
m_progress = new QProgressDialog("Loading file...", "Cancel", 0, 100, this);
m_progress->setWindowTitle("EasyProfiler");
m_progress->setModal(true);
m_progress->hide();
connect(m_progress, &QProgressDialog::canceled, this, &This::onFileReaderCancel);
if(QCoreApplication::arguments().size() > 1)
{
auto opened_filename = QCoreApplication::arguments().at(1).toStdString();
@ -129,13 +136,14 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph
}
}
ProfMainWindow::~ProfMainWindow()
EasyMainWindow::~EasyMainWindow()
{
delete m_progress;
}
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::onOpenFileClicked(bool)
void EasyMainWindow::onOpenFileClicked(bool)
{
auto filename = QFileDialog::getOpenFileName(this, "Open profiler log", m_lastFile.c_str(), "Profiler Log File (*.prof);;All Files (*.*)");
loadFile(filename.toStdString());
@ -143,85 +151,53 @@ void ProfMainWindow::onOpenFileClicked(bool)
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::loadFile(const std::string& stdfilename)
void EasyMainWindow::loadFile(const std::string& stdfilename)
{
::profiler::SerializedData data;
::profiler::thread_blocks_tree_t prof_blocks;
auto nblocks = fillTreesFromFile(stdfilename.c_str(), data, prof_blocks, true);
m_progress->setValue(0);
m_progress->show();
m_readerTimer.start(20);
m_reader.load(stdfilename);
if (nblocks != 0)
{
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
m_lastFile = stdfilename;
m_serializedData = ::std::move(data);
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
::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);
for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item);
static_cast<ProfGraphicsViewWidget*>(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks);
}
// ::profiler::SerializedData data;
// ::profiler::thread_blocks_tree_t prof_blocks;
// auto nblocks = fillTreesFromFile(stdfilename.c_str(), data, prof_blocks, true);
//
// if (nblocks != 0)
// {
// static_cast<EasyTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
//
// m_lastFile = stdfilename;
// m_serializedData = ::std::move(data);
// ::profiler_gui::EASY_GLOBALS.selected_thread = 0;
// ::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
// ::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::EasyBlock) * nblocks);
// for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item);
//
// static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks);
// }
}
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::onReloadFileClicked(bool)
void EasyMainWindow::onReloadFileClicked(bool)
{
if (m_lastFile.empty())
{
return;
}
::profiler::SerializedData data;
::profiler::thread_blocks_tree_t prof_blocks;
auto nblocks = fillTreesFromFile(m_lastFile.c_str(), data, prof_blocks, true);
if (nblocks != 0)
{
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
m_serializedData = ::std::move(data);
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
::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);
for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item);
static_cast<ProfGraphicsViewWidget*>(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks);
}
loadFile(m_lastFile);
}
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::onExitClicked(bool)
void EasyMainWindow::onExitClicked(bool)
{
close();
}
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::onTestViewportClicked(bool)
{
static_cast<ProfTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
auto view = static_cast<ProfGraphicsViewWidget*>(m_graphicsView->widget())->view();
view->clearSilent();
m_serializedData.clear();
::profiler_gui::EASY_GLOBALS.gui_blocks.clear();
::profiler_gui::EASY_GLOBALS.profiler_blocks.clear();
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
//view->test(18000, 40000000, 2);
view->test(100, 9000, 1);
}
void ProfMainWindow::onEncodingChanged(bool)
void EasyMainWindow::onEncodingChanged(bool)
{
auto _sender = qobject_cast<QAction*>(sender());
auto name = _sender->text();
@ -229,17 +205,22 @@ void ProfMainWindow::onEncodingChanged(bool)
QTextCodec::setCodecForLocale(codec);
}
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::closeEvent(QCloseEvent* close_event)
void EasyMainWindow::onDrawBordersChanged(bool _checked)
{
saveSettings();
QMainWindow::closeEvent(close_event);
::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders = _checked;
}
//////////////////////////////////////////////////////////////////////////
void ProfMainWindow::loadSettings()
void EasyMainWindow::closeEvent(QCloseEvent* close_event)
{
saveSettings();
Parent::closeEvent(close_event);
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow::loadSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("main");
@ -259,7 +240,7 @@ void ProfMainWindow::loadSettings()
settings.endGroup();
}
void ProfMainWindow::saveSettings()
void EasyMainWindow::saveSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("main");
@ -272,3 +253,111 @@ void ProfMainWindow::saveSettings()
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow::onFileReaderTimeout()
{
if (m_reader.done())
{
auto nblocks = m_reader.size();
if (nblocks != 0)
{
static_cast<EasyTreeWidget*>(m_treeWidget->widget())->clearSilent(true);
::profiler::SerializedData data;
::profiler::thread_blocks_tree_t prof_blocks;
::std::string stdfilename;
m_reader.get(data, prof_blocks, stdfilename);
m_lastFile = ::std::move(stdfilename);
m_serializedData = ::std::move(data);
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
::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::EasyBlock) * nblocks);
for (auto& guiblock : ::profiler_gui::EASY_GLOBALS.gui_blocks) ::profiler_gui::set_max(guiblock.tree_item);
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->view()->setTree(::profiler_gui::EASY_GLOBALS.profiler_blocks);
}
m_reader.interrupt();
m_readerTimer.stop();
m_progress->setValue(100);
m_progress->hide();
}
else
{
m_progress->setValue(m_reader.progress());
}
}
void EasyMainWindow::onFileReaderCancel()
{
m_readerTimer.stop();
m_reader.interrupt();
m_progress->hide();
}
//////////////////////////////////////////////////////////////////////////
EasyFileReader::EasyFileReader()
{
}
EasyFileReader::~EasyFileReader()
{
interrupt();
}
bool EasyFileReader::done() const
{
return m_bDone.load();
}
int EasyFileReader::progress() const
{
return m_progress.load();
}
unsigned int EasyFileReader::size() const
{
return m_size.load();
}
void EasyFileReader::load(const ::std::string& _filename)
{
interrupt();
m_filename = _filename;
m_thread = ::std::move(::std::thread([](::std::atomic_bool& isDone, ::std::atomic<unsigned int>& blocks_number, ::std::atomic<int>& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees) {
blocks_number.store(fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, true));
isDone.store(true);
}, ::std::ref(m_bDone), ::std::ref(m_size), ::std::ref(m_progress), m_filename.c_str(), ::std::ref(m_serializedData), ::std::ref(m_blocksTree)));
}
void EasyFileReader::interrupt()
{
m_progress.store(-100);
if (m_thread.joinable())
m_thread.join();
m_bDone.store(false);
m_progress.store(0);
m_size.store(0);
m_serializedData.clear();
m_blocksTree.clear();
}
void EasyFileReader::get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, ::std::string& _filename)
{
if (done())
{
m_serializedData.swap(_data);
m_blocksTree.swap(_tree);
m_filename.swap(_filename);
}
}
//////////////////////////////////////////////////////////////////////////

View File

@ -17,33 +17,67 @@
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
#include <QMainWindow>
#include <string>
#include <thread>
#include <atomic>
#include <QMainWindow>
#include <QTimer>
#include "profiler/reader.h"
//////////////////////////////////////////////////////////////////////////
class ProfTreeWidget;
class ProfGraphicsView;
class QDockWidget;
class ProfMainWindow : public QMainWindow
//////////////////////////////////////////////////////////////////////////
class EasyFileReader final
{
::profiler::SerializedData m_serializedData; ///<
::profiler::thread_blocks_tree_t m_blocksTree; ///<
::std::string m_filename; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic<int> m_progress; ///<
::std::atomic<unsigned int> m_size; ///<
public:
EasyFileReader();
~EasyFileReader();
bool done() const;
int progress() const;
unsigned int size() const;
void load(const ::std::string& _filename);
void interrupt();
void get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, ::std::string& _filename);
}; // END of class EasyFileReader.
//////////////////////////////////////////////////////////////////////////
class EasyMainWindow : public QMainWindow
{
Q_OBJECT
protected:
typedef ProfMainWindow This;
typedef EasyMainWindow This;
typedef QMainWindow Parent;
::std::string m_lastFile;
QDockWidget* m_treeWidget;
QDockWidget* m_graphicsView;
class QProgressDialog* m_progress;
QTimer m_readerTimer;
::profiler::SerializedData m_serializedData;
EasyFileReader m_reader;
public:
ProfMainWindow();
virtual ~ProfMainWindow();
EasyMainWindow();
virtual ~EasyMainWindow();
// Public virtual methods
@ -54,8 +88,10 @@ protected slots:
void onOpenFileClicked(bool);
void onReloadFileClicked(bool);
void onExitClicked(bool);
void onTestViewportClicked(bool);
void onEncodingChanged(bool);
void onDrawBordersChanged(bool);
void onFileReaderTimeout();
void onFileReaderCancel();
private:
@ -66,7 +102,7 @@ private:
void loadSettings();
void saveSettings();
}; // END of class ProfMainWindow.
}; // END of class EasyMainWindow.
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,190 @@
/************************************************************************
* file name : tree_widget_item.cpp
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyTreeWidgetItem.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: Moved sources from blocks_tree_widget.cpp
* : and renamed classes from Prof* to Easy*.
* :
* : *
* ----------------- :
* license : TODO: add license text
************************************************************************/
#include "tree_widget_item.h"
#include "globals.h"
//////////////////////////////////////////////////////////////////////////
EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent)
: Parent(_parent)
, m_block(_treeBlock)
, m_customBGColor(0)
, m_customTextColor(0)
{
}
EasyTreeWidgetItem::~EasyTreeWidgetItem()
{
}
bool EasyTreeWidgetItem::operator < (const Parent& _other) const
{
const auto col = treeWidget()->sortColumn();
switch (col)
{
//case COL_UNKNOWN:
case COL_NAME:
{
if (parent() == nullptr)
return false; // Do not sort topLevelItems by name
return Parent::operator < (_other);
}
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_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();
}
default:
{
// durations min, max, average
return data(col, Qt::UserRole).toULongLong() < _other.data(col, Qt::UserRole).toULongLong();
}
}
return false;
}
const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const
{
return m_block;
}
::profiler::timestamp_t EasyTreeWidgetItem::duration() const
{
if (m_block->node)
return m_block->node->block()->duration();
return data(COL_DURATION, Qt::UserRole).toULongLong();
}
::profiler::timestamp_t EasyTreeWidgetItem::selfDuration() const
{
return data(COL_SELF_DURATION, Qt::UserRole).toULongLong();
}
void EasyTreeWidgetItem::setTimeSmart(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
if (_time < 1e3)
{
setText(_column, QString("%1%2 ns").arg(_prefix).arg(nanosecondsTime));
}
else if (_time < 1e6)
{
setText(_column, QString("%1%2 us").arg(_prefix).arg(double(nanosecondsTime) * 1e-3, 0, 'f', 3));
}
else if (_time < 1e9)
{
setText(_column, QString("%1%2 ms").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'f', 3));
}
else
{
setText(_column, QString("%1%2 s").arg(_prefix).arg(double(nanosecondsTime) * 1e-9, 0, 'f', 3));
}
}
void EasyTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, QString::number(double(nanosecondsTime) * 1e-6, 'g', 9));
}
void EasyTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, QString("%1%2").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'g', 9));
}
void EasyTreeWidgetItem::setBackgroundColor(QRgb _color)
{
m_customBGColor = _color;
}
void EasyTreeWidgetItem::setTextColor(QRgb _color)
{
m_customTextColor = _color;
}
void EasyTreeWidgetItem::colorize(bool _colorize)
{
if (_colorize)
{
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
{
setBackground(i, QColor::fromRgb(m_customBGColor));
setForeground(i, QColor::fromRgb(m_customTextColor));
}
}
else
{
const QBrush nobrush;
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
{
setBackground(i, nobrush);
setForeground(i, nobrush);
}
}
}
void EasyTreeWidgetItem::collapseAll()
{
for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i)
{
static_cast<EasyTreeWidgetItem*>(child(i))->collapseAll();
}
setExpanded(false);
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = false;
}
void EasyTreeWidgetItem::expandAll()
{
for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i)
{
static_cast<EasyTreeWidgetItem*>(child(i))->expandAll();
}
setExpanded(true);
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = true;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,118 @@
/************************************************************************
* file name : tree_widget_item.h
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyTreeWidgetItem
* : for displyaing EasyProfiler blocks tree.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h
* : and renamed classes from Prof* to Easy*.
* :
* : *
* ----------------- :
* license : TODO: add license text
************************************************************************/
#ifndef EASY__TREE_WIDGET_ITEM__H_
#define EASY__TREE_WIDGET_ITEM__H_
#include <stdlib.h>
#include <QTreeWidget>
#include "profiler/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
enum EasyColumnsIndexes
{
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_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_PER_FRAME,
COL_MAX_PER_FRAME,
COL_AVERAGE_PER_FRAME,
COL_NCALLS_PER_FRAME,
COL_MIN_PER_THREAD,
COL_MAX_PER_THREAD,
COL_AVERAGE_PER_THREAD,
COL_NCALLS_PER_THREAD,
COL_MIN_PER_PARENT,
COL_MAX_PER_PARENT,
COL_AVERAGE_PER_PARENT,
COL_NCALLS_PER_PARENT,
COL_COLUMNS_NUMBER
};
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidgetItem : public QTreeWidgetItem
{
typedef QTreeWidgetItem Parent;
typedef EasyTreeWidgetItem This;
const ::profiler::BlocksTree* m_block;
QRgb m_customBGColor;
QRgb m_customTextColor;
public:
using Parent::setBackgroundColor;
using Parent::setTextColor;
EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr);
virtual ~EasyTreeWidgetItem();
bool operator < (const Parent& _other) const override;
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, const QString& _prefix = "");
void setTimeMs(int _column, const ::profiler::timestamp_t& _time);
void setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix);
void setBackgroundColor(QRgb _color);
void setTextColor(QRgb _color);
void colorize(bool _colorize);
void collapseAll();
void expandAll();
}; // END of class EasyTreeWidgetItem.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__TREE_WIDGET_ITEM__H_

View File

@ -0,0 +1,584 @@
/************************************************************************
* file name : tree_widget_loader.h
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyTreeWidgetLoader which aim is
* : to load EasyProfiler blocks hierarchy in separate thread.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp
* : and renamed Prof* to Easy*.
* :
* : *
* ----------------- :
* license : TODO: add license text
************************************************************************/
#include "tree_widget_loader.h"
#include "tree_widget_item.h"
#include "globals.h"
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
//////////////////////////////////////////////////////////////////////////
EasyTreeWidgetLoader::EasyTreeWidgetLoader() : m_bDone(ATOMIC_VAR_INIT(false)), m_bInterrupt(ATOMIC_VAR_INIT(false)), m_progress(ATOMIC_VAR_INIT(0))
{
}
EasyTreeWidgetLoader::~EasyTreeWidgetLoader()
{
interrupt();
}
bool EasyTreeWidgetLoader::done() const
{
return m_bDone.load();
}
void EasyTreeWidgetLoader::setDone()
{
m_bDone.store(true);
//m_progress.store(100);
}
void EasyTreeWidgetLoader::setProgress(int _progress)
{
m_progress.store(_progress);
}
bool EasyTreeWidgetLoader::interrupted() const
{
return m_bInterrupt.load();
}
int EasyTreeWidgetLoader::progress() const
{
return m_progress.load();
}
void EasyTreeWidgetLoader::takeTopLevelItems(ThreadedItems& _output)
{
if (done())
{
_output = ::std::move(m_topLevelItems);
m_topLevelItems.clear();
}
}
void EasyTreeWidgetLoader::takeItems(Items& _output)
{
if (done())
{
_output = ::std::move(m_items);
m_items.clear();
}
}
void EasyTreeWidgetLoader::interrupt()
{
m_bInterrupt.store(true);
if (m_thread.joinable())
m_thread.join();
m_bInterrupt.store(false);
m_bDone.store(false);
m_progress.store(0);
for (auto item : m_topLevelItems)
{
//qDeleteAll(item.second->takeChildren());
delete item.second;
}
m_items.clear();
m_topLevelItems.clear();
}
void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows)
{
interrupt();
m_thread = ::std::move(::std::thread(&FillTreeClass<EasyTreeWidgetLoader>::setTreeInternal1, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), ::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows));
}
void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows)
{
interrupt();
m_thread = ::std::move(::std::thread(&FillTreeClass<EasyTreeWidgetLoader>::setTreeInternal2, ::std::ref(*this), ::std::ref(m_items), ::std::ref(m_topLevelItems), _beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows));
}
//////////////////////////////////////////////////////////////////////////
template <class T>
void FillTreeClass<T>::setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows)
{
_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks
::profiler::timestamp_t finishtime = 0;
for (const auto& threadTree : _blocksTree)
{
const auto node_block = threadTree.second.tree.children.front().node->block();
const auto startTime = node_block->getBegin();
const auto endTime = node_block->getEnd();
if (_beginTime > startTime)
_beginTime = startTime;
if (finishtime < endTime)
finishtime = endTime;
}
//const QSignalBlocker b(this);
int i = 0;
const int total = static_cast<int>(_blocksTree.size());
for (const auto& threadTree : _blocksTree)
{
if (_safelocker.interrupted())
break;
auto& block = threadTree.second.tree;
auto item = new EasyTreeWidgetItem(&block);
if (threadTree.second.thread_name && threadTree.second.thread_name[0] != 0)
{
item->setText(COL_NAME, QString("%1 Thread %2").arg(threadTree.second.thread_name).arg(threadTree.first));
}
else
{
item->setText(COL_NAME, QString("Thread %1").arg(threadTree.first));
}
::profiler::timestamp_t duration = 0;
if (!block.children.empty())
{
duration = block.children.back().node->block()->getEnd() - block.children.front().node->block()->getBegin();
}
item->setTimeSmart(COL_DURATION, duration);
item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND);
item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND);
_items.push_back(item);
// TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now)
::profiler::timestamp_t children_duration = 0;
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 = FillTreeClass<T>::setTreeInternal(_safelocker, _items, _beginTime, block.children, item, nullptr, item, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows);
if (children_items_number > 0)
{
//total_items += children_items_number + 1;
//addTopLevelItem(item);
//m_roots[threadTree.first] = item;
_topLevelItems.emplace_back(threadTree.first, item);
}
else
{
_items.pop_back();
delete item;
}
_safelocker.setProgress((100 * ++i) / total);
}
_safelocker.setDone();
//return total_items;
}
//////////////////////////////////////////////////////////////////////////
auto calculateTotalChildrenNumber(const ::profiler::BlocksTree* _tree) -> decltype(_tree->children.size())
{
auto children_number = _tree->children.size();
for (const auto& child : _tree->children)
children_number += calculateTotalChildrenNumber(&child);
return children_number;
}
template <class T>
void FillTreeClass<T>::setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows)
{
//size_t blocksNumber = 0;
//for (const auto& block : _blocks)
// blocksNumber += calculateTotalChildrenNumber(block.tree);
// //blocksNumber += block.tree->total_children_number;
//m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks
RootsMap threadsMap;
int i = 0, total = static_cast<int>(_blocks.size());
//const QSignalBlocker b(this);
for (const auto& block : _blocks)
{
if (_safelocker.interrupted())
break;
const auto startTime = block.tree->node->block()->getBegin();
const auto endTime = block.tree->node->block()->getEnd();
if (startTime > _right || endTime < _left)
{
_safelocker.setProgress((90 * ++i) / total);
continue;
}
::profiler::timestamp_t duration = 0;
EasyTreeWidgetItem* thread_item = nullptr;
auto thread_item_it = threadsMap.find(block.root->thread_id);
if (thread_item_it != threadsMap.end())
{
thread_item = thread_item_it->second;
}
else
{
thread_item = new EasyTreeWidgetItem(&block.root->tree);
if (block.root->thread_name && block.root->thread_name[0] != 0)
{
thread_item->setText(COL_NAME, QString("%1 Thread %2").arg(block.root->thread_name).arg(block.root->thread_id));
}
else
{
thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id));
}
if (!block.root->tree.children.empty())
{
duration = block.root->tree.children.back().node->block()->getEnd() - block.root->tree.children.front().node->block()->getBegin();
}
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));
}
auto item = new EasyTreeWidgetItem(block.tree, thread_item);
duration = endTime - startTime;
item->setText(COL_NAME, ::profiler_gui::toUnicode(block.tree->node->getName()));
item->setTimeSmart(COL_DURATION, duration);
item->setTimeMs(COL_BEGIN, startTime - _beginTime);
item->setTimeMs(COL_END, endTime - _beginTime);
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_PARENT, "");
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_FRAME, "");
if (block.tree->per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
const auto& per_thread_stats = block.tree->per_thread_stats;
const auto& per_parent_stats = block.tree->per_parent_stats;
const auto& per_frame_stats = block.tree->per_frame_stats;
if (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration);
}
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(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));
if (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number));
if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_THREAD, "");
}
const auto color = block.tree->node->block()->getColor();
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);
auto item_index = static_cast<unsigned int>(_items.size());
_items.push_back(item);
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!block.tree->children.empty())
{
children_items_number = FillTreeClass<T>::setTreeInternal(_safelocker, _items, _beginTime, block.tree->children, item, item, thread_item, _left, _right, _strict, children_duration, _colorizeRows);
if (_safelocker.interrupted())
break;
}
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;
::profiler_gui::EASY_GLOBALS.gui_blocks[block.tree->block_index].tree_item = item_index;
if (_colorizeRows)
{
item->colorize(_colorizeRows);
}
}
else
{
_items.pop_back();
delete item;
}
_safelocker.setProgress((90 * ++i) / total);
}
i = 0;
total = static_cast<int>(threadsMap.size());
for (auto& it : threadsMap)
{
auto item = it.second;
if (item->childCount() > 0)
{
//addTopLevelItem(item);
//m_roots[it.first] = item;
_items.push_back(item);
_topLevelItems.emplace_back(it.first, item);
//++total_items;
}
else
{
delete item;
}
_safelocker.setProgress(90 + (10 * ++i) / total);
}
_safelocker.setDone();
//return total_items;
}
template <class T>
size_t FillTreeClass<T>::setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows)
{
size_t total_items = 0;
for (const auto& child : _children)
{
if (_safelocker.interrupted())
break;
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 EasyTreeWidgetItem(&child, _parent);
item->setText(COL_NAME, ::profiler_gui::toUnicode(child.node->getName()));
item->setTimeSmart(COL_DURATION, duration);
item->setTimeMs(COL_BEGIN, startTime - _beginTime);
item->setTimeMs(COL_END, endTime - _beginTime);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
const auto& per_thread_stats = child.per_thread_stats;
const auto& per_parent_stats = child.per_parent_stats;
const auto& per_frame_stats = child.per_frame_stats;
auto percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_parent->duration()));
auto percentage_sum = static_cast<int>(0.5 + 100. * static_cast<double>(per_parent_stats->total_duration) / static_cast<double>(_parent->duration()));
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)
{
if (_parent != _frame)
{
percentage = duration == 0 ? 0 : static_cast<int>(0.5 + 100. * static_cast<double>(duration) / static_cast<double>(_frame->duration()));
percentage_sum = static_cast<int>(0.5 + 100. * static_cast<double>(per_frame_stats->total_duration) / static_cast<double>(_frame->duration()));
}
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_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 (per_thread_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, per_thread_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, per_thread_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, per_thread_stats->total_duration);
}
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
if (_thread)
{
auto percentage_per_thread = static_cast<int>(0.5 + 100. * static_cast<double>(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 (per_parent_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, per_parent_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, per_parent_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number));
if (per_frame_stats->calls_number > 1 || !::profiler_gui::EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, per_frame_stats->min_duration, "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, per_frame_stats->max_duration, "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_PER_PARENT, "");
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_PARENT, "");
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_THREAD, "");
}
const auto color = child.node->block()->getColor();
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);
auto item_index = static_cast<unsigned int>(_items.size());
_items.push_back(item);
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!child.children.empty())
{
children_items_number = FillTreeClass<T>::setTreeInternal(_safelocker, _items, _beginTime, child.children, item, _frame ? _frame : item, _thread, _left, _right, _strict, children_duration, _colorizeRows);
if (_safelocker.interrupted())
break;
}
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;
::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index].tree_item = item_index;
if (_colorizeRows)
{
item->colorize(_colorizeRows);
}
}
else
{
_items.pop_back();
delete item;
}
}
return total_items;
}
//////////////////////////////////////////////////////////////////////////
template struct FillTreeClass<EasyTreeWidgetLoader>;
template struct FillTreeClass<StubLocker>;
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,90 @@
/************************************************************************
* file name : tree_widget_loader.h
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyTreeWidgetLoader which aim is
* : to load EasyProfiler blocks hierarchy in separate thread.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp
* : and renamed Prof* to Easy*.
* :
* : *
* ----------------- :
* license : TODO: add license text
************************************************************************/
#ifndef EASY__TREE_WIDGET_LOADER__H_
#define EASY__TREE_WIDGET_LOADER__H_
#include <stdlib.h>
#include <vector>
#include <thread>
#include <atomic>
#include "profiler/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidgetItem;
typedef ::std::vector<EasyTreeWidgetItem*> Items;
typedef ::std::vector<::std::pair<::profiler::thread_id_t, EasyTreeWidgetItem*> > ThreadedItems;
typedef ::std::unordered_map<::profiler::thread_id_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap;
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidgetLoader final
{
ThreadedItems m_topLevelItems; ///<
Items m_items; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic_bool m_bInterrupt; ///<
::std::atomic<int> m_progress; ///<
public:
EasyTreeWidgetLoader();
~EasyTreeWidgetLoader();
bool interrupted() const;
int progress() const;
bool done() const;
void takeTopLevelItems(ThreadedItems& _output);
void takeItems(Items& _output);
void interrupt();
void fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows);
void fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows);
void setDone();
void setProgress(int _progress);
}; // END of class EasyTreeWidgetLoader.
//////////////////////////////////////////////////////////////////////////
template <class T>
struct FillTreeClass final
{
static void setTreeInternal1(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, ::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows);
static void setTreeInternal2(T& _safelocker, Items& _items, ThreadedItems& _topLevelItems, const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows);
static size_t setTreeInternal(T& _safelocker, Items& _items, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, EasyTreeWidgetItem* _thread, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows);
};
//////////////////////////////////////////////////////////////////////////
struct StubLocker final
{
void setDone() {}
bool interrupted() const { return false; }
void setProgress(int) {}
};
//////////////////////////////////////////////////////////////////////////
#endif // EASY__TREE_WIDGET_LOADER__H_

View File

@ -1,282 +1,283 @@
//#define FULL_DISABLE_PROFILER
#include "profiler/profiler.h"
#include <chrono>
#include <thread>
#include <vector>
#include <iostream>
#include <condition_variable>
#include "profiler/reader.h"
#include <cstdlib>
#include <math.h>
std::condition_variable cv;
std::mutex cv_m;
int g_i = 0;
int OBJECTS = 500;
int RENDER_SPEPS = 1600;
int MODELLING_STEPS = 1000;
int RESOURCE_LOADING_COUNT = 50;
void localSleep(int magic=200000)
{
//PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
volatile int i = 0;
for (; i < magic; ++i);
}
void loadingResources(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan);
localSleep();
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
void prepareMath(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = i * i;
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
void calcIntersect(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
//int* intarray = new int[OBJECTS * OBJECTS];
int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
{
for (int j = i; j < OBJECTS; ++j)
//intarray[i * OBJECTS + j] = i * j - i / 2 + (OBJECTS - j) * 5;
intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5;
}
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
double multModel(double i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
return i * sin(i) * cos(i);
}
void calcPhys(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2);
calcIntersect();
delete[] intarray;
}
double calcSubbrain(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
return i * i * i - i / 10 + (OBJECTS - i) * 7 ;
}
void calcBrain(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcSubbrain(double(i)) + double(i * 180 / 3);
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
void calculateBehavior(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue);
calcPhys();
calcBrain();
}
void modellingStep(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy);
prepareMath();
calculateBehavior();
}
void prepareRender(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred);
localSleep();
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
int multPhys(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
return i * i * i * i / 100;
}
int calcPhysicForObject(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
return multPhys(i) + i / 3 - (OBJECTS - i) * 15;
}
void calculatePhysics(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
unsigned int* intarray = new unsigned int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcPhysicForObject(i);
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
void frame(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta);
prepareRender();
calculatePhysics();
}
void loadingResourcesThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Resource loading")
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
loadingResources();
PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void modellingThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Modelling")
for (int i = 0; i < RENDER_SPEPS; i++){
modellingStep();
localSleep(300000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void renderThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Render")
for (int i = 0; i < MODELLING_STEPS; i++){
frame();
localSleep(300000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void four()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(37));
}
void five()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
void six()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(42));
}
void three()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
four();
five();
six();
}
void seven()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(147));
}
void two()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(26));
}
void one()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
two();
three();
seven();
}
/*
one
two
three
four
five
six
seven
*/
int main(int argc, char* argv[])
{
if (argc > 1 && argv[1]){
OBJECTS = std::atoi(argv[1]);
}
if (argc > 2 && argv[2]){
RENDER_SPEPS = std::atoi(argv[2]);
}
if (argc > 3 && argv[3]){
MODELLING_STEPS = std::atoi(argv[3]);
}
if (argc > 4 && argv[4]){
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
}
std::cout << "Objects count: " << OBJECTS << std::endl;
std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
auto start = std::chrono::system_clock::now();
PROFILER_ENABLE;
PROFILER_SET_MAIN_THREAD;
//one();
//one();
/**/
std::vector<std::thread> threads;
std::thread render = std::thread(renderThread);
std::thread modelling = std::thread(modellingThread);
for(int i=0; i < 3; i++){
threads.emplace_back(std::thread(loadingResourcesThread));
threads.emplace_back(std::thread(renderThread));
threads.emplace_back(std::thread(modellingThread));
}
{
std::lock_guard<std::mutex> lk(cv_m);
g_i = 1;
}
cv.notify_all();
render.join();
modelling.join();
for(auto& t : threads){
t.join();
}
/**/
auto end = std::chrono::system_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl;
auto blocks_count = profiler::dumpBlocksToFile("test.prof");
std::cout << "Blocks count: " << blocks_count << std::endl;
return 0;
}
//#define FULL_DISABLE_PROFILER
#include "profiler/profiler.h"
#include <chrono>
#include <thread>
#include <vector>
#include <iostream>
#include <condition_variable>
#include "profiler/reader.h"
#include <cstdlib>
#include <math.h>
std::condition_variable cv;
std::mutex cv_m;
int g_i = 0;
int OBJECTS = 500;
int RENDER_SPEPS = 1600;
int MODELLING_STEPS = 1000;
int RESOURCE_LOADING_COUNT = 50;
void localSleep(int magic=200000)
{
//PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
volatile int i = 0;
for (; i < magic; ++i);
}
void loadingResources(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan);
localSleep();
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
void prepareMath(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = i * i;
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
void calcIntersect(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
//int* intarray = new int[OBJECTS * OBJECTS];
int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
{
for (int j = i; j < OBJECTS; ++j)
//intarray[i * OBJECTS + j] = i * j - i / 2 + (OBJECTS - j) * 5;
intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5;
}
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
double multModel(double i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
return i * sin(i) * cos(i);
}
void calcPhys(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2);
calcIntersect();
delete[] intarray;
}
double calcSubbrain(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
return i * i * i - i / 10 + (OBJECTS - i) * 7 ;
}
void calcBrain(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcSubbrain(i) + double(i * 180 / 3);
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
void calculateBehavior(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue);
calcPhys();
calcBrain();
}
void modellingStep(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy);
prepareMath();
calculateBehavior();
}
void prepareRender(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred);
localSleep();
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
int multPhys(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
return i * i * i * i / 100;
}
int calcPhysicForObject(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
return multPhys(i) + i / 3 - (OBJECTS - i) * 15;
}
void calculatePhysics(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
unsigned int* intarray = new unsigned int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcPhysicForObject(i);
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
void frame(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta);
prepareRender();
calculatePhysics();
}
void loadingResourcesThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Resource loading")
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
loadingResources();
PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan);
localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void modellingThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Modelling")
for (int i = 0; i < RENDER_SPEPS; i++){
modellingStep();
localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void renderThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Render")
for (int i = 0; i < MODELLING_STEPS; i++){
frame();
localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void four()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(37));
}
void five()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
void six()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(42));
}
void three()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
four();
five();
six();
}
void seven()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(147));
}
void two()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(26));
}
void one()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
two();
three();
seven();
}
/*
one
two
three
four
five
six
seven
*/
int main(int argc, char* argv[])
{
if (argc > 1 && argv[1]){
OBJECTS = std::atoi(argv[1]);
}
if (argc > 2 && argv[2]){
RENDER_SPEPS = std::atoi(argv[2]);
}
if (argc > 3 && argv[3]){
MODELLING_STEPS = std::atoi(argv[3]);
}
if (argc > 4 && argv[4]){
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
}
std::cout << "Objects count: " << OBJECTS << std::endl;
std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
auto start = std::chrono::system_clock::now();
PROFILER_ENABLE;
PROFILER_SET_MAIN_THREAD;
//one();
//one();
/**/
std::vector<std::thread> threads;
std::thread render = std::thread(renderThread);
std::thread modelling = std::thread(modellingThread);
for(int i=0; i < 3; i++){
threads.emplace_back(std::thread(loadingResourcesThread));
threads.emplace_back(std::thread(renderThread));
threads.emplace_back(std::thread(modellingThread));
}
{
std::lock_guard<std::mutex> lk(cv_m);
g_i = 1;
}
cv.notify_all();
render.join();
modelling.join();
for(auto& t : threads){
t.join();
}
/**/
auto end = std::chrono::system_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl;
auto blocks_count = profiler::dumpBlocksToFile("test.prof");
std::cout << "Blocks count: " << blocks_count << std::endl;
return 0;
}

View File

@ -221,14 +221,16 @@ typedef ::std::map<::profiler::thread_id_t, StatsMap> PerThreadStats;
extern "C"{
unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics)
unsigned int fillTreesFromFile(::std::atomic<int>& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::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);
progress.store(0);
if (!inFile.is_open())
{
progress.store(100);
return 0;
}
@ -239,6 +241,7 @@ extern "C"{
inFile.read((char*)&memory_size, sizeof(uint64_t));
if (memory_size == 0)
{
progress.store(100);
return 0;
}
@ -346,8 +349,19 @@ extern "C"{
current.per_thread_stats = update_statistics(per_thread_statistics, current);
}
if (progress.load() < 0)
break;
progress.store(static_cast<int>(90 * i / memory_size));
}
if (progress.load() < 0)
{
progress.store(100);
serialized_blocks.clear();
threaded_trees.clear();
return 0;
}
PROFILER_BEGIN_BLOCK_GROUPED("Gather statistics for roots", ::profiler::colors::Purple)
if (gather_statistics)
{
@ -382,13 +396,16 @@ extern "C"{
}, ::std::ref(root))));
}
int j = 0, n = static_cast<int>(statistics_threads.size());
for (auto& t : statistics_threads)
{
t.join();
progress.store(90 + (10 * ++j) / n);
}
}
else
{
int j = 0, n = static_cast<int>(threaded_trees.size());
for (auto& it : threaded_trees)
{
auto& root = it.second;
@ -402,11 +419,14 @@ extern "C"{
}
++root.tree.depth;
progress.store(90 + (10 * ++j) / n);
}
}
PROFILER_END_BLOCK
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
progress.store(100);
return blocks_counter;
}
}