mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-26 16:11:02 +08:00
New flexible block statuses instead of ENABLED, DISABLED: OFF, ON, FORCE_ON, OFF_RECURSIVE, ON_WITHOUT_CHILDREN, FORCE_ON_WITHOUT_CHILDREN
This commit is contained in:
parent
cd0ef96793
commit
e49b6179ef
@ -42,7 +42,7 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
{
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
}
|
||||
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,6 +330,7 @@ namespace profiler {
|
||||
class PROFILER_API BaseBlockDescriptor
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
friend ::ThreadStorage;
|
||||
|
||||
protected:
|
||||
|
||||
@ -330,9 +338,9 @@ namespace profiler {
|
||||
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
|
||||
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.
|
||||
|
||||
@ -383,15 +391,15 @@ namespace profiler {
|
||||
|
||||
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
|
||||
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;
|
||||
@ -411,7 +419,7 @@ namespace profiler {
|
||||
friend ::ThreadStorage;
|
||||
|
||||
const char* m_name;
|
||||
bool m_enabled;
|
||||
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.
|
||||
|
||||
@ -560,10 +576,6 @@ namespace profiler {
|
||||
|
||||
}
|
||||
|
||||
inline void setEnabled(::profiler::EasyEnableFlag _isEnable) {
|
||||
setEnabled(_isEnable == ::profiler::ENABLED);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
@ -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 <class ... TArgs>
|
||||
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 <class T, class ... TArgs>
|
||||
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 <class ... TArgs>
|
||||
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 <class ... TArgs>
|
||||
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;
|
||||
}
|
||||
|
||||
//***********************************************
|
||||
|
@ -21,8 +21,6 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#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:
|
||||
|
@ -38,6 +38,7 @@
|
||||
************************************************************************/
|
||||
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QHeaderView>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QSignalBlocker>
|
||||
@ -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<quint32>(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<EasyTreeWidgetItem*>(currentItem());
|
||||
if (item == nullptr)
|
||||
return;
|
||||
|
||||
auto action = qobject_cast<QAction*>(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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,6 @@
|
||||
#define EASY__TREE_WIDGET__H_
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <QAction>
|
||||
#include <QTimer>
|
||||
#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();
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QHeaderView>
|
||||
#include <QString>
|
||||
#include <QContextMenuEvent>
|
||||
@ -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<EasyDescWidgetItem*>(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<quint32>(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<EasyDescWidgetItem*>(_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<QAction*>(sender());
|
||||
if (action != nullptr)
|
||||
{
|
||||
auto& desc = easyDescriptor(static_cast<EasyDescWidgetItem*>(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())));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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<std::mutex> 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<std::mutex> 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,33 +172,26 @@ 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<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));
|
||||
@ -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 =
|
||||
|
@ -23,35 +23,11 @@
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
#include "profiler/profiler.h"
|
||||
|
||||
#include "profile_manager.h"
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
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<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
|
||||
time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(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()
|
||||
|
@ -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<CSwitch*>(_traceEvent->UserData);
|
||||
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
|
||||
|
@ -23,41 +23,38 @@
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#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 <thread>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <fstream>
|
||||
#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<uint16_t>(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<uint16_t>(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<uint16_t>(strlen(block.name()));
|
||||
auto size = static_cast<uint16_t>(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,11 +246,11 @@ ProfileManager::ProfileManager()
|
||||
|
||||
ProfileManager::~ProfileManager()
|
||||
{
|
||||
|
||||
stopListenSignalToCapture();
|
||||
if(m_listenThread.joinable()){
|
||||
|
||||
if (m_listenThread.joinable())
|
||||
m_listenThread.join();
|
||||
}
|
||||
|
||||
for (auto desc : m_descriptors)
|
||||
{
|
||||
if (desc != nullptr)
|
||||
@ -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<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(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<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(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<uint16_t>(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));
|
||||
|
@ -20,31 +20,26 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
#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 <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
//#include <list>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <chrono>
|
||||
#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<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
|
||||
return std::chrono::time_point_cast<std::chrono::nanoseconds>(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<std::reference_wrapper<profiler::Block>, SIZEOF_CSWITCH * (uint16_t)128U> blocks;
|
||||
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> 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<profiler::BlockDescriptor*> block_descriptors_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef std::unordered_map<profiler::hashed_cstr, bool> blocks_enable_status_t;
|
||||
typedef std::unordered_map<profiler::hashed_cstr, profiler::EasyBlockStatus> blocks_enable_status_t;
|
||||
#else
|
||||
typedef std::unordered_map<profiler::hashed_stdstring, bool> blocks_enable_status_t;
|
||||
typedef std::unordered_map<profiler::hashed_stdstring, profiler::EasyBlockStatus> 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 <class ... TArgs>
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user