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 ...
|
// 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){
|
if(something){
|
||||||
EASY_BLOCK("Calling bar()"); // Block with default color
|
EASY_BLOCK("Calling bar()"); // Block with default color
|
||||||
bar();
|
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_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...
|
// 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
|
\endcode
|
||||||
|
|
||||||
@ -83,7 +88,7 @@ Block will be automatically completed by destructor.
|
|||||||
}
|
}
|
||||||
|
|
||||||
void baz(){
|
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...
|
// som code...
|
||||||
}
|
}
|
||||||
\endcode
|
\endcode
|
||||||
@ -158,8 +163,10 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION.
|
|||||||
*/
|
*/
|
||||||
# define EASY_THREAD(name)\
|
# define EASY_THREAD(name)\
|
||||||
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\
|
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)\
|
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.
|
/** Macro for main thread registration.
|
||||||
|
|
||||||
@ -295,7 +302,7 @@ Otherwise, no log messages will be printed.
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class ProfileManager;
|
class ProfileManager;
|
||||||
class ThreadStorage;
|
struct ThreadStorage;
|
||||||
|
|
||||||
namespace profiler {
|
namespace profiler {
|
||||||
|
|
||||||
@ -323,16 +330,17 @@ namespace profiler {
|
|||||||
class PROFILER_API BaseBlockDescriptor
|
class PROFILER_API BaseBlockDescriptor
|
||||||
{
|
{
|
||||||
friend ::ProfileManager;
|
friend ::ProfileManager;
|
||||||
|
friend ::ThreadStorage;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors)
|
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
|
int m_line; ///< Line number in the source file
|
||||||
color_t m_color; ///< Color of the block packed into 1-byte structure
|
color_t m_color; ///< Color of the block packed into 1-byte structure
|
||||||
block_type_t m_type; ///< Type of the block (See BlockType)
|
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:
|
public:
|
||||||
|
|
||||||
@ -340,7 +348,7 @@ namespace profiler {
|
|||||||
inline int line() const { return m_line; }
|
inline int line() const { return m_line; }
|
||||||
inline color_t color() const { return m_color; }
|
inline color_t color() const { return m_color; }
|
||||||
inline block_type_t type() const { return m_type; }
|
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.
|
}; // END of class BaseBlockDescriptor.
|
||||||
|
|
||||||
@ -381,17 +389,17 @@ namespace profiler {
|
|||||||
{
|
{
|
||||||
friend ::ProfileManager;
|
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_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
|
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
|
uint16_t m_size; ///< Used memory size
|
||||||
bool m_expired; ///< Is this descriptor expired
|
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:
|
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 {
|
inline const char* name() const {
|
||||||
return m_name;
|
return m_name;
|
||||||
@ -410,8 +418,8 @@ namespace profiler {
|
|||||||
friend ::ProfileManager;
|
friend ::ProfileManager;
|
||||||
friend ::ThreadStorage;
|
friend ::ThreadStorage;
|
||||||
|
|
||||||
const char* m_name;
|
const char* m_name;
|
||||||
bool m_enabled;
|
EasyBlockStatus m_status;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -420,7 +428,8 @@ namespace profiler {
|
|||||||
void finish();
|
void finish();
|
||||||
void finish(timestamp_t _time);
|
void finish(timestamp_t _time);
|
||||||
inline bool finished() const { return m_end >= m_begin; }
|
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:
|
public:
|
||||||
|
|
||||||
@ -459,6 +468,13 @@ namespace profiler {
|
|||||||
|
|
||||||
}; // END of class BlockDescRef.
|
}; // END of class BlockDescRef.
|
||||||
|
|
||||||
|
class PROFILER_API ThreadGuard final {
|
||||||
|
friend ::ProfileManager;
|
||||||
|
thread_id_t m_id = 0;
|
||||||
|
public:
|
||||||
|
~ThreadGuard();
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Core API
|
// Core API
|
||||||
// Note: it is better to use macros defined above than a direct calls to API.
|
// Note: it is better to use macros defined above than a direct calls to API.
|
||||||
@ -472,7 +488,7 @@ namespace profiler {
|
|||||||
|
|
||||||
\ingroup 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.
|
/** Stores event in the blocks list.
|
||||||
|
|
||||||
@ -517,7 +533,7 @@ namespace profiler {
|
|||||||
|
|
||||||
\ingroup 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.
|
/** Enable or disable event tracing.
|
||||||
|
|
||||||
@ -555,15 +571,11 @@ namespace profiler {
|
|||||||
PROFILER_API const char* getContextSwitchLogFilename();
|
PROFILER_API const char* getContextSwitchLogFilename();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PROFILER_API void startListenSignalToCapture();
|
PROFILER_API void startListenSignalToCapture();
|
||||||
PROFILER_API void stopListenSignalToCapture();
|
PROFILER_API void stopListenSignalToCapture();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setEnabled(::profiler::EasyEnableFlag _isEnable) {
|
|
||||||
setEnabled(_isEnable == ::profiler::ENABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
} // END of namespace profiler.
|
} // END of namespace profiler.
|
||||||
|
@ -80,10 +80,13 @@
|
|||||||
|
|
||||||
namespace profiler {
|
namespace profiler {
|
||||||
|
|
||||||
enum EasyEnableFlag : uint8_t
|
enum EasyBlockStatus : uint8_t {
|
||||||
{
|
OFF = 0, ///< The block is OFF
|
||||||
DISABLED = 0,
|
ON = 1, ///< The block is ON (but if it's parent block is off recursively then this block will be off too)
|
||||||
ENABLED = 1
|
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 {
|
struct passthrough_hash final {
|
||||||
@ -126,7 +129,7 @@ namespace profiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ... TArgs>
|
template <class ... TArgs>
|
||||||
inline color_t extract_color(::profiler::EasyEnableFlag, TArgs...) {
|
inline color_t extract_color(::profiler::EasyBlockStatus, TArgs...) {
|
||||||
return ::profiler::colors::Default;
|
return ::profiler::colors::Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,24 +151,24 @@ namespace profiler {
|
|||||||
|
|
||||||
//***********************************************
|
//***********************************************
|
||||||
|
|
||||||
inline bool extract_enable_flag() {
|
inline EasyBlockStatus extract_enable_flag() {
|
||||||
return true;
|
return ::profiler::ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class ... TArgs>
|
template <class T, class ... TArgs>
|
||||||
inline bool extract_enable_flag(T, ::profiler::EasyEnableFlag _flag, TArgs...) {
|
inline EasyBlockStatus extract_enable_flag(T, ::profiler::EasyBlockStatus _flag, TArgs...) {
|
||||||
return _flag == ::profiler::ENABLED;
|
return _flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ... TArgs>
|
template <class ... TArgs>
|
||||||
inline bool extract_enable_flag(::profiler::EasyEnableFlag _flag, TArgs...) {
|
inline EasyBlockStatus extract_enable_flag(::profiler::EasyBlockStatus _flag, TArgs...) {
|
||||||
return _flag == ::profiler::ENABLED;
|
return _flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ... TArgs>
|
template <class ... TArgs>
|
||||||
inline bool extract_enable_flag(TArgs...) {
|
inline EasyBlockStatus extract_enable_flag(TArgs...) {
|
||||||
static_assert(sizeof...(TArgs) < 2, "No EasyEnableFlag in arguments list for EASY_BLOCK(name, ...)!");
|
static_assert(sizeof...(TArgs) < 2, "No EasyBlockStatus in arguments list for EASY_BLOCK(name, ...)!");
|
||||||
return true;
|
return ::profiler::ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
//***********************************************
|
//***********************************************
|
||||||
|
@ -21,8 +21,6 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#include "profiler/profiler.h"
|
#include "profiler/profiler.h"
|
||||||
|
|
||||||
class ThreadStorage;
|
|
||||||
|
|
||||||
namespace profiler {
|
namespace profiler {
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -69,9 +67,9 @@ namespace profiler {
|
|||||||
return name() + m_nameLength;
|
return name() + m_nameLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setEnabled(bool _enabled)
|
inline void setStatus(EasyBlockStatus _status)
|
||||||
{
|
{
|
||||||
m_enabled = _enabled;
|
m_status = _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QAction>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
@ -442,18 +443,24 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto id = item->block().node->id();
|
const auto& desc = easyDescriptor(item->block().node->id());
|
||||||
action = menu.addAction("Block enabled");
|
auto submenu = menu.addMenu("Block status");
|
||||||
action->setCheckable(true);
|
|
||||||
action->setChecked(easyDescriptor(id).enabled());
|
|
||||||
action->setData(id);
|
|
||||||
connect(action, &QAction::triggered, this, &This::onBlockEnableDisable);
|
|
||||||
|
|
||||||
if (action->isChecked()) {
|
#define ADD_STATUS_ACTION(NameValue, StatusValue)\
|
||||||
auto f = action->font();
|
action = submenu->addAction(NameValue);\
|
||||||
f.setBold(true);
|
action->setCheckable(true);\
|
||||||
action->setFont(f);
|
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();
|
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());
|
auto action = qobject_cast<QAction*>(sender());
|
||||||
if (action != nullptr)
|
if (action != nullptr)
|
||||||
{
|
{
|
||||||
auto id = action->data().toUInt();
|
auto& desc = easyDescriptor(item->block().node->id());
|
||||||
easyDescriptor(id).setEnabled(_checked);
|
desc.setStatus(static_cast<::profiler::EasyBlockStatus>(action->data().toUInt()));
|
||||||
emit EASY_GLOBALS.events.enableStatusChanged(id, _checked);
|
emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
#define EASY__TREE_WIDGET__H_
|
#define EASY__TREE_WIDGET__H_
|
||||||
|
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
#include <QAction>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "tree_widget_loader.h"
|
#include "tree_widget_loader.h"
|
||||||
#include "profiler/reader.h"
|
#include "profiler/reader.h"
|
||||||
@ -108,7 +107,7 @@ private slots:
|
|||||||
|
|
||||||
void onSelectedBlockChange(uint32_t _block_index);
|
void onSelectedBlockChange(uint32_t _block_index);
|
||||||
|
|
||||||
void onBlockEnableDisable(bool _checked);
|
void onBlockStatusChangeClicked(bool);
|
||||||
|
|
||||||
void resizeColumnsToContents();
|
void resizeColumnsToContents();
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QActionGroup>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
@ -63,14 +64,92 @@
|
|||||||
enum DescColumns
|
enum DescColumns
|
||||||
{
|
{
|
||||||
DESC_COL_FILE_LINE = 0,
|
DESC_COL_FILE_LINE = 0,
|
||||||
|
DESC_COL_TYPE,
|
||||||
DESC_COL_NAME,
|
DESC_COL_NAME,
|
||||||
DESC_COL_STATUS,
|
DESC_COL_STATUS,
|
||||||
|
|
||||||
DESC_COL_COLUMNS_NUMBER
|
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();
|
auto header_item = new QTreeWidgetItem();
|
||||||
header_item->setText(DESC_COL_FILE_LINE, "File/Line");
|
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_NAME, "Name");
|
||||||
header_item->setText(DESC_COL_STATUS, "Status");
|
header_item->setText(DESC_COL_STATUS, "Status");
|
||||||
setHeaderItem(header_item);
|
setHeaderItem(header_item);
|
||||||
|
|
||||||
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
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::itemExpanded, this, &This::onItemExpand);
|
||||||
connect(this, &Parent::itemDoubleClicked, this, &This::onDoubleClick);
|
connect(this, &Parent::itemDoubleClicked, this, &This::onDoubleClick);
|
||||||
connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
|
connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
|
||||||
@ -155,12 +235,40 @@ void EasyDescTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
|||||||
auto header_item = headerItem();
|
auto header_item = headerItem();
|
||||||
for (int i = 0; i < DESC_COL_STATUS; ++i)
|
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);
|
action->setCheckable(true);
|
||||||
if (i == m_searchColumn)
|
if (i == m_searchColumn)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
connect(action, &QAction::triggered, this, &This::onSearchColumnChange);
|
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());
|
menu.exec(QCursor::pos());
|
||||||
@ -254,6 +362,8 @@ void EasyDescTreeWidget::build()
|
|||||||
{
|
{
|
||||||
p.item = new QTreeWidgetItem();
|
p.item = new QTreeWidgetItem();
|
||||||
p.item->setText(DESC_COL_FILE_LINE, desc->file());
|
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());
|
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->setData(DESC_COL_FILE_LINE, Qt::UserRole, desc->line());
|
||||||
item->setText(DESC_COL_NAME, desc->name());
|
item->setText(DESC_COL_NAME, desc->name());
|
||||||
|
|
||||||
item->setFont(DESC_COL_STATUS, f);
|
if (desc->type() == ::profiler::BLOCK_TYPE_BLOCK)
|
||||||
|
|
||||||
QBrush brush;
|
|
||||||
if (desc->enabled())
|
|
||||||
{
|
{
|
||||||
item->setText(DESC_COL_STATUS, "ON");
|
item->setText(DESC_COL_TYPE, "B");
|
||||||
brush.setColor(QColor::fromRgba(ENABLED_COLOR));
|
item->setToolTip(DESC_COL_TYPE, "Block");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->setText(DESC_COL_STATUS, "OFF");
|
item->setText(DESC_COL_TYPE, "E");
|
||||||
brush.setColor(QColor::fromRgba(DISABLED_COLOR));
|
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;
|
m_items[id] = item;
|
||||||
}
|
}
|
||||||
@ -312,29 +421,17 @@ void EasyDescTreeWidget::onItemExpand(QTreeWidgetItem*)
|
|||||||
|
|
||||||
void EasyDescTreeWidget::onDoubleClick(QTreeWidgetItem* _item, int _column)
|
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 item = static_cast<EasyDescWidgetItem*>(_item);
|
||||||
auto& desc = easyDescriptor(item->desc());
|
auto& desc = easyDescriptor(item->desc());
|
||||||
|
desc.setStatus(nextStatus(desc.status()));
|
||||||
|
|
||||||
QBrush brush;
|
item->setText(DESC_COL_STATUS, statusText(desc.status()));
|
||||||
if (desc.enabled())
|
item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status())));
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
m_bLocked = true;
|
m_bLocked = true;
|
||||||
emit EASY_GLOBALS.events.enableStatusChanged(item->desc(), desc.enabled());
|
emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status());
|
||||||
m_bLocked = false;
|
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)
|
if (m_bLocked)
|
||||||
return;
|
return;
|
||||||
@ -370,19 +490,9 @@ void EasyDescTreeWidget::onEnableStatusChange(::profiler::block_id_t _id, bool _
|
|||||||
if (item == nullptr)
|
if (item == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QBrush brush;
|
auto& desc = easyDescriptor(item->desc());
|
||||||
if (_enabled)
|
item->setText(DESC_COL_STATUS, statusText(desc.status()));
|
||||||
{
|
item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status())));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -107,11 +107,12 @@ public slots:
|
|||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void onSearchColumnChange(bool);
|
void onSearchColumnChange(bool);
|
||||||
|
void onBlockStatusChangeClicked(bool);
|
||||||
void onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _prev);
|
void onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _prev);
|
||||||
void onItemExpand(QTreeWidgetItem* _item);
|
void onItemExpand(QTreeWidgetItem* _item);
|
||||||
void onDoubleClick(QTreeWidgetItem* _item, int _column);
|
void onDoubleClick(QTreeWidgetItem* _item, int _column);
|
||||||
void onSelectedBlockChange(uint32_t _block_index);
|
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();
|
void resizeColumnsToContents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -52,7 +52,7 @@ namespace profiler_gui {
|
|||||||
void itemsExpandStateChanged();
|
void itemsExpandStateChanged();
|
||||||
void drawBordersChanged();
|
void drawBordersChanged();
|
||||||
void chronoPositionChanged();
|
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.
|
}; // END of class EasyGlobalSignals.
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ std::mutex cv_m;
|
|||||||
int g_i = 0;
|
int g_i = 0;
|
||||||
|
|
||||||
int OBJECTS = 500;
|
int OBJECTS = 500;
|
||||||
int RENDER_STEPS = 1600;
|
int MODELLING_STEPS = 1500;
|
||||||
int MODELLING_STEPS = 1000;
|
int RENDER_STEPS = 1500;
|
||||||
int RESOURCE_LOADING_COUNT = 50;
|
int RESOURCE_LOADING_COUNT = 50;
|
||||||
|
|
||||||
void localSleep(int magic=200000)
|
void localSleep(int magic=200000)
|
||||||
@ -105,7 +105,7 @@ void prepareRender(){
|
|||||||
|
|
||||||
int multPhys(int i)
|
int multPhys(int i)
|
||||||
{
|
{
|
||||||
EASY_FUNCTION(profiler::colors::Red700, profiler::DISABLED);
|
EASY_FUNCTION(profiler::colors::Red700, profiler::ON);
|
||||||
return i * i * i * i / 100;
|
return i * i * i * i / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ void modellingThread(){
|
|||||||
//std::unique_lock<std::mutex> lk(cv_m);
|
//std::unique_lock<std::mutex> lk(cv_m);
|
||||||
//cv.wait(lk, []{return g_i == 1; });
|
//cv.wait(lk, []{return g_i == 1; });
|
||||||
EASY_THREAD("Modelling");
|
EASY_THREAD("Modelling");
|
||||||
for (int i = 0; i < RENDER_STEPS; i++){
|
for (int i = 0; i < MODELLING_STEPS; i++){
|
||||||
modellingStep();
|
modellingStep();
|
||||||
localSleep(1200000);
|
localSleep(1200000);
|
||||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
@ -157,7 +157,7 @@ void renderThread(){
|
|||||||
//std::unique_lock<std::mutex> lk(cv_m);
|
//std::unique_lock<std::mutex> lk(cv_m);
|
||||||
//cv.wait(lk, []{return g_i == 1; });
|
//cv.wait(lk, []{return g_i == 1; });
|
||||||
EASY_THREAD("Render");
|
EASY_THREAD("Render");
|
||||||
for (int i = 0; i < MODELLING_STEPS; i++){
|
for (int i = 0; i < RENDER_STEPS; i++){
|
||||||
frame();
|
frame();
|
||||||
localSleep(1200000);
|
localSleep(1200000);
|
||||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
@ -172,34 +172,27 @@ int main(int argc, char* argv[])
|
|||||||
OBJECTS = std::atoi(argv[1]);
|
OBJECTS = std::atoi(argv[1]);
|
||||||
}
|
}
|
||||||
if (argc > 2 && argv[2]){
|
if (argc > 2 && argv[2]){
|
||||||
RENDER_STEPS = std::atoi(argv[2]);
|
MODELLING_STEPS = std::atoi(argv[2]);
|
||||||
}
|
}
|
||||||
if (argc > 3 && argv[3]){
|
if (argc > 3 && argv[3]){
|
||||||
MODELLING_STEPS = std::atoi(argv[3]);
|
RENDER_STEPS = std::atoi(argv[3]);
|
||||||
}
|
}
|
||||||
if (argc > 4 && argv[4]){
|
if (argc > 4 && argv[4]){
|
||||||
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
|
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Objects count: " << OBJECTS << std::endl;
|
std::cout << "Objects count: " << OBJECTS << std::endl;
|
||||||
std::cout << "Render steps: " << RENDER_STEPS << std::endl;
|
std::cout << "Render steps: " << MODELLING_STEPS << std::endl;
|
||||||
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
|
std::cout << "Modelling steps: " << RENDER_STEPS << std::endl;
|
||||||
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
|
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
|
||||||
|
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
EASY_PROFILER_ENABLE;
|
EASY_PROFILER_ENABLE;
|
||||||
EASY_MAIN_THREAD;
|
EASY_MAIN_THREAD;
|
||||||
profiler::startListenSignalToCapture();
|
profiler::startListenSignalToCapture();
|
||||||
//one();
|
|
||||||
//one();
|
|
||||||
/**/
|
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
|
for (int i=0; i < 3; i++) {
|
||||||
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(loadingResourcesThread));
|
||||||
threads.emplace_back(std::thread(renderThread));
|
threads.emplace_back(std::thread(renderThread));
|
||||||
threads.emplace_back(std::thread(modellingThread));
|
threads.emplace_back(std::thread(modellingThread));
|
||||||
@ -210,16 +203,10 @@ int main(int argc, char* argv[])
|
|||||||
cv_m.unlock();
|
cv_m.unlock();
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
|
|
||||||
for (int i = 0; i < RENDER_STEPS; ++i) {
|
modellingThread();
|
||||||
modellingStep();
|
|
||||||
localSleep(1200000);
|
|
||||||
}
|
|
||||||
|
|
||||||
render.join();
|
|
||||||
modelling.join();
|
|
||||||
for(auto& t : threads)
|
for(auto& t : threads)
|
||||||
t.join();
|
t.join();
|
||||||
/**/
|
|
||||||
|
|
||||||
auto end = std::chrono::system_clock::now();
|
auto end = std::chrono::system_clock::now();
|
||||||
auto elapsed =
|
auto elapsed =
|
||||||
|
@ -23,35 +23,11 @@
|
|||||||
* : You should have received a copy of the GNU General Public License
|
* : You should have received a copy of the GNU General Public License
|
||||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
#include "profiler/profiler.h"
|
|
||||||
#include "profile_manager.h"
|
#include "profile_manager.h"
|
||||||
#include <ctime>
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace profiler;
|
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)
|
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
|
||||||
: m_begin(_begin_time)
|
: m_begin(_begin_time)
|
||||||
, m_end(0)
|
, m_end(0)
|
||||||
@ -63,23 +39,25 @@ BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
|
|||||||
Block::Block(Block&& that)
|
Block::Block(Block&& that)
|
||||||
: BaseBlockData(that.m_begin, that.m_id)
|
: BaseBlockData(that.m_begin, that.m_id)
|
||||||
, m_name(that.m_name)
|
, m_name(that.m_name)
|
||||||
, m_enabled(that.m_enabled)
|
, m_status(that.m_status)
|
||||||
{
|
{
|
||||||
m_end = that.m_end;
|
m_end = that.m_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::Block(const BaseBlockDescriptor& _descriptor, const char* _runtimeName)
|
Block::Block(const BaseBlockDescriptor& _descriptor, const char* _runtimeName)
|
||||||
: BaseBlockData(_descriptor.enabled() ? getCurrentTime() : 1ULL, _descriptor.id())
|
: BaseBlockData(1ULL, _descriptor.id())
|
||||||
, m_name(_runtimeName)
|
, 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)
|
Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, const char* _runtimeName)
|
||||||
: BaseBlockData(_begin_time, _descriptor_id)
|
: BaseBlockData(_begin_time, _descriptor_id)
|
||||||
, m_name(_runtimeName)
|
, m_name(_runtimeName)
|
||||||
, m_enabled(true)
|
, m_status(::profiler::ON)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Block::start()
|
void Block::start()
|
||||||
|
@ -103,7 +103,7 @@ namespace profiler {
|
|||||||
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
|
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EASY_FUNCTION(::profiler::colors::White, ::profiler::DISABLED);
|
EASY_FUNCTION(::profiler::colors::White, ::profiler::OFF);
|
||||||
|
|
||||||
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
|
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
|
||||||
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
|
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
|
* : You should have received a copy of the GNU General Public License
|
||||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
#include "profile_manager.h"
|
#include "profile_manager.h"
|
||||||
#include "profiler/serialized_block.h"
|
#include "profiler/serialized_block.h"
|
||||||
#include "profiler/easy_net.h"
|
#include "profiler/easy_net.h"
|
||||||
|
|
||||||
#include "profiler/easy_socket.h"
|
#include "profiler/easy_socket.h"
|
||||||
#include "event_trace_win.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;
|
using namespace profiler;
|
||||||
|
|
||||||
#ifdef _WIN32
|
const uint8_t FORCE_ON_FLAG = profiler::FORCE_ON & ~profiler::ON;
|
||||||
extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern timestamp_t getCurrentTime();
|
|
||||||
|
|
||||||
//auto& MANAGER = ProfileManager::instance();
|
//auto& MANAGER = ProfileManager::instance();
|
||||||
#define 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" {
|
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()
|
PROFILER_API void endBlock()
|
||||||
@ -85,9 +82,9 @@ extern "C" {
|
|||||||
return MANAGER.dumpBlocksToFile(filename);
|
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)
|
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_id(_id)
|
||||||
, m_line(_line)
|
, m_line(_line)
|
||||||
, m_type(_block_type)
|
, m_type(_block_type)
|
||||||
, m_color(_color)
|
, 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)
|
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, _enabled, _line, _block_type, _color)
|
: BaseBlockDescriptor(_id, _status, _line, _block_type, _color)
|
||||||
, m_name(_name)
|
, m_name(_name)
|
||||||
, m_filename(_filename)
|
, m_filename(_filename)
|
||||||
, m_pEnable(nullptr)
|
, m_pStatus(nullptr)
|
||||||
, m_size(static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2))
|
, m_size(static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2))
|
||||||
, m_expired(false)
|
, m_expired(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDescriptor::BlockDescriptor(bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
BlockDescriptor::BlockDescriptor(EasyBlockStatus _status, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
||||||
: BaseBlockDescriptor(0, _enabled, _line, _block_type, _color)
|
: BaseBlockDescriptor(0, _status, _line, _block_type, _color)
|
||||||
, m_name(_name)
|
, m_name(_name)
|
||||||
, m_filename(_filename)
|
, m_filename(_filename)
|
||||||
, m_pEnable(nullptr)
|
, m_pStatus(nullptr)
|
||||||
, m_size(static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2))
|
, m_size(static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2))
|
||||||
, m_expired(false)
|
, m_expired(false)
|
||||||
{
|
{
|
||||||
@ -178,14 +175,14 @@ BlockDescRef::~BlockDescRef()
|
|||||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||||
{
|
{
|
||||||
#if EASY_MEASURE_STORAGE_EXPAND != 0
|
#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
|
#endif
|
||||||
|
|
||||||
auto name_length = static_cast<uint16_t>(strlen(block.name()));
|
auto name_length = static_cast<uint16_t>(strlen(block.name()));
|
||||||
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
||||||
|
|
||||||
#if EASY_MEASURE_STORAGE_EXPAND != 0
|
#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(), "");
|
profiler::Block b(0ULL, desc->id(), "");
|
||||||
if (expanded) b.start();
|
if (expanded) b.start();
|
||||||
#endif
|
#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()
|
ProfileManager::ProfileManager()
|
||||||
{
|
{
|
||||||
@ -239,16 +246,16 @@ ProfileManager::ProfileManager()
|
|||||||
|
|
||||||
ProfileManager::~ProfileManager()
|
ProfileManager::~ProfileManager()
|
||||||
{
|
{
|
||||||
|
stopListenSignalToCapture();
|
||||||
stopListenSignalToCapture();
|
|
||||||
if(m_listenThread.joinable()){
|
if (m_listenThread.joinable())
|
||||||
m_listenThread.join();
|
m_listenThread.join();
|
||||||
}
|
|
||||||
for (auto desc : m_descriptors)
|
for (auto desc : m_descriptors)
|
||||||
{
|
{
|
||||||
if (desc != nullptr)
|
if (desc != nullptr)
|
||||||
delete desc;
|
delete desc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileManager& ProfileManager::instance()
|
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)
|
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;
|
return;
|
||||||
|
|
||||||
profiler::Block b(_desc, _runtimeName);
|
|
||||||
b.finish(b.begin());
|
|
||||||
|
|
||||||
if (THREAD_STORAGE == nullptr)
|
if (THREAD_STORAGE == nullptr)
|
||||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
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);
|
THREAD_STORAGE->storeBlock(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,6 +315,26 @@ void ProfileManager::beginBlock(Block& _block)
|
|||||||
if (THREAD_STORAGE == nullptr)
|
if (THREAD_STORAGE == nullptr)
|
||||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
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);
|
THREAD_STORAGE->blocks.openedList.emplace(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,14 +367,22 @@ void ProfileManager::endBlock()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Block& lastBlock = THREAD_STORAGE->blocks.openedList.top();
|
Block& lastBlock = THREAD_STORAGE->blocks.openedList.top();
|
||||||
if (lastBlock.enabled())
|
if (lastBlock.m_status & profiler::ON)
|
||||||
{
|
{
|
||||||
if (!lastBlock.finished())
|
if (!lastBlock.finished())
|
||||||
lastBlock.finish();
|
lastBlock.finish();
|
||||||
THREAD_STORAGE->storeBlock(lastBlock);
|
THREAD_STORAGE->storeBlock(lastBlock);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastBlock.m_end = lastBlock.m_begin; // this is to restrict endBlock() call inside ~Block()
|
||||||
|
}
|
||||||
|
|
||||||
THREAD_STORAGE->blocks.openedList.pop();
|
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)
|
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)
|
if (wasEnabled)
|
||||||
::profiler::setEnabled(false);
|
::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
|
// This is to make sure that no new descriptors or new threads will be
|
||||||
// added until we finish sending data.
|
// added until we finish sending data.
|
||||||
guard_lock_t lock1(m_storedSpin);
|
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
|
// 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
|
#ifndef _WIN32
|
||||||
if (eventTracingEnabled)
|
if (eventTracingEnabled)
|
||||||
{
|
{
|
||||||
@ -416,15 +462,24 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Calculate used memory total size and total blocks number
|
// Calculate used memory total size and total blocks number
|
||||||
uint64_t usedMemorySize = 0;
|
uint64_t usedMemorySize = 0;
|
||||||
uint32_t blocks_number = 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;
|
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
|
// 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
|
// 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);
|
const auto name_size = static_cast<uint16_t>(t.name.size() + 1);
|
||||||
_outputStream.write(name_size);
|
_outputStream.write(name_size);
|
||||||
@ -482,6 +537,11 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
t.clearClosed();
|
t.clearClosed();
|
||||||
t.blocks.openedList.clear();
|
t.blocks.openedList.clear();
|
||||||
t.sync.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)
|
// 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;
|
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 (!THREAD_STORAGE->named)
|
||||||
{
|
{
|
||||||
|
if (!isNewThread) {
|
||||||
|
threadGuard.m_id = THREAD_STORAGE->id = getCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
THREAD_STORAGE->named = true;
|
THREAD_STORAGE->named = true;
|
||||||
THREAD_STORAGE->name = name;
|
THREAD_STORAGE->name = name;
|
||||||
}
|
}
|
||||||
@ -528,7 +595,7 @@ const char* ProfileManager::registerThread(const char* name)
|
|||||||
return THREAD_STORAGE->name.c_str();
|
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);
|
guard_lock_t lock(m_storedSpin);
|
||||||
|
|
||||||
@ -537,16 +604,16 @@ void ProfileManager::setBlockEnabled(profiler::block_id_t _id, const profiler::h
|
|||||||
{
|
{
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
*desc->m_pEnable = _enabled;
|
*desc->m_pStatus = _status;
|
||||||
desc->m_enabled = _enabled; // TODO: possible concurrent access, atomic may be needed
|
desc->m_status = _status; // TODO: possible concurrent access, atomic may be needed
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
blocks_enable_status_t::key_type key(_key.c_str(), _key.size(), _key.hcode());
|
blocks_enable_status_t::key_type key(_key.c_str(), _key.size(), _key.hcode());
|
||||||
m_blocksEnableStatus[key] = _enabled;
|
m_blocksEnableStatus[key] = _status;
|
||||||
#else
|
#else
|
||||||
m_blocksEnableStatus[_key] = _enabled;
|
m_blocksEnableStatus[_key] = _status;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -572,6 +639,7 @@ void ProfileManager::stopListenSignalToCapture()
|
|||||||
|
|
||||||
void ProfileManager::startListen()
|
void ProfileManager::startListen()
|
||||||
{
|
{
|
||||||
|
EASY_THREAD("EasyProfiler.Listen");
|
||||||
|
|
||||||
EasySocket socket;
|
EasySocket socket;
|
||||||
profiler::net::Message replyMessage(profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING);
|
profiler::net::Message replyMessage(profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING);
|
||||||
@ -583,9 +651,9 @@ void ProfileManager::startListen()
|
|||||||
bool hasConnect = false;
|
bool hasConnect = false;
|
||||||
|
|
||||||
socket.listen();
|
socket.listen();
|
||||||
|
|
||||||
socket.accept();
|
socket.accept();
|
||||||
|
|
||||||
|
EASY_EVENT("ClientConnected", profiler::colors::White, profiler::OFF);
|
||||||
hasConnect = true;
|
hasConnect = true;
|
||||||
printf("Client Accepted!\n");
|
printf("Client Accepted!\n");
|
||||||
|
|
||||||
@ -596,7 +664,6 @@ void ProfileManager::startListen()
|
|||||||
|
|
||||||
while (hasConnect && !m_stopListen.load())
|
while (hasConnect && !m_stopListen.load())
|
||||||
{
|
{
|
||||||
|
|
||||||
char buffer[256] = {};
|
char buffer[256] = {};
|
||||||
|
|
||||||
bytes = socket.receive(buffer, 255);
|
bytes = socket.receive(buffer, 255);
|
||||||
@ -616,7 +683,8 @@ void ProfileManager::startListen()
|
|||||||
case profiler::net::MESSAGE_TYPE_REQUEST_START_CAPTURE:
|
case profiler::net::MESSAGE_TYPE_REQUEST_START_CAPTURE:
|
||||||
{
|
{
|
||||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_START_CAPTURE\n");
|
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;
|
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING;
|
||||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||||
@ -626,7 +694,8 @@ void ProfileManager::startListen()
|
|||||||
case profiler::net::MESSAGE_TYPE_REQUEST_STOP_CAPTURE:
|
case profiler::net::MESSAGE_TYPE_REQUEST_STOP_CAPTURE:
|
||||||
{
|
{
|
||||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_STOP_CAPTURE\n");
|
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;
|
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_PREPARE_BLOCKS;
|
||||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
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______
|
#define EASY_PROFILER____MANAGER____H______
|
||||||
|
|
||||||
#include "profiler/profiler.h"
|
#include "profiler/profiler.h"
|
||||||
#include "profiler/serialized_block.h"
|
|
||||||
|
|
||||||
#include "profiler/easy_socket.h"
|
#include "profiler/easy_socket.h"
|
||||||
#include "spin_lock.h"
|
#include "spin_lock.h"
|
||||||
#include "outstream.h"
|
#include "outstream.h"
|
||||||
#include "hashed_cstr.h"
|
#include "hashed_cstr.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <string>
|
|
||||||
#include <functional>
|
|
||||||
#include <string.h>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
//#include <list>
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#else
|
#else
|
||||||
#include <thread>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <chrono>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline uint32_t getCurrentThreadId()
|
inline uint32_t getCurrentThreadId()
|
||||||
@ -58,6 +53,20 @@ inline uint32_t getCurrentThreadId()
|
|||||||
#endif
|
#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 {
|
namespace profiler {
|
||||||
|
|
||||||
class SerializedBlock;
|
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_ALIGNED(TYPE, VAR, A) TYPE VAR
|
||||||
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
|
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
|
||||||
# define EASY_FREE(MEMPTR) free(MEMPTR)
|
# 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<std::reference_wrapper<profiler::Block>, SIZEOF_CSWITCH * (uint16_t)128U> blocks;
|
||||||
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> sync;
|
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> sync;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
profiler::thread_id_t id = 0;
|
||||||
|
std::atomic_bool expired;
|
||||||
|
bool allowChildren = true;
|
||||||
bool named = false;
|
bool named = false;
|
||||||
|
|
||||||
void storeBlock(const profiler::Block& _block);
|
void storeBlock(const profiler::Block& _block);
|
||||||
void storeCSwitch(const profiler::Block& _block);
|
void storeCSwitch(const profiler::Block& _block);
|
||||||
void clearClosed();
|
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;
|
typedef std::vector<profiler::BlockDescriptor*> block_descriptors_t;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
map_of_threads_stacks m_threads;
|
map_of_threads_stacks m_threads;
|
||||||
@ -339,7 +353,7 @@ class ProfileManager final
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t dumpBlocksToStream(profiler::OStream& _outputStream);
|
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;
|
std::thread m_listenThread;
|
||||||
bool m_isAlreadyListened = false;
|
bool m_isAlreadyListened = false;
|
||||||
@ -354,9 +368,9 @@ public:
|
|||||||
~ProfileManager();
|
~ProfileManager();
|
||||||
|
|
||||||
template <class ... TArgs>
|
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);
|
guard_lock_t lock(m_storedSpin);
|
||||||
m_usedMemorySize += desc->m_size;
|
m_usedMemorySize += desc->m_size;
|
||||||
@ -367,12 +381,12 @@ public:
|
|||||||
auto it = m_blocksEnableStatus.find(key);
|
auto it = m_blocksEnableStatus.find(key);
|
||||||
if (it != m_blocksEnableStatus.end())
|
if (it != m_blocksEnableStatus.end())
|
||||||
{
|
{
|
||||||
desc->m_enabled = it->second;
|
desc->m_status = it->second;
|
||||||
desc->m_pEnable = &it->second;
|
desc->m_pStatus = &it->second;
|
||||||
}
|
}
|
||||||
else
|
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;
|
return desc;
|
||||||
@ -384,7 +398,7 @@ public:
|
|||||||
void setEnabled(bool isEnable);
|
void setEnabled(bool isEnable);
|
||||||
void setEventTracingEnabled(bool _isEnable);
|
void setEventTracingEnabled(bool _isEnable);
|
||||||
uint32_t dumpBlocksToFile(const char* filename);
|
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
|
#ifndef _WIN32
|
||||||
void setContextSwitchLogFilename(const char* name)
|
void setContextSwitchLogFilename(const char* name)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user