diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h
index 49491bf..905f025 100644
--- a/include/profiler/profiler.h
+++ b/include/profiler/profiler.h
@@ -19,67 +19,36 @@ along with this program.If not, see .
#ifndef EASY_PROFILER____H_______
#define EASY_PROFILER____H_______
-#ifdef _WIN32
-# define __func__ __FUNCTION__
-# if defined(_MSC_VER) && _MSC_VER <= 1800
-// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
-# define EASY_THREAD_LOCAL __declspec(thread)
-# endif
-#elif defined(__GNUC__)
-#ifndef __clang__
-# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4)
-// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
-# define EASY_THREAD_LOCAL __thread
-#endif
-# endif
-#if defined ( __clang__ )
-# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3)
-# define EASY_THREAD_LOCAL __thread
-#endif
-#endif
-
-#endif
-
-// TODO: Check thread local support for clanv earlier than 3.3
-
-#ifndef EASY_THREAD_LOCAL
-# define EASY_THREAD_LOCAL thread_local
-# define EASY_THREAD_LOCAL_CPP11
-#endif
+#include "profiler/profiler_aux.h"
#if defined ( __clang__ )
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
#ifndef FULL_DISABLE_PROFILER
-#include
-
-#define EASY_TOKEN_JOIN(x, y) x ## y
-#define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
-#define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
-#define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
-
/**
\defgroup profiler Profiler
*/
-namespace profiler {
- template struct NameSwitch final {
- static const char* runtime_name(const char* name) { return name; }
- static const char* compiletime_name(const char*) { return ""; }
- };
+/** If != 0 then EasyProfiler will measure time for blocks storage expansion.
+If 0 then EasyProfiler will be compiled without blocks of code responsible
+for measuring these events.
- template <> struct NameSwitch final {
- static const char* runtime_name(const char*) { return ""; }
- static const char* compiletime_name(const char* name) { return name; }
- };
-} // END of namespace profiler.
+These are "EasyProfiler.ExpandStorage" blocks on a diagram.
-#define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::compiletime_name(name)
-#define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::runtime_name(name)
+\ingroup profiler
+*/
+# define EASY_MEASURE_STORAGE_EXPAND 0
+/** If true then "EasyProfiler.ExpandStorage" events are enabled by default and will be
+writed to output file or translated over the net.
+If false then you need to enable these events via GUI if you'll want to see them.
+
+\ingroup profiler
+*/
+# define EASY_STORAGE_EXPAND_ENABLED true
/** Macro of beginning of block with custom name and color.
@@ -88,6 +57,8 @@ namespace profiler {
void foo()
{
// some code ...
+
+ EASY_BLOCK("Check something", profiler::DISABLED); // Disabled block (There is possibility to enable this block later via GUI)
if(something){
EASY_BLOCK("Calling bar()"); // Block with default color
bar();
@@ -96,6 +67,10 @@ namespace profiler {
EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block
baz();
}
+ 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
+ // some another code...
}
\endcode
@@ -103,9 +78,9 @@ Block will be automatically completed by destructor.
\ingroup profiler
*/
-#define EASY_BLOCK(name, ...)\
- static const ::profiler::BaseBlockDescriptor& EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
- ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
+# define EASY_BLOCK(name, ...)\
+ static const ::profiler::BlockDescRef EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
+ EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__));\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
@@ -122,15 +97,20 @@ Block will be automatically completed by destructor.
EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar"
//some code...
}
+
+ void baz(){
+ EASY_FUNCTION(profiler::DISABLED); // Disabled block with name="baz" and default color (There is possibility to enable this block later via GUI)
+ // som code...
+ }
\endcode
Name of the block automatically created with function name.
\ingroup profiler
*/
-#define EASY_FUNCTION(...)\
- static const ::profiler::BaseBlockDescriptor& EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\
- ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
+# define EASY_FUNCTION(...)\
+ static const ::profiler::BlockDescRef EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
+ __func__, __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__));\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), "");\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
@@ -157,7 +137,7 @@ int foo()
\ingroup profiler
*/
-#define EASY_END_BLOCK ::profiler::endBlock();
+# define EASY_END_BLOCK ::profiler::endBlock();
/** Macro of creating event with custom name and color.
@@ -168,20 +148,23 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION.
\ingroup profiler
*/
-#define EASY_EVENT(name, ...)\
- static const ::profiler::BaseBlockDescriptor& EASY_UNIQUE_DESC(__LINE__) = \
- ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\
+# define EASY_EVENT(name, ...)\
+ static const ::profiler::BlockDescRef EASY_UNIQUE_DESC(__LINE__) = \
+ ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__), EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
+ ::profiler::BLOCK_TYPE_EVENT, ::profiler::extract_color(__VA_ARGS__));\
::profiler::storeBlock(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));
/** Macro enabling profiler
+
\ingroup profiler
*/
-#define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
+# define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
/** Macro disabling profiler
+
\ingroup profiler
*/
-#define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
+# define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
/** Macro of naming current thread.
@@ -189,7 +172,7 @@ If this thread has been already named then nothing changes.
\ingroup profiler
*/
-#define EASY_THREAD(name)\
+# define EASY_THREAD(name)\
EASY_THREAD_LOCAL static const char* 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::setThreadName(name, __FILE__, __func__, __LINE__);
@@ -200,39 +183,31 @@ This is only for user comfort. There is no difference for EasyProfiler GUI betwe
\ingroup profiler
*/
-#define EASY_MAIN_THREAD EASY_THREAD("Main")
+# define EASY_MAIN_THREAD EASY_THREAD("Main")
#else
-#define EASY_BLOCK(...)
-#define EASY_FUNCTION(...)
-#define EASY_END_BLOCK
-#define EASY_PROFILER_ENABLE
-#define EASY_PROFILER_DISABLE
-#define EASY_EVENT(...)
-#define EASY_THREAD(...)
-#define EASY_MAIN_THREAD
+# define EASY_MEASURE_STORAGE_EXPAND 0
+# define EASY_STORAGE_EXPAND_ENABLED false
+# define EASY_BLOCK(...)
+# define EASY_FUNCTION(...)
+# define EASY_END_BLOCK
+# define EASY_PROFILER_ENABLE
+# define EASY_PROFILER_DISABLE
+# define EASY_EVENT(...)
+# define EASY_THREAD(...)
+# define EASY_MAIN_THREAD
#endif
-#include
-#include
-#include "profiler/profiler_colors.h"
-
-#ifdef _WIN32
-#ifdef _BUILD_PROFILER
-#define PROFILER_API __declspec(dllexport)
-#else
-#define PROFILER_API __declspec(dllimport)
-#endif
-#else
-#define PROFILER_API
-#endif
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
class ProfileManager;
+class ThreadStorage;
namespace profiler {
- class Block;
- class BaseBlockDescriptor;
+ //////////////////////////////////////////////////////////////////////
+ // Core types
typedef uint64_t timestamp_t;
typedef uint32_t thread_id_t;
@@ -249,17 +224,7 @@ namespace profiler {
};
typedef BlockType block_type_t;
- extern "C" {
- PROFILER_API const BaseBlockDescriptor& registerDescription(const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color = ::profiler::colors::Default);
- PROFILER_API void storeBlock(const BaseBlockDescriptor& _desc, const char* _runtimeName);
- PROFILER_API void beginBlock(Block& _block);
- PROFILER_API void endBlock();
- PROFILER_API void setEnabled(bool _isEnable);
- PROFILER_API uint32_t dumpBlocksToFile(const char* _filename);
- PROFILER_API const char* setThreadName(const char* _name, const char* _filename, const char* _funcname, int _line);
- PROFILER_API void setContextSwitchLogFilename(const char* _name);
- PROFILER_API const char* getContextSwitchLogFilename();
- }
+ //***********************************************
#pragma pack(push,1)
class PROFILER_API BaseBlockDescriptor
@@ -274,7 +239,7 @@ namespace profiler {
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
- BaseBlockDescriptor(block_id_t _id, int _line, block_type_t _block_type, color_t _color);
+ BaseBlockDescriptor(block_id_t _id, bool _enabled, int _line, block_type_t _block_type, color_t _color);
public:
@@ -283,22 +248,10 @@ namespace profiler {
inline color_t color() const { return m_color; }
inline block_type_t type() const { return m_type; }
inline bool enabled() const { return m_enabled; }
- };
- class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
- {
- friend ::ProfileManager;
+ }; // END of class BaseBlockDescriptor.
- 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
-
- public:
-
- BlockDescriptor(uint64_t& _used_mem, block_id_t _id, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
-
- inline const char* name() const { return m_name; }
- inline const char* file() const { return m_filename; }
- };
+ //***********************************************
class PROFILER_API BaseBlockData
{
@@ -325,20 +278,52 @@ namespace profiler {
private:
BaseBlockData() = delete;
- };
+
+ }; // END of class BaseBlockData.
#pragma pack(pop)
+ //***********************************************
+
+ class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
+ {
+ friend ::ProfileManager;
+
+ const char* m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier
+ const char* m_filename; ///< Source file name where this block is declared
+
+ BlockDescriptor(uint64_t& _used_mem, bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
+ void setId(block_id_t _id);
+
+ public:
+
+ BlockDescriptor(uint64_t& _used_mem, block_id_t _id, bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
+
+ inline const char* name() const {
+ return m_name;
+ }
+
+ inline const char* file() const {
+ return m_filename;
+ }
+
+ }; // END of class BlockDescriptor.
+
+ //***********************************************
+
class PROFILER_API Block final : public BaseBlockData
{
friend ::ProfileManager;
+ friend ::ThreadStorage;
const char* m_name;
bool m_enabled;
private:
+ void start();
+ void start(timestamp_t _time);
void finish();
- void finish(timestamp_t _end_time);
+ void finish(timestamp_t _time);
inline bool finished() const { return m_end >= m_begin; }
inline bool enabled() const { return m_enabled; }
@@ -346,18 +331,58 @@ namespace profiler {
Block(Block&& that);
Block(const BaseBlockDescriptor& _desc, const char* _runtimeName);
- Block(timestamp_t _begin_time, block_id_t _id, bool _enabled, const char* _runtimeName);
+ Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName);
~Block();
inline const char* name() const { return m_name; }
- };
+
+ }; // END of class Block.
+
+ //***********************************************
+
+ class PROFILER_API BlockDescRef final
+ {
+ const BaseBlockDescriptor& m_desc;
+
+ public:
+
+ BlockDescRef(const BaseBlockDescriptor& _desc) : m_desc(_desc) { }
+ inline operator const BaseBlockDescriptor& () const { return m_desc; }
+ ~BlockDescRef();
+
+ private:
+
+ BlockDescRef() = delete;
+ BlockDescRef(const BlockDescRef&) = delete;
+ BlockDescRef& operator = (const BlockDescRef&) = delete;
+
+ }; // END of class BlockDescRef.
+
+ //////////////////////////////////////////////////////////////////////
+ // Core API
+
+ extern "C" {
+ PROFILER_API const BaseBlockDescriptor& registerDescription(bool _enabled, const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color);
+ PROFILER_API void storeBlock(const BaseBlockDescriptor& _desc, const char* _runtimeName);
+ PROFILER_API void beginBlock(Block& _block);
+ PROFILER_API void endBlock();
+ PROFILER_API void setEnabled(bool _isEnable);
+ PROFILER_API uint32_t dumpBlocksToFile(const char* _filename);
+ PROFILER_API const char* setThreadName(const char* _name, const char* _filename, const char* _funcname, int _line);
+ PROFILER_API void setContextSwitchLogFilename(const char* _name);
+ PROFILER_API const char* getContextSwitchLogFilename();
+ }
+
+ inline void setEnabled(::profiler::EasyEnableFlag _isEnable) {
+ setEnabled(_isEnable == ::profiler::ENABLED);
+ }
//////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#if defined ( __clang__ )
-#pragma clang diagnostic pop
+# pragma clang diagnostic pop
#endif
#endif // EASY_PROFILER____H_______
diff --git a/include/profiler/profiler_aux.h b/include/profiler/profiler_aux.h
new file mode 100644
index 0000000..5ab3a4b
--- /dev/null
+++ b/include/profiler/profiler_aux.h
@@ -0,0 +1,176 @@
+/************************************************************************
+* file name : profiler_aux.h
+* ----------------- :
+* creation time : 2016/06/11
+* author : Victor Zarubkin
+* email : v.s.zarubkin@gmail.com
+* ----------------- :
+* description : This file contains auxiliary profiler macros and funcitons.
+* ----------------- :
+* change log : * 2016/06/11 Victor Zarubkin: Moved sources from profiler.h
+* :
+* : *
+* ----------------- :
+* license : Lightweight profiler library for c++
+* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
+* :
+* : This program is free software : you can redistribute it and / or modify
+* : it under the terms of the GNU General Public License as published by
+* : the Free Software Foundation, either version 3 of the License, or
+* : (at your option) any later version.
+* :
+* : This program is distributed in the hope that it will be useful,
+* : but WITHOUT ANY WARRANTY; without even the implied warranty of
+* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+* : GNU General Public License for more details.
+* :
+* : You should have received a copy of the GNU General Public License
+* : along with this program.If not, see .
+************************************************************************/
+
+#ifndef EASY_PROFILER__AUX__H_______
+#define EASY_PROFILER__AUX__H_______
+
+#include
+#include
+#include "profiler/profiler_colors.h"
+
+//////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+
+# define __func__ __FUNCTION__
+# if defined(_MSC_VER) && _MSC_VER <= 1800
+// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
+# define EASY_THREAD_LOCAL __declspec(thread)
+# endif
+# ifdef _BUILD_PROFILER
+# define PROFILER_API __declspec(dllexport)
+# else
+# define PROFILER_API __declspec(dllimport)
+# endif
+
+#elif defined (__clang__)
+
+# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3)
+# define EASY_THREAD_LOCAL __thread
+# endif
+
+#elif defined(__GNUC__)
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4)
+// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
+# define EASY_THREAD_LOCAL __thread
+# endif
+
+#endif
+
+// TODO: Check thread_local support for clang earlier than 3.3
+
+#ifndef EASY_THREAD_LOCAL
+# define EASY_THREAD_LOCAL thread_local
+# define EASY_THREAD_LOCAL_CPP11
+#endif
+
+#ifndef PROFILER_API
+# define PROFILER_API
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+
+namespace profiler {
+
+ enum EasyEnableFlag : uint8_t
+ {
+ DISABLED = 0,
+ ENABLED = 1
+ };
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef FULL_DISABLE_PROFILER
+
+#include
+
+# define EASY_STRINGIFY(a) #a
+# define EASY_TOKEN_JOIN(x, y) x ## y
+# define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
+# define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
+# define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
+
+namespace profiler {
+
+ template struct NameSwitch final {
+ static const char* runtime_name(const char* name) { return name; }
+ static const char* compiletime_name(const char*, const char* autoGeneratedName) { return autoGeneratedName; }
+ };
+
+ template <> struct NameSwitch final {
+ static const char* runtime_name(const char*) { return ""; }
+ static const char* compiletime_name(const char* name, const char*) { return name; }
+ };
+
+ //***********************************************
+
+ inline color_t extract_color() {
+ return ::profiler::colors::Default;
+ }
+
+ template
+ inline color_t extract_color(::profiler::EasyEnableFlag, TArgs...) {
+ return ::profiler::colors::Default;
+ }
+
+ template
+ inline color_t extract_color(color_t _color, TArgs...) {
+ return _color;
+ }
+
+ template
+ inline color_t extract_color(T, color_t _color, TArgs...) {
+ return _color;
+ }
+
+ template
+ inline color_t extract_color(TArgs...) {
+ static_assert(false, "No profiler::color_t in arguments list for EASY_BLOCK(name, ...)!");
+ return ::profiler::colors::Default;
+ }
+
+ //***********************************************
+
+ inline bool extract_enable_flag() {
+ return true;
+ }
+
+ template
+ inline bool extract_enable_flag(T, ::profiler::EasyEnableFlag _flag, TArgs...) {
+ return _flag == ::profiler::ENABLED;
+ }
+
+ template
+ inline bool extract_enable_flag(::profiler::EasyEnableFlag _flag, TArgs...) {
+ return _flag == ::profiler::ENABLED;
+ }
+
+ template
+ inline bool extract_enable_flag(TArgs...) {
+ static_assert(sizeof...(TArgs) < 2, "No EasyEnableFlag in arguments list for EASY_BLOCK(name, ...)!");
+ return true;
+ }
+
+ //***********************************************
+
+} // END of namespace profiler.
+
+# define EASY_UNIQUE_LINE_ID __FILE__ ":" EASY_STRINGIFY(__LINE__)
+# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID)
+# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::runtime_name(name)
+
+#endif // FULL_DISABLE_PROFILER
+
+//////////////////////////////////////////////////////////////////////////
+
+#endif // EASY_PROFILER__AUX__H_______
diff --git a/sample/main.cpp b/sample/main.cpp
index 143fb94..c741a24 100644
--- a/sample/main.cpp
+++ b/sample/main.cpp
@@ -105,7 +105,7 @@ void prepareRender(){
int multPhys(int i)
{
- EASY_FUNCTION(profiler::colors::Red700);
+ EASY_FUNCTION(profiler::colors::Red700, profiler::DISABLED);
return i * i * i * i / 100;
}
diff --git a/src/block.cpp b/src/block.cpp
index 48b2ce3..9d7597a 100644
--- a/src/block.cpp
+++ b/src/block.cpp
@@ -68,25 +68,37 @@ Block::Block(Block&& that)
}
Block::Block(const BaseBlockDescriptor& _descriptor, const char* _runtimeName)
- : Block(getCurrentTime(), _descriptor.id(), _descriptor.enabled(), _runtimeName)
+ : BaseBlockData(_descriptor.enabled() ? getCurrentTime() : 1ULL, _descriptor.id())
+ , m_name(_runtimeName)
+ , m_enabled(_descriptor.enabled())
{
}
-Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, bool _enabled, const char* _runtimeName)
+Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, const char* _runtimeName)
: BaseBlockData(_begin_time, _descriptor_id)
, m_name(_runtimeName)
- , m_enabled(_enabled)
+ , m_enabled(true)
{
}
+void Block::start()
+{
+ m_begin = getCurrentTime();
+}
+
+void Block::start(timestamp_t _time)
+{
+ m_begin = _time;
+}
+
void Block::finish()
{
m_end = getCurrentTime();
}
-void Block::finish(timestamp_t _end_time)
+void Block::finish(timestamp_t _time)
{
- m_end = _end_time;
+ m_end = _time;
}
Block::~Block()
diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp
index d60ed94..5550ba1 100644
--- a/src/event_trace_win.cpp
+++ b/src/event_trace_win.cpp
@@ -43,12 +43,12 @@ namespace profiler {
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
return;
- //EASY_FUNCTION(::profiler::colors::Red);
+ //EASY_FUNCTION(::profiler::colors::White);
auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData);
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
- static const auto& desc = MANAGER.addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
+ static const auto& desc = MANAGER.addBlockDescriptor(true, "OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, desc.id());
MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time);
}
@@ -145,7 +145,6 @@ namespace profiler {
m_stubThread = ::std::move(::std::thread([this]()
{
EASY_THREAD("EasyProfiler.ETW");
- //EASY_BLOCK("ProcessTrace()", ::profiler::colors::Red);
ProcessTrace(&m_openedHandle, 1, 0, 0);
}));
diff --git a/src/hashed_cstr.h b/src/hashed_cstr.h
new file mode 100644
index 0000000..0691c34
--- /dev/null
+++ b/src/hashed_cstr.h
@@ -0,0 +1,229 @@
+/************************************************************************
+* file name : hashed_str.h
+* ----------------- :
+* creation time : 2016/09/11
+* author : Victor Zarubkin
+* email : v.s.zarubkin@gmail.com
+* ----------------- :
+* description : The file contains definition of C-strings with calculated hash-code.
+* : These strings may be used as optimized keys for std::unordered_map.
+* ----------------- :
+* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from reader.cpp
+* :
+* : *
+* ----------------- :
+* license : Lightweight profiler library for c++
+* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
+* :
+* : This program is free software : you can redistribute it and / or modify
+* : it under the terms of the GNU General Public License as published by
+* : the Free Software Foundation, either version 3 of the License, or
+* : (at your option) any later version.
+* :
+* : This program is distributed in the hope that it will be useful,
+* : but WITHOUT ANY WARRANTY; without even the implied warranty of
+* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+* : GNU General Public License for more details.
+* :
+* : You should have received a copy of the GNU General Public License
+* : along with this program.If not, see .
+************************************************************************/
+
+#ifndef EASY_PROFILER__HASHED_CSTR__H_
+#define EASY_PROFILER__HASHED_CSTR__H_
+
+#include
+#include
+#include
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+
+namespace profiler {
+
+ /** \brief Simple C-string pointer with length.
+
+ It is used as base class for a key in std::unordered_map.
+ It is used to get better performance than std::string.
+ It simply stores a pointer and a length, there is no
+ any memory allocation and copy.
+
+ \warning Make sure you know what you are doing. You have to be sure that
+ pointed C-string will exist until you finish using this cstring.
+
+ \ingroup profiler
+ */
+ class cstring
+ {
+ protected:
+
+ const char* m_str;
+ size_t m_len;
+
+ public:
+
+ explicit cstring(const char* _str) : m_str(_str), m_len(strlen(_str))
+ {
+ }
+
+ cstring(const cstring&) = default;
+ cstring& operator = (const cstring&) = default;
+
+ inline bool operator == (const cstring& _other) const
+ {
+ return m_len == _other.m_len && !strncmp(m_str, _other.m_str, m_len);
+ }
+
+ inline bool operator != (const cstring& _other) const
+ {
+ return !operator == (_other);
+ }
+
+ inline bool operator < (const cstring& _other) const
+ {
+ if (m_len == _other.m_len)
+ {
+ return strncmp(m_str, _other.m_str, m_len) < 0;
+ }
+
+ return m_len < _other.m_len;
+ }
+
+ }; // END of class cstring.
+
+ /** \brief cstring with precalculated hash.
+
+ This is used to calculate hash for C-string and to cache it
+ to be used in the future without recurring hash calculatoin.
+
+ \note This class is used as a key in std::unordered_map.
+
+ \ingroup profiler
+ */
+ class hashed_cstr final : public cstring
+ {
+ typedef cstring Parent;
+
+ size_t m_hash;
+
+ public:
+
+ explicit hashed_cstr(const char* _str) : Parent(_str), m_hash(0)
+ {
+ m_hash = ::std::_Hash_seq((const unsigned char *)m_str, m_len);
+ }
+
+ hashed_cstr(const hashed_cstr&) = default;
+ hashed_cstr& operator = (const hashed_cstr&) = default;
+
+ inline bool operator == (const hashed_cstr& _other) const
+ {
+ return m_hash == _other.m_hash && Parent::operator == (_other);
+ }
+
+ inline bool operator != (const hashed_cstr& _other) const
+ {
+ return !operator == (_other);
+ }
+
+ inline size_t hcode() const
+ {
+ return m_hash;
+ }
+
+ }; // END of class hashed_cstr.
+
+} // END of namespace profiler.
+
+namespace std {
+
+ /** \brief Simply returns precalculated hash of a C-string. */
+ template <> struct hash<::profiler::hashed_cstr> {
+ typedef ::profiler::hashed_cstr argument_type;
+ typedef size_t result_type;
+ inline size_t operator () (const ::profiler::hashed_cstr& _str) const {
+ return _str.hcode();
+ }
+ };
+
+} // END of namespace std.
+
+#else ////////////////////////////////////////////////////////////////////
+
+// TODO: Create hashed_cstr for Linux (need to use Linux version of std::_Hash_seq)
+
+#endif
+
+namespace profiler {
+
+ class hashed_stdstring final
+ {
+ ::std::string m_str;
+ size_t m_hash;
+
+ public:
+
+ hashed_stdstring(const char* _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
+ {
+ }
+
+ hashed_stdstring(const ::std::string& _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
+ {
+ }
+
+ hashed_stdstring(::std::string&& _str) : m_str(::std::forward<::std::string&&>(_str)), m_hash(::std::hash<::std::string>()(m_str))
+ {
+ }
+
+ hashed_stdstring(hashed_stdstring&& _other) : m_str(::std::move(_other.m_str)), m_hash(_other.m_hash)
+ {
+ }
+
+ hashed_stdstring(const hashed_stdstring&) = default;
+ hashed_stdstring& operator = (const hashed_stdstring&) = default;
+
+ hashed_stdstring& operator = (hashed_stdstring&& _other)
+ {
+ m_str = ::std::move(_other.m_str);
+ m_hash = _other.m_hash;
+ return *this;
+ }
+
+ inline bool operator == (const hashed_stdstring& _other) const
+ {
+ return m_hash == _other.m_hash && m_str == _other.m_str;
+ }
+
+ inline bool operator != (const hashed_stdstring& _other) const
+ {
+ return !operator == (_other);
+ }
+
+ inline size_t hcode() const
+ {
+ return m_hash;
+ }
+
+ }; // END of class hashed_stdstring.
+
+} // END of namespace profiler.
+
+namespace std {
+
+ /** \brief Simply returns precalculated hash of a std::string. */
+ template <> struct hash<::profiler::hashed_stdstring> {
+ typedef ::profiler::hashed_stdstring argument_type;
+ typedef size_t result_type;
+ inline size_t operator () (const ::profiler::hashed_stdstring& _str) const {
+ return _str.hcode();
+ }
+ };
+
+} // END of namespace std.
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+#endif // EASY_PROFILER__HASHED_CSTR__H_
diff --git a/src/outstream.h b/src/outstream.h
new file mode 100644
index 0000000..ee82b1c
--- /dev/null
+++ b/src/outstream.h
@@ -0,0 +1,75 @@
+/************************************************************************
+* file name : outstream.h
+* ----------------- :
+* creation time : 2016/09/11
+* authors : Sergey Yagovtsev, Victor Zarubkin
+* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
+* ----------------- :
+* description : The file contains definition of output stream helpers.
+* ----------------- :
+* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from profiler_manager.h/.cpp
+* :
+* : *
+* ----------------- :
+* license : Lightweight profiler library for c++
+* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
+* :
+* : This program is free software : you can redistribute it and / or modify
+* : it under the terms of the GNU General Public License as published by
+* : the Free Software Foundation, either version 3 of the License, or
+* : (at your option) any later version.
+* :
+* : This program is distributed in the hope that it will be useful,
+* : but WITHOUT ANY WARRANTY; without even the implied warranty of
+* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+* : GNU General Public License for more details.
+* :
+* : You should have received a copy of the GNU General Public License
+* : along with this program.If not, see .
+************************************************************************/
+
+#ifndef EASY_PROFILER__OUTPUT_STREAM__H_
+#define EASY_PROFILER__OUTPUT_STREAM__H_
+
+#include
+#include
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+namespace profiler {
+
+ class OStream final
+ {
+ ::std::stringstream m_stream;
+
+ public:
+
+ explicit OStream() : m_stream(std::ios_base::out | std::ios_base::binary)
+ {
+
+ }
+
+ template void write(const char* _data, T _size)
+ {
+ m_stream.write(_data, _size);
+ }
+
+ template void write(const T& _data)
+ {
+ m_stream.write((const char*)&_data, sizeof(T));
+ }
+
+ const ::std::stringstream& stream() const
+ {
+ return m_stream;
+ }
+
+ }; // END of class OStream.
+
+} // END of namespace profiler.
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+#endif // EASY_PROFILER__OUTPUT_STREAM__H_
diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp
index 118390c..935e2c7 100644
--- a/src/profile_manager.cpp
+++ b/src/profile_manager.cpp
@@ -23,14 +23,13 @@
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see .
************************************************************************/
-#include "profile_manager.h"
-#include "profiler/serialized_block.h"
-#include "event_trace_win.h"
+#include
#include
-#include
-
#include
+#include "profiler/serialized_block.h"
+#include "profile_manager.h"
+#include "event_trace_win.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -41,14 +40,16 @@ using namespace profiler;
extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY;
#endif
+extern timestamp_t getCurrentTime();
+
//auto& MANAGER = ProfileManager::instance();
#define MANAGER ProfileManager::instance()
extern "C" {
- PROFILER_API const BaseBlockDescriptor& registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
+ PROFILER_API const BaseBlockDescriptor& registerDescription(bool _enabled, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
{
- return MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color);
+ return MANAGER.addBlockDescriptor(_enabled, _name, _filename, _line, _block_type, _color);
}
PROFILER_API void endBlock()
@@ -109,44 +110,87 @@ SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
//////////////////////////////////////////////////////////////////////////
-BaseBlockDescriptor::BaseBlockDescriptor(block_id_t _id, int _line, block_type_t _block_type, color_t _color)
+BaseBlockDescriptor::BaseBlockDescriptor(block_id_t _id, bool _enabled, 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(true)
+ , m_enabled(_enabled)
{
}
-BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, block_id_t _id, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
- : BaseBlockDescriptor(_id, _line, _block_type, _color)
+BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, 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)
, m_name(_name)
, m_filename(_filename)
{
_used_mem += sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2;
}
+BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, 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)
+ , m_name(_name)
+ , m_filename(_filename)
+{
+ _used_mem += sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2;
+}
+
+void BlockDescriptor::setId(block_id_t _id)
+{
+ m_id = _id;
+}
+
+BlockDescRef::~BlockDescRef()
+{
+ MANAGER.markExpired(m_desc.id());
+}
+
//////////////////////////////////////////////////////////////////////////
void ThreadStorage::storeBlock(const profiler::Block& block)
{
+#if EASY_MEASURE_STORAGE_EXPAND != 0
+ static const auto desc = MANAGER.addBlockDescriptor(EASY_STORAGE_EXPAND_ENABLED, "EasyProfiler.ExpandStorage", __FILE__, __LINE__, profiler::BLOCK_TYPE_BLOCK, profiler::colors::White);
+#endif
+
auto name_length = static_cast(strlen(block.name()));
auto size = static_cast(sizeof(BaseBlockData) + name_length + 1);
- auto data = blocks.alloc.allocate(size);
- ::new (static_cast(data)) SerializedBlock(block, name_length);
+
+#if EASY_MEASURE_STORAGE_EXPAND != 0
+ const bool expanded = desc.enabled() && blocks.closedList.need_expand(size);
+ profiler::Block b(0ULL, desc.id(), "");
+ if (expanded) b.start();
+#endif
+
+ auto data = blocks.closedList.allocate(size);
+
+#if EASY_MEASURE_STORAGE_EXPAND != 0
+ if (expanded) b.finish();
+#endif
+
+ ::new (data) SerializedBlock(block, name_length);
blocks.usedMemorySize += size;
- blocks.closedList.emplace_back(reinterpret_cast(data));
+
+#if EASY_MEASURE_STORAGE_EXPAND != 0
+ if (expanded)
+ {
+ name_length = 0;
+ size = static_cast(sizeof(BaseBlockData) + 1);
+ data = blocks.closedList.allocate(size);
+ ::new (data) SerializedBlock(b, name_length);
+ blocks.usedMemorySize += size;
+ }
+#endif
}
void ThreadStorage::storeCSwitch(const profiler::Block& block)
{
auto name_length = static_cast(strlen(block.name()));
auto size = static_cast(sizeof(BaseBlockData) + name_length + 1);
- auto data = sync.alloc.allocate(size);
- ::new (static_cast(data)) SerializedBlock(block, name_length);
+ auto data = sync.closedList.allocate(size);
+ ::new (data) SerializedBlock(block, name_length);
sync.usedMemorySize += size;
- sync.closedList.emplace_back(reinterpret_cast(data));
}
void ThreadStorage::clearClosed()
@@ -159,25 +203,9 @@ void ThreadStorage::clearClosed()
EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
-// #ifdef _WIN32
-// LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL;
-// LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
-// {
-// std::ofstream testexp("TEST_EXP.txt", std::fstream::binary);
-// testexp.write("APPLICATION CRASHED!", strlen("APPLICATION CRASHED!"));
-//
-// EasyEventTracer::instance().disable();
-// if (PREVIOUS_FILTER)
-// return PREVIOUS_FILTER(ExceptionInfo);
-// return EXCEPTION_CONTINUE_SEARCH;
-// }
-// #endif
-
ProfileManager::ProfileManager()
{
-// #ifdef _WIN32
-// PREVIOUS_FILTER = SetUnhandledExceptionFilter(easyTopLevelExceptionFilter);
-// #endif
+ m_expiredDescriptors.reserve(1024U);
}
ProfileManager::~ProfileManager()
@@ -197,6 +225,28 @@ ProfileManager& ProfileManager::instance()
return m_profileManager;
}
+void ProfileManager::markExpired(profiler::block_id_t _id)
+{
+ // Mark block descriptor as expired (descriptor may become expired if it's .dll/.so have been unloaded during application execution).
+ // We can not delete this descriptor now, because we need to send/write all collected data first.
+
+ guard_lock_t lock(m_storedSpin);
+ m_expiredDescriptors.push_back(_id);
+}
+
+ThreadStorage& ProfileManager::threadStorage(profiler::thread_id_t _thread_id)
+{
+ guard_lock_t lock(m_spin);
+ return m_threads[_thread_id];
+}
+
+ThreadStorage* ProfileManager::findThreadStorage(profiler::thread_id_t _thread_id)
+{
+ guard_lock_t lock(m_spin);
+ auto it = m_threads.find(_thread_id);
+ return it != m_threads.end() ? &it->second : nullptr;
+}
+
void ProfileManager::storeBlock(const profiler::BaseBlockDescriptor& _desc, const char* _runtimeName)
{
if (!m_isEnabled || !_desc.enabled())
@@ -226,7 +276,7 @@ void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profil
{
auto ts = findThreadStorage(_thread_id);
if (ts != nullptr)
- ts->sync.openedList.emplace(_time, _id, true, "");
+ ts->sync.openedList.emplace(_time, _id, "");
}
void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
@@ -234,7 +284,7 @@ void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profil
auto ts = findThreadStorage(_thread_id);
if (ts != nullptr)
{
- profiler::Block b(_time, _id, true, "");
+ profiler::Block b(_time, _id, "");
b.finish(_time);
ts->storeCSwitch(b);
}
@@ -279,39 +329,16 @@ void ProfileManager::setEnabled(bool isEnable)
//////////////////////////////////////////////////////////////////////////
-class FileWriter final
-{
- std::ofstream m_file;
-
-public:
-
- explicit FileWriter(const char* _filename) : m_file(_filename, std::fstream::binary) { }
-
- template void write(const char* _data, T _size) {
- m_file.write(_data, _size);
- }
-
- template void write(const T& _data) {
- m_file.write((const char*)&_data, sizeof(T));
- }
-
- void writeBlock(const profiler::SerializedBlock* _block)
- {
- auto sz = static_cast(sizeof(BaseBlockData) + strlen(_block->name()) + 1);
- write(sz);
- write(_block->data(), sz);
- }
-};
-
-//////////////////////////////////////////////////////////////////////////
-
-uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
+uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
{
const bool wasEnabled = m_isEnabled;
if (wasEnabled)
::profiler::setEnabled(false);
+
#ifndef _WIN32
+ // Read thread context switch events from temporary file
+
uint64_t timestamp;
uint32_t thread_from, thread_to;
@@ -319,19 +346,16 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
if(infile.is_open())
{
- static const auto desc = addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
+ static const auto& desc = addBlockDescriptor(true, "OS.ContextSwitch", __FILE__, __LINE__, profiler::BLOCK_TYPE_CONTEXT_SWITCH, profiler::colors::White);
while (infile >> timestamp >> thread_from >> thread_to)
{
- beginContextSwitch(thread_from, timestamp, desc);
+ beginContextSwitch(thread_from, timestamp, desc.id());
endContextSwitch(thread_to, timestamp);
}
}
-
#endif
-
- FileWriter of(filename);
-
+ // 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)
@@ -341,53 +365,80 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
blocks_number += static_cast(t.blocks.closedList.size()) + static_cast(t.sync.closedList.size());
}
+ // Write CPU frequency to let GUI calculate real time value from CPU clocks
#ifdef _WIN32
- of.write(CPU_FREQUENCY);
+ _outputStream.write(CPU_FREQUENCY);
#else
- of.write(0LL);
+ _outputStream.write(0LL);
#endif
- of.write(blocks_number);
- of.write(usedMemorySize);
- of.write(static_cast(m_descriptors.size()));
- of.write(m_usedMemorySize);
+ // Write blocks number and used memory size
+ _outputStream.write(blocks_number);
+ _outputStream.write(usedMemorySize);
+ _outputStream.write(static_cast(m_descriptors.size()));
+ _outputStream.write(m_usedMemorySize);
+ // Write block descriptors
for (const auto descriptor : m_descriptors)
{
const auto name_size = static_cast(strlen(descriptor->name()) + 1);
const auto filename_size = static_cast(strlen(descriptor->file()) + 1);
const auto size = static_cast(sizeof(profiler::SerializedBlockDescriptor) + name_size + filename_size);
- of.write(size);
- of.write(*descriptor);
- of.write(name_size);
- of.write(descriptor->name(), name_size);
- of.write(descriptor->file(), filename_size);
+ _outputStream.write(size);
+ _outputStream.write(*descriptor);
+ _outputStream.write(name_size);
+ _outputStream.write(descriptor->name(), name_size);
+ _outputStream.write(descriptor->file(), filename_size);
}
+ // Write blocks and context switch events for each thread
for (auto& thread_storage : m_threads)
{
auto& t = thread_storage.second;
- of.write(thread_storage.first);
+ _outputStream.write(thread_storage.first);
- of.write(static_cast(t.sync.closedList.size()));
- for (auto b : t.sync.closedList)
- of.writeBlock(b);
+ _outputStream.write(t.sync.closedList.size());
+ t.sync.closedList.serialize(_outputStream);
- of.write(static_cast(t.blocks.closedList.size()));
- for (auto b : t.blocks.closedList)
- of.writeBlock(b);
+ _outputStream.write(t.blocks.closedList.size());
+ t.blocks.closedList.serialize(_outputStream);
t.clearClosed();
}
-// if (wasEnabled)
-// ::profiler::setEnabled(true);
+ if (!m_expiredDescriptors.empty())
+ {
+ // Remove all expired block descriptors (descriptor may become expired if it's .dll/.so have been unloaded during application execution)
+
+ std::sort(m_expiredDescriptors.begin(), m_expiredDescriptors.end());
+ for (auto it = m_expiredDescriptors.rbegin(), rend = m_expiredDescriptors.rend(); it != rend; ++it)
+ {
+ auto id = *it;
+ delete m_descriptors[id];
+ m_descriptors.erase(m_descriptors.begin() + id);
+ }
+ m_expiredDescriptors.clear();
+ }
+
+ //if (wasEnabled)
+ // ::profiler::setEnabled(true);
return blocks_number;
}
+uint32_t ProfileManager::dumpBlocksToFile(const char* _filename)
+{
+ profiler::OStream outputStream;
+ const auto blocksNumber = dumpBlocksToStream(outputStream);
+
+ std::ofstream of(_filename, std::fstream::binary);
+ of << outputStream.stream().str();
+
+ return blocksNumber;
+}
+
const char* ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line)
{
if (THREAD_STORAGE == nullptr)
@@ -397,7 +448,7 @@ const char* ProfileManager::setThreadName(const char* name, const char* filename
if (!THREAD_STORAGE->named)
{
- const auto& desc = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Black);
+ const auto& desc = addBlockDescriptor(true, _funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Black);
profiler::Block b(desc, name);
b.finish(b.begin());
diff --git a/src/profile_manager.h b/src/profile_manager.h
index 2b54726..9e40153 100644
--- a/src/profile_manager.h
+++ b/src/profile_manager.h
@@ -16,14 +16,13 @@ You should have received a copy of the GNU General Public License
along with this program.If not, see .
**/
-#ifndef ___PROFILER____MANAGER____H______
-#define ___PROFILER____MANAGER____H______
+#ifndef EASY_PROFILER____MANAGER____H______
+#define EASY_PROFILER____MANAGER____H______
#include "profiler/profiler.h"
-
#include "spin_lock.h"
-
-#include
+#include "outstream.h"
+//#include "hashed_cstr.h"
#include