From e49b6179ef19991e7b6e6b53e6f021dda9cc58a5 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Tue, 20 Sep 2016 22:57:34 +0300 Subject: [PATCH] New flexible block statuses instead of ENABLED, DISABLED: OFF, ON, FORCE_ON, OFF_RECURSIVE, ON_WITHOUT_CHILDREN, FORCE_ON_WITHOUT_CHILDREN --- include/profiler/profiler.h | 72 ++++---- include/profiler/profiler_aux.h | 31 ++-- include/profiler/serialized_block.h | 6 +- profiler_gui/blocks_tree_widget.cpp | 44 +++-- profiler_gui/blocks_tree_widget.h | 3 +- profiler_gui/descriptors_tree_widget.cpp | 200 +++++++++++++++++----- profiler_gui/descriptors_tree_widget.h | 3 +- profiler_gui/globals_qobjects.h | 2 +- sample/main.cpp | 37 ++--- src/block.cpp | 36 +--- src/event_trace_win.cpp | 2 +- src/profile_manager.cpp | 201 +++++++++++++++-------- src/profile_manager.h | 58 ++++--- 13 files changed, 440 insertions(+), 255 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 6450be4..3571a68 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -42,7 +42,7 @@ along with this program.If not, see . { // some code ... - EASY_BLOCK("Check something", profiler::DISABLED); // Disabled block (There is possibility to enable this block later via GUI) + EASY_BLOCK("Check something", profiler::OFF); // Disabled block (There is possibility to enable this block later via GUI) if(something){ EASY_BLOCK("Calling bar()"); // Block with default color bar(); @@ -53,8 +53,13 @@ along with this program.If not, see . } EASY_END_BLOCK; // End of "Check something" block (Even if "Check something" is disabled, this EASY_END_BLOCK will not end any other block). - EASY_BLOCK("Some another block", profiler::colors::Blue, profiler::DISABLED); // Disabled block with Blue color + EASY_BLOCK("Some another block", profiler::colors::Blue, profiler::ON_WITHOUT_CHILDREN); // Block with Blue color without // some another code... + EASY_BLOCK("Calculate sum"); // This block will not be profiled because it's parent is ON_WITHOUT_CHILDREN + int sum = 0; + for (int i = 0; i < 10; ++i) + sum += i; + EASY_END_BLOCK; // End of "Calculate sum" block } \endcode @@ -83,7 +88,7 @@ Block will be automatically completed by destructor. } void baz(){ - EASY_FUNCTION(profiler::DISABLED); // Disabled block with name="baz" and default color (There is possibility to enable this block later via GUI) + EASY_FUNCTION(profiler::FORCE_ON); // Force enabled block with name="baz" and default color (This block will be profiled even if it's parent is OFF_RECURSIVE) // som code... } \endcode @@ -158,8 +163,10 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION. */ # define EASY_THREAD(name)\ EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\ + ::profiler::ThreadGuard EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__);\ if (EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) == nullptr)\ - EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name); + EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name,\ + EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__)); /** Macro for main thread registration. @@ -295,7 +302,7 @@ Otherwise, no log messages will be printed. ////////////////////////////////////////////////////////////////////////// class ProfileManager; -class ThreadStorage; +struct ThreadStorage; namespace profiler { @@ -323,16 +330,17 @@ namespace profiler { class PROFILER_API BaseBlockDescriptor { friend ::ProfileManager; + friend ::ThreadStorage; protected: - block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors) - int m_line; ///< Line number in the source file - color_t m_color; ///< Color of the block packed into 1-byte structure - block_type_t m_type; ///< Type of the block (See BlockType) - bool m_enabled; ///< If false then blocks with such id() will not be stored by profiler during profile session + block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors) + int m_line; ///< Line number in the source file + color_t m_color; ///< Color of the block packed into 1-byte structure + block_type_t m_type; ///< Type of the block (See BlockType) + EasyBlockStatus m_status; ///< If false then blocks with such id() will not be stored by profiler during profile session - BaseBlockDescriptor(block_id_t _id, bool _enabled, int _line, block_type_t _block_type, color_t _color); + BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color); public: @@ -340,7 +348,7 @@ namespace profiler { inline int line() const { return m_line; } inline color_t color() const { return m_color; } inline block_type_t type() const { return m_type; } - inline bool enabled() const { return m_enabled; } + inline EasyBlockStatus status() const { return m_status; } }; // END of class BaseBlockDescriptor. @@ -381,17 +389,17 @@ namespace profiler { { friend ::ProfileManager; - const char* m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier - const char* m_filename; ///< Source file name where this block is declared - bool* m_pEnable; ///< Pointer to the enable flag in unordered_map - uint16_t m_size; ///< Used memory size - bool m_expired; ///< Is this descriptor expired + const char* m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier + const char* m_filename; ///< Source file name where this block is declared + EasyBlockStatus* m_pStatus; ///< Pointer to the enable flag in unordered_map + uint16_t m_size; ///< Used memory size + bool m_expired; ///< Is this descriptor expired - BlockDescriptor(bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color); + BlockDescriptor(EasyBlockStatus _status, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color); public: - BlockDescriptor(block_id_t _id, bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color); + BlockDescriptor(block_id_t _id, EasyBlockStatus _status, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color); inline const char* name() const { return m_name; @@ -410,8 +418,8 @@ namespace profiler { friend ::ProfileManager; friend ::ThreadStorage; - const char* m_name; - bool m_enabled; + const char* m_name; + EasyBlockStatus m_status; private: @@ -420,7 +428,8 @@ namespace profiler { void finish(); void finish(timestamp_t _time); inline bool finished() const { return m_end >= m_begin; } - inline bool enabled() const { return m_enabled; } + inline EasyBlockStatus status() const { return m_status; } + inline void setStatus(EasyBlockStatus _status) { m_status = _status; } public: @@ -459,6 +468,13 @@ namespace profiler { }; // END of class BlockDescRef. + class PROFILER_API ThreadGuard final { + friend ::ProfileManager; + thread_id_t m_id = 0; + public: + ~ThreadGuard(); + }; + ////////////////////////////////////////////////////////////////////// // Core API // Note: it is better to use macros defined above than a direct calls to API. @@ -472,7 +488,7 @@ namespace profiler { \ingroup profiler */ - PROFILER_API const BaseBlockDescriptor* registerDescription(bool _enabled, const char* _autogenUniqueId, const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color); + PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus _status, const char* _autogenUniqueId, const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color); /** Stores event in the blocks list. @@ -517,7 +533,7 @@ namespace profiler { \ingroup profiler */ - PROFILER_API const char* registerThread(const char* _name); + PROFILER_API const char* registerThread(const char* _name, ThreadGuard&); /** Enable or disable event tracing. @@ -555,15 +571,11 @@ namespace profiler { PROFILER_API const char* getContextSwitchLogFilename(); #endif - PROFILER_API void startListenSignalToCapture(); - PROFILER_API void stopListenSignalToCapture(); + PROFILER_API void startListenSignalToCapture(); + PROFILER_API void stopListenSignalToCapture(); } - inline void setEnabled(::profiler::EasyEnableFlag _isEnable) { - setEnabled(_isEnable == ::profiler::ENABLED); - } - ////////////////////////////////////////////////////////////////////// } // END of namespace profiler. diff --git a/include/profiler/profiler_aux.h b/include/profiler/profiler_aux.h index 18c2d95..be73e77 100644 --- a/include/profiler/profiler_aux.h +++ b/include/profiler/profiler_aux.h @@ -80,10 +80,13 @@ namespace profiler { - enum EasyEnableFlag : uint8_t - { - DISABLED = 0, - ENABLED = 1 + enum EasyBlockStatus : uint8_t { + OFF = 0, ///< The block is OFF + ON = 1, ///< The block is ON (but if it's parent block is off recursively then this block will be off too) + FORCE_ON = ON | 2, ///< The block is ALWAYS ON (even if it's parent has turned off all children) + OFF_RECURSIVE = 4, ///< The block is OFF and all of it's children by call-stack are also OFF. + ON_WITHOUT_CHILDREN = ON | OFF_RECURSIVE, ///< The block is ON but all of it's children are OFF. + FORCE_ON_WITHOUT_CHILDREN = FORCE_ON | OFF_RECURSIVE, ///< The block is ALWAYS ON but all of it's children are OFF. }; struct passthrough_hash final { @@ -126,7 +129,7 @@ namespace profiler { } template - inline color_t extract_color(::profiler::EasyEnableFlag, TArgs...) { + inline color_t extract_color(::profiler::EasyBlockStatus, TArgs...) { return ::profiler::colors::Default; } @@ -148,24 +151,24 @@ namespace profiler { //*********************************************** - inline bool extract_enable_flag() { - return true; + inline EasyBlockStatus extract_enable_flag() { + return ::profiler::ON; } template - inline bool extract_enable_flag(T, ::profiler::EasyEnableFlag _flag, TArgs...) { - return _flag == ::profiler::ENABLED; + inline EasyBlockStatus extract_enable_flag(T, ::profiler::EasyBlockStatus _flag, TArgs...) { + return _flag; } template - inline bool extract_enable_flag(::profiler::EasyEnableFlag _flag, TArgs...) { - return _flag == ::profiler::ENABLED; + inline EasyBlockStatus extract_enable_flag(::profiler::EasyBlockStatus _flag, TArgs...) { + return _flag; } template - inline bool extract_enable_flag(TArgs...) { - static_assert(sizeof...(TArgs) < 2, "No EasyEnableFlag in arguments list for EASY_BLOCK(name, ...)!"); - return true; + inline EasyBlockStatus extract_enable_flag(TArgs...) { + static_assert(sizeof...(TArgs) < 2, "No EasyBlockStatus in arguments list for EASY_BLOCK(name, ...)!"); + return ::profiler::ON; } //*********************************************** diff --git a/include/profiler/serialized_block.h b/include/profiler/serialized_block.h index 9e6f592..4ed0c31 100644 --- a/include/profiler/serialized_block.h +++ b/include/profiler/serialized_block.h @@ -21,8 +21,6 @@ along with this program.If not, see . #include "profiler/profiler.h" -class ThreadStorage; - namespace profiler { ////////////////////////////////////////////////////////////////////////// @@ -69,9 +67,9 @@ namespace profiler { return name() + m_nameLength; } - inline void setEnabled(bool _enabled) + inline void setStatus(EasyBlockStatus _status) { - m_enabled = _enabled; + m_status = _status; } private: diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 89c9313..4e10a2d 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -38,6 +38,7 @@ ************************************************************************/ #include +#include #include #include #include @@ -442,18 +443,24 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event) } } - auto id = item->block().node->id(); - action = menu.addAction("Block enabled"); - action->setCheckable(true); - action->setChecked(easyDescriptor(id).enabled()); - action->setData(id); - connect(action, &QAction::triggered, this, &This::onBlockEnableDisable); + const auto& desc = easyDescriptor(item->block().node->id()); + auto submenu = menu.addMenu("Block status"); - if (action->isChecked()) { - auto f = action->font(); - f.setBold(true); - action->setFont(f); - } +#define ADD_STATUS_ACTION(NameValue, StatusValue)\ + action = submenu->addAction(NameValue);\ + action->setCheckable(true);\ + action->setChecked(desc.status() == StatusValue);\ + action->setData(static_cast(StatusValue));\ + connect(action, &QAction::triggered, this, &This::onBlockStatusChangeClicked) + + ADD_STATUS_ACTION("Off", ::profiler::OFF); + ADD_STATUS_ACTION("On", ::profiler::ON); + ADD_STATUS_ACTION("Force-On", ::profiler::FORCE_ON); + ADD_STATUS_ACTION("Off-recursive", ::profiler::OFF_RECURSIVE); + ADD_STATUS_ACTION("On-without-children", ::profiler::ON_WITHOUT_CHILDREN); + ADD_STATUS_ACTION("Force-On-without-children", ::profiler::FORCE_ON_WITHOUT_CHILDREN); + +#undef ADD_STATUS_ACTION } menu.addSeparator(); @@ -579,14 +586,21 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool) ////////////////////////////////////////////////////////////////////////// -void EasyTreeWidget::onBlockEnableDisable(bool _checked) +void EasyTreeWidget::onBlockStatusChangeClicked(bool _checked) { + if (!_checked) + return; + + auto item = static_cast(currentItem()); + if (item == nullptr) + return; + auto action = qobject_cast(sender()); if (action != nullptr) { - auto id = action->data().toUInt(); - easyDescriptor(id).setEnabled(_checked); - emit EASY_GLOBALS.events.enableStatusChanged(id, _checked); + auto& desc = easyDescriptor(item->block().node->id()); + desc.setStatus(static_cast<::profiler::EasyBlockStatus>(action->data().toUInt())); + emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status()); } } diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index 187a436..15c68db 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -40,7 +40,6 @@ #define EASY__TREE_WIDGET__H_ #include -#include #include #include "tree_widget_loader.h" #include "profiler/reader.h" @@ -108,7 +107,7 @@ private slots: void onSelectedBlockChange(uint32_t _block_index); - void onBlockEnableDisable(bool _checked); + void onBlockStatusChangeClicked(bool); void resizeColumnsToContents(); diff --git a/profiler_gui/descriptors_tree_widget.cpp b/profiler_gui/descriptors_tree_widget.cpp index 26bb513..a123118 100644 --- a/profiler_gui/descriptors_tree_widget.cpp +++ b/profiler_gui/descriptors_tree_widget.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -63,14 +64,92 @@ enum DescColumns { DESC_COL_FILE_LINE = 0, + DESC_COL_TYPE, DESC_COL_NAME, DESC_COL_STATUS, DESC_COL_COLUMNS_NUMBER }; -const auto ENABLED_COLOR = ::profiler::colors::LightGreen900; -const auto DISABLED_COLOR = ::profiler::colors::DarkRed; +////////////////////////////////////////////////////////////////////////// + +::profiler::EasyBlockStatus nextStatus(::profiler::EasyBlockStatus _status) +{ + switch (_status) + { + case ::profiler::OFF: + return ::profiler::ON; + + case ::profiler::ON: + return ::profiler::FORCE_ON; + + case ::profiler::FORCE_ON: + return ::profiler::OFF_RECURSIVE; + + case ::profiler::OFF_RECURSIVE: + return ::profiler::ON_WITHOUT_CHILDREN; + + case ::profiler::ON_WITHOUT_CHILDREN: + return ::profiler::FORCE_ON_WITHOUT_CHILDREN; + + case ::profiler::FORCE_ON_WITHOUT_CHILDREN: + return ::profiler::OFF; + } + + return ::profiler::OFF; +} + +const char* statusText(::profiler::EasyBlockStatus _status) +{ + switch (_status) + { + case ::profiler::OFF: + return "OFF"; + + case ::profiler::ON: + return "ON"; + + case ::profiler::FORCE_ON: + return "FORCE_ON"; + + case ::profiler::OFF_RECURSIVE: + return "OFF_RECURSIVE"; + + case ::profiler::ON_WITHOUT_CHILDREN: + return "ON_WITHOUT_CHILDREN"; + + case ::profiler::FORCE_ON_WITHOUT_CHILDREN: + return "FORCE_ON_WITHOUT_CHILDREN"; + } + + return ""; +} + +::profiler::color_t statusColor(::profiler::EasyBlockStatus _status) +{ + switch (_status) + { + case ::profiler::OFF: + return ::profiler::colors::Red900; + + case ::profiler::ON: + return ::profiler::colors::LightGreen900; + + case ::profiler::FORCE_ON: + return ::profiler::colors::LightGreen900; + + case ::profiler::OFF_RECURSIVE: + return ::profiler::colors::Red900; + + case ::profiler::ON_WITHOUT_CHILDREN: + return ::profiler::colors::Lime900; + + case ::profiler::FORCE_ON_WITHOUT_CHILDREN: + return ::profiler::colors::Lime900; + } + + return ::profiler::colors::Black; +} ////////////////////////////////////////////////////////////////////////// @@ -117,12 +196,13 @@ EasyDescTreeWidget::EasyDescTreeWidget(QWidget* _parent) auto header_item = new QTreeWidgetItem(); header_item->setText(DESC_COL_FILE_LINE, "File/Line"); + header_item->setText(DESC_COL_TYPE, "Type"); header_item->setText(DESC_COL_NAME, "Name"); header_item->setText(DESC_COL_STATUS, "Status"); setHeaderItem(header_item); connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); - connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::enableStatusChanged, this, &This::onEnableStatusChange); + connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::blockStatusChanged, this, &This::onBlockStatusChange); connect(this, &Parent::itemExpanded, this, &This::onItemExpand); connect(this, &Parent::itemDoubleClicked, this, &This::onDoubleClick); connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange); @@ -155,12 +235,40 @@ void EasyDescTreeWidget::contextMenuEvent(QContextMenuEvent* _event) auto header_item = headerItem(); for (int i = 0; i < DESC_COL_STATUS; ++i) { - action = new QAction(header_item->text(i), nullptr); + if (i == DESC_COL_TYPE) + continue; + + action = submenu->addAction(header_item->text(i)); + action->setData(i); action->setCheckable(true); if (i == m_searchColumn) action->setChecked(true); connect(action, &QAction::triggered, this, &This::onSearchColumnChange); - submenu->addAction(action); + } + + auto item = currentItem(); + if (item != nullptr && item->parent() != nullptr && currentColumn() >= DESC_COL_TYPE) + { + const auto& desc = easyDescriptor(static_cast(item)->desc()); + + menu.addSeparator(); + auto submenu = menu.addMenu("Change status"); + +#define ADD_STATUS_ACTION(NameValue, StatusValue)\ + action = submenu->addAction(NameValue);\ + action->setCheckable(true);\ + action->setChecked(desc.status() == StatusValue);\ + action->setData(static_cast(StatusValue));\ + connect(action, &QAction::triggered, this, &This::onBlockStatusChangeClicked) + + ADD_STATUS_ACTION("Off", ::profiler::OFF); + ADD_STATUS_ACTION("On", ::profiler::ON); + ADD_STATUS_ACTION("Force-On", ::profiler::FORCE_ON); + ADD_STATUS_ACTION("Off-recursive", ::profiler::OFF_RECURSIVE); + ADD_STATUS_ACTION("On-without-children", ::profiler::ON_WITHOUT_CHILDREN); + ADD_STATUS_ACTION("Force-On-without-children", ::profiler::FORCE_ON_WITHOUT_CHILDREN); + +#undef ADD_STATUS_ACTION } menu.exec(QCursor::pos()); @@ -254,6 +362,8 @@ void EasyDescTreeWidget::build() { p.item = new QTreeWidgetItem(); p.item->setText(DESC_COL_FILE_LINE, desc->file()); + p.item->setText(DESC_COL_TYPE, "F"); + p.item->setToolTip(DESC_COL_TYPE, "File"); } auto it = p.children.find(desc->line()); @@ -264,21 +374,20 @@ void EasyDescTreeWidget::build() item->setData(DESC_COL_FILE_LINE, Qt::UserRole, desc->line()); item->setText(DESC_COL_NAME, desc->name()); - item->setFont(DESC_COL_STATUS, f); - - QBrush brush; - if (desc->enabled()) + if (desc->type() == ::profiler::BLOCK_TYPE_BLOCK) { - item->setText(DESC_COL_STATUS, "ON"); - brush.setColor(QColor::fromRgba(ENABLED_COLOR)); + item->setText(DESC_COL_TYPE, "B"); + item->setToolTip(DESC_COL_TYPE, "Block"); } else { - item->setText(DESC_COL_STATUS, "OFF"); - brush.setColor(QColor::fromRgba(DISABLED_COLOR)); + item->setText(DESC_COL_TYPE, "E"); + item->setToolTip(DESC_COL_TYPE, "Event"); } - item->setForeground(DESC_COL_STATUS, brush); + item->setFont(DESC_COL_STATUS, f); + item->setText(DESC_COL_STATUS, statusText(desc->status())); + item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc->status()))); m_items[id] = item; } @@ -312,29 +421,17 @@ void EasyDescTreeWidget::onItemExpand(QTreeWidgetItem*) void EasyDescTreeWidget::onDoubleClick(QTreeWidgetItem* _item, int _column) { - if (_column >= DESC_COL_NAME && _item->parent() != nullptr) + if (_column >= DESC_COL_TYPE && _item->parent() != nullptr) { auto item = static_cast(_item); auto& desc = easyDescriptor(item->desc()); + desc.setStatus(nextStatus(desc.status())); - QBrush brush; - if (desc.enabled()) - { - desc.setEnabled(false); - item->setText(DESC_COL_STATUS, "OFF"); - brush.setColor(QColor::fromRgba(DISABLED_COLOR)); - } - else - { - desc.setEnabled(true); - item->setText(DESC_COL_STATUS, "ON"); - brush.setColor(QColor::fromRgba(ENABLED_COLOR)); - } - - item->setForeground(DESC_COL_STATUS, brush); + item->setText(DESC_COL_STATUS, statusText(desc.status())); + item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status()))); m_bLocked = true; - emit EASY_GLOBALS.events.enableStatusChanged(item->desc(), desc.enabled()); + emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status()); m_bLocked = false; } } @@ -361,7 +458,30 @@ void EasyDescTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidget ////////////////////////////////////////////////////////////////////////// -void EasyDescTreeWidget::onEnableStatusChange(::profiler::block_id_t _id, bool _enabled) +void EasyDescTreeWidget::onBlockStatusChangeClicked(bool _checked) +{ + if (!_checked) + return; + + auto item = currentItem(); + if (item == nullptr || item->parent() == nullptr) + return; + + auto action = qobject_cast(sender()); + if (action != nullptr) + { + auto& desc = easyDescriptor(static_cast(item)->desc()); + desc.setStatus(static_cast<::profiler::EasyBlockStatus>(action->data().toUInt())); + item->setText(DESC_COL_STATUS, statusText(desc.status())); + item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status()))); + + m_bLocked = true; + emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status()); + m_bLocked = false; + } +} + +void EasyDescTreeWidget::onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status) { if (m_bLocked) return; @@ -370,19 +490,9 @@ void EasyDescTreeWidget::onEnableStatusChange(::profiler::block_id_t _id, bool _ if (item == nullptr) return; - QBrush brush; - if (_enabled) - { - item->setText(DESC_COL_STATUS, "ON"); - brush.setColor(QColor::fromRgba(ENABLED_COLOR)); - } - else - { - item->setText(DESC_COL_STATUS, "OFF"); - brush.setColor(QColor::fromRgba(DISABLED_COLOR)); - } - - item->setForeground(DESC_COL_STATUS, brush); + auto& desc = easyDescriptor(item->desc()); + item->setText(DESC_COL_STATUS, statusText(desc.status())); + item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status()))); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/descriptors_tree_widget.h b/profiler_gui/descriptors_tree_widget.h index 9ff1adc..671d8e3 100644 --- a/profiler_gui/descriptors_tree_widget.h +++ b/profiler_gui/descriptors_tree_widget.h @@ -107,11 +107,12 @@ public slots: private slots: void onSearchColumnChange(bool); + void onBlockStatusChangeClicked(bool); void onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _prev); void onItemExpand(QTreeWidgetItem* _item); void onDoubleClick(QTreeWidgetItem* _item, int _column); void onSelectedBlockChange(uint32_t _block_index); - void onEnableStatusChange(::profiler::block_id_t _id, bool _enabled); + void onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status); void resizeColumnsToContents(); private: diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index fd4fc72..2629ff6 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -52,7 +52,7 @@ namespace profiler_gui { void itemsExpandStateChanged(); void drawBordersChanged(); void chronoPositionChanged(); - void enableStatusChanged(::profiler::block_id_t _id, bool _enabled); + void blockStatusChanged(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status); }; // END of class EasyGlobalSignals. diff --git a/sample/main.cpp b/sample/main.cpp index 7235d64..0b7848b 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -14,8 +14,8 @@ std::mutex cv_m; int g_i = 0; int OBJECTS = 500; -int RENDER_STEPS = 1600; -int MODELLING_STEPS = 1000; +int MODELLING_STEPS = 1500; +int RENDER_STEPS = 1500; int RESOURCE_LOADING_COUNT = 50; void localSleep(int magic=200000) @@ -105,7 +105,7 @@ void prepareRender(){ int multPhys(int i) { - EASY_FUNCTION(profiler::colors::Red700, profiler::DISABLED); + EASY_FUNCTION(profiler::colors::Red700, profiler::ON); return i * i * i * i / 100; } @@ -146,7 +146,7 @@ void modellingThread(){ //std::unique_lock lk(cv_m); //cv.wait(lk, []{return g_i == 1; }); EASY_THREAD("Modelling"); - for (int i = 0; i < RENDER_STEPS; i++){ + for (int i = 0; i < MODELLING_STEPS; i++){ modellingStep(); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); @@ -157,7 +157,7 @@ void renderThread(){ //std::unique_lock lk(cv_m); //cv.wait(lk, []{return g_i == 1; }); EASY_THREAD("Render"); - for (int i = 0; i < MODELLING_STEPS; i++){ + for (int i = 0; i < RENDER_STEPS; i++){ frame(); localSleep(1200000); //std::this_thread::sleep_for(std::chrono::milliseconds(20)); @@ -172,34 +172,27 @@ int main(int argc, char* argv[]) OBJECTS = std::atoi(argv[1]); } if (argc > 2 && argv[2]){ - RENDER_STEPS = std::atoi(argv[2]); + MODELLING_STEPS = std::atoi(argv[2]); } if (argc > 3 && argv[3]){ - MODELLING_STEPS = std::atoi(argv[3]); + RENDER_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_STEPS << std::endl; - std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl; + std::cout << "Render steps: " << MODELLING_STEPS << std::endl; + std::cout << "Modelling steps: " << RENDER_STEPS << std::endl; std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; auto start = std::chrono::system_clock::now(); EASY_PROFILER_ENABLE; EASY_MAIN_THREAD; profiler::startListenSignalToCapture(); - //one(); - //one(); - /**/ + std::vector threads; - - std::thread render = std::thread(renderThread); - std::thread modelling = std::thread(modellingThread); - - - for(int i=0; i < 3; i++){ + 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)); @@ -210,16 +203,10 @@ int main(int argc, char* argv[]) cv_m.unlock(); cv.notify_all(); - for (int i = 0; i < RENDER_STEPS; ++i) { - modellingStep(); - localSleep(1200000); - } + modellingThread(); - render.join(); - modelling.join(); for(auto& t : threads) t.join(); - /**/ auto end = std::chrono::system_clock::now(); auto elapsed = diff --git a/src/block.cpp b/src/block.cpp index 4f43f01..741ba8f 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -23,35 +23,11 @@ * : You should have received a copy of the GNU General Public License * : along with this program.If not, see . ************************************************************************/ -#include "profiler/profiler.h" + #include "profile_manager.h" -#include -#include -#include using namespace profiler; -#ifdef _WIN32 -decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; })(); -#endif - -inline timestamp_t getCurrentTime() -{ -#ifdef _WIN32 - //see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx - LARGE_INTEGER elapsedMicroseconds; - if (!QueryPerformanceCounter(&elapsedMicroseconds)) - return 0; - //elapsedMicroseconds.QuadPart *= 1000000000LL; - //elapsedMicroseconds.QuadPart /= CPU_FREQUENCY; - return (timestamp_t)elapsedMicroseconds.QuadPart; -#else - std::chrono::time_point time_point; - time_point = std::chrono::time_point_cast(std::chrono::system_clock::now()); - return time_point.time_since_epoch().count(); -#endif -} - BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id) : m_begin(_begin_time) , m_end(0) @@ -63,23 +39,25 @@ BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id) Block::Block(Block&& that) : BaseBlockData(that.m_begin, that.m_id) , m_name(that.m_name) - , m_enabled(that.m_enabled) + , m_status(that.m_status) { m_end = that.m_end; } Block::Block(const BaseBlockDescriptor& _descriptor, const char* _runtimeName) - : BaseBlockData(_descriptor.enabled() ? getCurrentTime() : 1ULL, _descriptor.id()) + : BaseBlockData(1ULL, _descriptor.id()) , m_name(_runtimeName) - , m_enabled(_descriptor.enabled()) + , m_status(_descriptor.status()) { + } Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, const char* _runtimeName) : BaseBlockData(_begin_time, _descriptor_id) , m_name(_runtimeName) - , m_enabled(true) + , m_status(::profiler::ON) { + } void Block::start() diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index 9352ae8..9eadf0e 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -103,7 +103,7 @@ namespace profiler { if (sizeof(CSwitch) != _traceEvent->UserDataLength) return; - EASY_FUNCTION(::profiler::colors::White, ::profiler::DISABLED); + EASY_FUNCTION(::profiler::colors::White, ::profiler::OFF); auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart); diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index b4a7379..db6c98b 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -23,41 +23,38 @@ * : You should have received a copy of the GNU General Public License * : along with this program.If not, see . ************************************************************************/ + +#include +#include #include "profile_manager.h" #include "profiler/serialized_block.h" #include "profiler/easy_net.h" - #include "profiler/easy_socket.h" #include "event_trace_win.h" -#include -#include -#include - -#include -#include "profiler/serialized_block.h" -#include "profile_manager.h" -#include "event_trace_win.h" - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// using namespace profiler; -#ifdef _WIN32 -extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; -#endif - -extern timestamp_t getCurrentTime(); +const uint8_t FORCE_ON_FLAG = profiler::FORCE_ON & ~profiler::ON; //auto& MANAGER = ProfileManager::instance(); #define MANAGER ProfileManager::instance() +EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr; + +#ifdef _WIN32 +decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; })(); +#endif + +////////////////////////////////////////////////////////////////////////// + extern "C" { - PROFILER_API const BaseBlockDescriptor* registerDescription(bool _enabled, const char* _autogenUniqueId, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) + PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus _status, const char* _autogenUniqueId, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) { - return MANAGER.addBlockDescriptor(_enabled, _autogenUniqueId, _name, _filename, _line, _block_type, _color); + return MANAGER.addBlockDescriptor(_status, _autogenUniqueId, _name, _filename, _line, _block_type, _color); } PROFILER_API void endBlock() @@ -85,9 +82,9 @@ extern "C" { return MANAGER.dumpBlocksToFile(filename); } - PROFILER_API const char* registerThread(const char* name)//, const char* filename, const char* _funcname, int line) + PROFILER_API const char* registerThread(const char* name, ThreadGuard& threadGuard) { - return MANAGER.registerThread(name);// , filename, _funcname, line); + return MANAGER.registerThread(name, threadGuard); } PROFILER_API void setEventTracingEnabled(bool _isEnable) @@ -138,31 +135,31 @@ SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) ////////////////////////////////////////////////////////////////////////// -BaseBlockDescriptor::BaseBlockDescriptor(block_id_t _id, bool _enabled, int _line, block_type_t _block_type, color_t _color) +BaseBlockDescriptor::BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color) : m_id(_id) , m_line(_line) , m_type(_block_type) , m_color(_color) - , m_enabled(_enabled) + , m_status(_status) { } -BlockDescriptor::BlockDescriptor(block_id_t _id, bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) - : BaseBlockDescriptor(_id, _enabled, _line, _block_type, _color) +BlockDescriptor::BlockDescriptor(block_id_t _id, EasyBlockStatus _status, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) + : BaseBlockDescriptor(_id, _status, _line, _block_type, _color) , m_name(_name) , m_filename(_filename) - , m_pEnable(nullptr) + , m_pStatus(nullptr) , m_size(static_cast(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2)) , m_expired(false) { } -BlockDescriptor::BlockDescriptor(bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) - : BaseBlockDescriptor(0, _enabled, _line, _block_type, _color) +BlockDescriptor::BlockDescriptor(EasyBlockStatus _status, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) + : BaseBlockDescriptor(0, _status, _line, _block_type, _color) , m_name(_name) , m_filename(_filename) - , m_pEnable(nullptr) + , m_pStatus(nullptr) , m_size(static_cast(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2)) , m_expired(false) { @@ -178,14 +175,14 @@ BlockDescRef::~BlockDescRef() void ThreadStorage::storeBlock(const profiler::Block& block) { #if EASY_MEASURE_STORAGE_EXPAND != 0 - static const auto desc = MANAGER.addBlockDescriptor(EASY_STORAGE_EXPAND_ENABLED, EASY_UNIQUE_LINE_ID, "EasyProfiler.ExpandStorage", __FILE__, __LINE__, profiler::BLOCK_TYPE_BLOCK, profiler::colors::White); + static const auto desc = MANAGER.addBlockDescriptor(EASY_STORAGE_EXPAND_ENABLED ? profiler::ON : profiler::OFF, EASY_UNIQUE_LINE_ID, "EasyProfiler.ExpandStorage", __FILE__, __LINE__, profiler::BLOCK_TYPE_BLOCK, profiler::colors::White); #endif auto name_length = static_cast(strlen(block.name())); auto size = static_cast(sizeof(BaseBlockData) + name_length + 1); #if EASY_MEASURE_STORAGE_EXPAND != 0 - const bool expanded = desc->enabled() && blocks.closedList.need_expand(size); + const bool expanded = (desc->m_status & profiler::ON) && blocks.closedList.need_expand(size); profiler::Block b(0ULL, desc->id(), ""); if (expanded) b.start(); #endif @@ -228,7 +225,17 @@ void ThreadStorage::clearClosed() ////////////////////////////////////////////////////////////////////////// -EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr; +ThreadGuard::~ThreadGuard() +{ + if (m_id != 0 && THREAD_STORAGE != nullptr && THREAD_STORAGE->id == m_id) + { + //printf("%s Thread expired!\n", THREAD_STORAGE->name.c_str()); + THREAD_STORAGE->expired.store(true, std::memory_order_release); + THREAD_STORAGE = nullptr; + } +} + +////////////////////////////////////////////////////////////////////////// ProfileManager::ProfileManager() { @@ -239,16 +246,16 @@ ProfileManager::ProfileManager() ProfileManager::~ProfileManager() { - - stopListenSignalToCapture(); - if(m_listenThread.joinable()){ - m_listenThread.join(); - } - for (auto desc : m_descriptors) - { - if (desc != nullptr) - delete desc; - } + stopListenSignalToCapture(); + + if (m_listenThread.joinable()) + m_listenThread.join(); + + for (auto desc : m_descriptors) + { + if (desc != nullptr) + delete desc; + } } ProfileManager& ProfileManager::instance() @@ -282,15 +289,21 @@ ThreadStorage* ProfileManager::_findThreadStorage(profiler::thread_id_t _thread_ void ProfileManager::storeBlock(const profiler::BaseBlockDescriptor& _desc, const char* _runtimeName) { - if (!m_isEnabled.load(std::memory_order_acquire) || !_desc.enabled()) + if (!m_isEnabled.load(std::memory_order_acquire) || !(_desc.m_status & profiler::ON)) return; - profiler::Block b(_desc, _runtimeName); - b.finish(b.begin()); - if (THREAD_STORAGE == nullptr) THREAD_STORAGE = &threadStorage(getCurrentThreadId()); +#if EASY_ENABLE_BLOCK_STATUS != 0 + if (!THREAD_STORAGE->allowChildren) + return; +#endif + + profiler::Block b(_desc, _runtimeName); + b.start(); + b.m_end = b.m_begin; + THREAD_STORAGE->storeBlock(b); } @@ -302,6 +315,26 @@ void ProfileManager::beginBlock(Block& _block) if (THREAD_STORAGE == nullptr) THREAD_STORAGE = &threadStorage(getCurrentThreadId()); +#if EASY_ENABLE_BLOCK_STATUS != 0 + if (THREAD_STORAGE->allowChildren) + { +#endif + if (_block.m_status & profiler::ON) + _block.start(); +#if EASY_ENABLE_BLOCK_STATUS != 0 + THREAD_STORAGE->allowChildren = !(_block.m_status & profiler::OFF_RECURSIVE); + } + else if (_block.m_status & FORCE_ON_FLAG) + { + _block.start(); + _block.m_status = profiler::FORCE_ON_WITHOUT_CHILDREN; + } + else + { + _block.m_status = profiler::OFF_RECURSIVE; + } +#endif + THREAD_STORAGE->blocks.openedList.emplace(_block); } @@ -334,14 +367,22 @@ void ProfileManager::endBlock() return; Block& lastBlock = THREAD_STORAGE->blocks.openedList.top(); - if (lastBlock.enabled()) + if (lastBlock.m_status & profiler::ON) { if (!lastBlock.finished()) lastBlock.finish(); THREAD_STORAGE->storeBlock(lastBlock); } + else + { + lastBlock.m_end = lastBlock.m_begin; // this is to restrict endBlock() call inside ~Block() + } THREAD_STORAGE->blocks.openedList.pop(); + +#if EASY_ENABLE_BLOCK_STATUS != 0 + THREAD_STORAGE->allowChildren = THREAD_STORAGE->blocks.openedList.empty() || !(lastBlock.m_status & profiler::OFF_RECURSIVE); +#endif } void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime, bool _lockSpin) @@ -389,8 +430,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream) if (wasEnabled) ::profiler::setEnabled(false); - //TODO remove it - std::this_thread::sleep_for(std::chrono::milliseconds(20)); + // This is to make sure that no new descriptors or new threads will be // added until we finish sending data. guard_lock_t lock1(m_storedSpin); @@ -398,6 +438,12 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream) // This is the only place using both spins, so no dead-lock will occur + // Wait for some time to be sure that all operations which began before setEnabled(false) will be finished. + // This is much better than inserting spin-lock or atomic variable check into each store operation. + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + // TODO: think about better solution because this one is not 100% safe... + + #ifndef _WIN32 if (eventTracingEnabled) { @@ -416,15 +462,24 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream) } #endif - // Calculate used memory total size and total blocks number uint64_t usedMemorySize = 0; uint32_t blocks_number = 0; - for (const auto& thread_storage : m_threads) + for (auto it = m_threads.begin(), end = m_threads.end(); it != end;) { - const auto& t = thread_storage.second; + const auto& t = it->second; + const uint32_t num = static_cast(t.blocks.closedList.size()) + static_cast(t.sync.closedList.size()); + + if (t.expired.load(std::memory_order_acquire) && num == 0) { + // Thread has been finished and contains no profiled information. + // Remove it now. + m_threads.erase(it++); + continue; + } + usedMemorySize += t.blocks.usedMemorySize + t.sync.usedMemorySize; - blocks_number += static_cast(t.blocks.closedList.size()) + static_cast(t.sync.closedList.size()); + blocks_number += num; + ++it; } // Write CPU frequency to let GUI calculate real time value from CPU clocks @@ -461,11 +516,11 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream) } // Write blocks and context switch events for each thread - for (auto& thread_storage : m_threads) + for (auto it = m_threads.begin(), end = m_threads.end(); it != end;) { - auto& t = thread_storage.second; + auto& t = it->second; - _outputStream.write(thread_storage.first); + _outputStream.write(it->first); const auto name_size = static_cast(t.name.size() + 1); _outputStream.write(name_size); @@ -482,6 +537,11 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream) t.clearClosed(); t.blocks.openedList.clear(); t.sync.openedList.clear(); + + if (t.expired.load(std::memory_order_acquire)) + m_threads.erase(it++); // Remove expired thread after writing all profiled information + else + ++it; } // Remove all expired block descriptors (descriptor may become expired if it's .dll/.so have been unloaded during application execution) @@ -512,15 +572,22 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* _filename) return blocksNumber; } -const char* ProfileManager::registerThread(const char* name) +const char* ProfileManager::registerThread(const char* name, ThreadGuard& threadGuard) { - if (THREAD_STORAGE == nullptr) + const bool isNewThread = THREAD_STORAGE == nullptr; + if (isNewThread) { - THREAD_STORAGE = &threadStorage(getCurrentThreadId()); + const auto id = getCurrentThreadId(); + THREAD_STORAGE = &threadStorage(id); + threadGuard.m_id = THREAD_STORAGE->id = id; } if (!THREAD_STORAGE->named) { + if (!isNewThread) { + threadGuard.m_id = THREAD_STORAGE->id = getCurrentThreadId(); + } + THREAD_STORAGE->named = true; THREAD_STORAGE->name = name; } @@ -528,7 +595,7 @@ const char* ProfileManager::registerThread(const char* name) return THREAD_STORAGE->name.c_str(); } -void ProfileManager::setBlockEnabled(profiler::block_id_t _id, const profiler::hashed_stdstring& _key, bool _enabled) +void ProfileManager::setBlockStatus(block_id_t _id, const hashed_stdstring& _key, EasyBlockStatus _status) { guard_lock_t lock(m_storedSpin); @@ -537,16 +604,16 @@ void ProfileManager::setBlockEnabled(profiler::block_id_t _id, const profiler::h { lock.unlock(); - *desc->m_pEnable = _enabled; - desc->m_enabled = _enabled; // TODO: possible concurrent access, atomic may be needed + *desc->m_pStatus = _status; + desc->m_status = _status; // TODO: possible concurrent access, atomic may be needed } else { #ifdef _WIN32 blocks_enable_status_t::key_type key(_key.c_str(), _key.size(), _key.hcode()); - m_blocksEnableStatus[key] = _enabled; + m_blocksEnableStatus[key] = _status; #else - m_blocksEnableStatus[_key] = _enabled; + m_blocksEnableStatus[_key] = _status; #endif } } @@ -572,6 +639,7 @@ void ProfileManager::stopListenSignalToCapture() void ProfileManager::startListen() { + EASY_THREAD("EasyProfiler.Listen"); EasySocket socket; profiler::net::Message replyMessage(profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING); @@ -583,9 +651,9 @@ void ProfileManager::startListen() bool hasConnect = false; socket.listen(); - socket.accept(); + EASY_EVENT("ClientConnected", profiler::colors::White, profiler::OFF); hasConnect = true; printf("Client Accepted!\n"); @@ -596,7 +664,6 @@ void ProfileManager::startListen() while (hasConnect && !m_stopListen.load()) { - char buffer[256] = {}; bytes = socket.receive(buffer, 255); @@ -616,7 +683,8 @@ void ProfileManager::startListen() case profiler::net::MESSAGE_TYPE_REQUEST_START_CAPTURE: { printf("RECEIVED MESSAGE_TYPE_REQUEST_START_CAPTURE\n"); - profiler::setEnabled(true); + ProfileManager::setEnabled(true); + EASY_EVENT("StartCapture", profiler::colors::Green, profiler::OFF); replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING; bytes = socket.send(&replyMessage, sizeof(replyMessage)); @@ -626,7 +694,8 @@ void ProfileManager::startListen() case profiler::net::MESSAGE_TYPE_REQUEST_STOP_CAPTURE: { printf("RECEIVED MESSAGE_TYPE_REQUEST_STOP_CAPTURE\n"); - profiler::setEnabled(false); + EASY_EVENT("StopCapture", profiler::colors::Red, profiler::OFF); + ProfileManager::setEnabled(false); replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_PREPARE_BLOCKS; bytes = socket.send(&replyMessage, sizeof(replyMessage)); diff --git a/src/profile_manager.h b/src/profile_manager.h index 5cc10e4..d58ab83 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -20,31 +20,26 @@ along with this program.If not, see . #define EASY_PROFILER____MANAGER____H______ #include "profiler/profiler.h" -#include "profiler/serialized_block.h" - #include "profiler/easy_socket.h" #include "spin_lock.h" #include "outstream.h" #include "hashed_cstr.h" #include -#include #include #include -#include -#include -#include #include #include +//#include ////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #include #else -#include #include #include #include +#include #endif inline uint32_t getCurrentThreadId() @@ -58,6 +53,20 @@ inline uint32_t getCurrentThreadId() #endif } +inline profiler::timestamp_t getCurrentTime() +{ +#ifdef _WIN32 + //see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx + LARGE_INTEGER elapsedMicroseconds; + if (!QueryPerformanceCounter(&elapsedMicroseconds)) + return 0; + return (profiler::timestamp_t)elapsedMicroseconds.QuadPart; +#else + //std::chrono::time_point time_point; + return std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); +#endif +} + namespace profiler { class SerializedBlock; @@ -72,9 +81,10 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// -//#define EASY_ENABLE_ALIGNMENT +#define EASY_ENABLE_BLOCK_STATUS 1 +#define EASY_ENABLE_ALIGNMENT 0 -#ifndef EASY_ENABLE_ALIGNMENT +#if EASY_ENABLE_ALIGNMENT == 0 # define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR # define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE) # define EASY_FREE(MEMPTR) free(MEMPTR) @@ -288,20 +298,24 @@ struct BlocksList final }; -class ThreadStorage final +struct ThreadStorage final { -public: - BlocksList, SIZEOF_CSWITCH * (uint16_t)128U> blocks; BlocksList sync; std::string name; + profiler::thread_id_t id = 0; + std::atomic_bool expired; + bool allowChildren = true; bool named = false; void storeBlock(const profiler::Block& _block); void storeCSwitch(const profiler::Block& _block); void clearClosed(); - ThreadStorage() = default; + ThreadStorage() + { + expired = ATOMIC_VAR_INIT(false); + } }; ////////////////////////////////////////////////////////////////////////// @@ -319,9 +333,9 @@ class ProfileManager final typedef std::vector block_descriptors_t; #ifdef _WIN32 - typedef std::unordered_map blocks_enable_status_t; + typedef std::unordered_map blocks_enable_status_t; #else - typedef std::unordered_map blocks_enable_status_t; + typedef std::unordered_map blocks_enable_status_t; #endif map_of_threads_stacks m_threads; @@ -339,7 +353,7 @@ class ProfileManager final #endif uint32_t dumpBlocksToStream(profiler::OStream& _outputStream); - void setBlockEnabled(profiler::block_id_t _id, const profiler::hashed_stdstring& _key, bool _enabled); + void setBlockStatus(profiler::block_id_t _id, const profiler::hashed_stdstring& _key, profiler::EasyBlockStatus _status); std::thread m_listenThread; bool m_isAlreadyListened = false; @@ -354,9 +368,9 @@ public: ~ProfileManager(); template - const profiler::BaseBlockDescriptor* addBlockDescriptor(bool _enabledByDefault, const char* _autogenUniqueId, TArgs ... _args) + const profiler::BaseBlockDescriptor* addBlockDescriptor(profiler::EasyBlockStatus _defaultStatus, const char* _autogenUniqueId, TArgs ... _args) { - auto desc = new profiler::BlockDescriptor(_enabledByDefault, _args...); + auto desc = new profiler::BlockDescriptor(_defaultStatus, _args...); guard_lock_t lock(m_storedSpin); m_usedMemorySize += desc->m_size; @@ -367,12 +381,12 @@ public: auto it = m_blocksEnableStatus.find(key); if (it != m_blocksEnableStatus.end()) { - desc->m_enabled = it->second; - desc->m_pEnable = &it->second; + desc->m_status = it->second; + desc->m_pStatus = &it->second; } else { - desc->m_pEnable = &m_blocksEnableStatus.emplace(key, desc->enabled()).first->second; + desc->m_pStatus = &m_blocksEnableStatus.emplace(key, desc->status()).first->second; } return desc; @@ -384,7 +398,7 @@ public: void setEnabled(bool isEnable); void setEventTracingEnabled(bool _isEnable); uint32_t dumpBlocksToFile(const char* filename); - const char* registerThread(const char* name);// , const char* filename, const char* _funcname, int line); + const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard); #ifndef _WIN32 void setContextSwitchLogFilename(const char* name)