diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h
index 55e9b74..42c2887 100644
--- a/include/profiler/profiler.h
+++ b/include/profiler/profiler.h
@@ -20,7 +20,23 @@ along with this program.If not, see .
#define EASY_PROFILER____H_______
#ifdef _WIN32
-#define __func__ __FUNCTION__
+# 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__)
+# 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!
+
+#ifndef EASY_THREAD_LOCAL
+# define EASY_THREAD_LOCAL thread_local
+# define EASY_THREAD_LOCAL_CPP11
#endif
#if defined ( __clang__ )
@@ -80,9 +96,9 @@ Block will be automatically completed by destructor.
\ingroup profiler
*/
#define EASY_BLOCK(name, ...)\
- static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
+ static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
- ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\
+ ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro of beginning of block with function name and custom color.
@@ -105,9 +121,9 @@ Name of the block automatically created with function name.
\ingroup profiler
*/
#define EASY_FUNCTION(...)\
- static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(__func__, __FILE__, __LINE__,\
+ static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\
::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
- ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), "");\
+ ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), "");\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro of completion of last nearest open block.
@@ -145,9 +161,9 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION.
\ingroup profiler
*/
#define EASY_EVENT(name, ...)\
- static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
+ static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\
- ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\
+ ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro enabling profiler
@@ -166,10 +182,15 @@ If this thread has been already named then nothing changes.
\ingroup profiler
*/
-#ifdef _WIN32
-#define EASY_THREAD(name) ::profiler::setThreadName(name, __FILE__, __func__, __LINE__);
+#ifdef EASY_THREAD_LOCAL_CPP11
+#define EASY_THREAD(name)\
+ EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = \
+ ::profiler::setThreadName(name, __FILE__, __func__, __LINE__);
#else
-#define EASY_THREAD(name) thread_local static const ::profiler::ThreadNameSetter EASY_TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name, __FILE__, __func__, __LINE__);
+#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__);
#endif
/** Macro of naming main thread.
@@ -211,20 +232,9 @@ class ThreadStorage;
namespace profiler {
class Block;
- class StaticBlockDescriptor;
-
- extern "C"{
- void PROFILER_API beginBlock(Block& _block);
- void PROFILER_API endBlock();
- void PROFILER_API setEnabled(bool isEnable);
- uint32_t PROFILER_API dumpBlocksToFile(const char* filename);
- void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line);
- void PROFILER_API setContextSwitchLogFilename(const char* name);
- PROFILER_API const char* getContextSwitchLogFilename();
- }
- typedef uint64_t timestamp_t;
- typedef uint32_t thread_id_t;
+ typedef uint64_t timestamp_t;
+ typedef uint32_t thread_id_t;
typedef uint32_t block_id_t;
enum BlockType : uint8_t
@@ -237,6 +247,17 @@ namespace profiler {
BLOCK_TYPES_NUMBER
};
typedef BlockType block_type_t;
+
+ extern "C" {
+ PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor);
+ 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
@@ -322,28 +343,6 @@ namespace profiler {
//////////////////////////////////////////////////////////////////////
- class PROFILER_API StaticBlockDescriptor final
- {
- block_id_t m_id;
-
- public:
-
- StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor);
- inline block_id_t id() const { return m_id; }
- };
-
-#ifndef _WIN32
- struct PROFILER_API ThreadNameSetter final
- {
- ThreadNameSetter(const char* _name, const char* _filename, const char* _funcname, int _line)
- {
- setThreadName(_name, _filename, _funcname, _line);
- }
- };
-#endif
-
- //////////////////////////////////////////////////////////////////////
-
} // END of namespace profiler.
#if defined ( __clang__ )
diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp
index 2480434..804d4f3 100644
--- a/src/event_trace_win.cpp
+++ b/src/event_trace_win.cpp
@@ -48,9 +48,9 @@ namespace profiler {
auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData);
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
- static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
- MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId);
- MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time);
+ static const auto desc = MANAGER.addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
+ MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, desc);
+ MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time);
}
//////////////////////////////////////////////////////////////////////////
diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp
index 4dc6bb5..9b482c0 100644
--- a/src/profile_manager.cpp
+++ b/src/profile_manager.cpp
@@ -10,16 +10,6 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-#define EASY_INTERNAL_BLOCK(name, easyType, CODE) CODE
-//#define EASY_INTERNAL_BLOCK(name, easyType, CODE)\
-// static const profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(name, __FILE__, __LINE__, easyType, profiler::colors::White);\
-// ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(easyType, EASY_UNIQUE_DESC(__LINE__).id(), "");\
-// CODE\
-// EASY_UNIQUE_BLOCK(__LINE__).finish();\
-// thread_storage.storeBlock(EASY_UNIQUE_BLOCK(__LINE__))
-
-//////////////////////////////////////////////////////////////////////////
-
using namespace profiler;
#ifdef _WIN32
@@ -29,14 +19,19 @@ extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY;
//auto& MANAGER = ProfileManager::instance();
#define MANAGER ProfileManager::instance()
-extern "C"{
+extern "C" {
- void PROFILER_API endBlock()
+ PROFILER_API block_id_t registerDescription(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);
+ }
+
+ PROFILER_API void endBlock()
{
MANAGER.endBlock();
}
- void PROFILER_API setEnabled(bool isEnable)
+ PROFILER_API void setEnabled(bool isEnable)
{
MANAGER.setEnabled(isEnable);
#ifdef _WIN32
@@ -47,22 +42,22 @@ extern "C"{
#endif
}
- void PROFILER_API beginBlock(Block& _block)
+ PROFILER_API void beginBlock(Block& _block)
{
MANAGER.beginBlock(_block);
}
- uint32_t PROFILER_API dumpBlocksToFile(const char* filename)
+ PROFILER_API uint32_t dumpBlocksToFile(const char* filename)
{
return MANAGER.dumpBlocksToFile(filename);
}
- void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line)
+ PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line)
{
return MANAGER.setThreadName(name, filename, _funcname, line);
}
- void PROFILER_API setContextSwitchLogFilename(const char* name)
+ PROFILER_API void setContextSwitchLogFilename(const char* name)
{
return MANAGER.setContextSwitchLogFilename(name);
}
@@ -84,12 +79,6 @@ SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
//////////////////////////////////////////////////////////////////////////
-StaticBlockDescriptor::StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
- : m_id(MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color))
-{
-
-}
-
BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color)
: m_line(_line)
, m_type(_block_type)
@@ -136,6 +125,8 @@ 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)
@@ -175,32 +166,30 @@ void ProfileManager::beginBlock(Block& _block)
if (!m_isEnabled)
return;
- EASY_INTERNAL_BLOCK("Easy.Spin", profiler::BLOCK_TYPE_BLOCK,\
- auto& thread_storage = threadStorage(getCurrentThreadId());\
- );
+ if (THREAD_STORAGE == nullptr)
+ THREAD_STORAGE = &threadStorage(getCurrentThreadId());
- EASY_INTERNAL_BLOCK("Easy.Insert", profiler::BLOCK_TYPE_BLOCK,\
- if (!_block.isFinished())
- thread_storage.blocks.openedList.emplace(_block);
- else
- thread_storage.storeBlock(_block);\
- );
+ if (!_block.isFinished())
+ THREAD_STORAGE->blocks.openedList.emplace(_block);
+ else
+ THREAD_STORAGE->storeBlock(_block);
}
-void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id)
+void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
{
- auto thread_storage = _threadStorage(_thread_id);
- if (thread_storage != nullptr)
- thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
+ auto ts = findThreadStorage(_thread_id);
+ if (ts != nullptr)
+ ts->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
}
-void ProfileManager::_cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id)
+void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
{
- auto thread_storage = _threadStorage(_thread_id);
- if (thread_storage != nullptr){
+ auto ts = findThreadStorage(_thread_id);
+ if (ts != nullptr)
+ {
profiler::Block lastBlock(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
lastBlock.finish(_time);
- thread_storage->storeCSwitch(lastBlock);
+ ts->storeCSwitch(lastBlock);
}
}
@@ -209,29 +198,28 @@ void ProfileManager::endBlock()
if (!m_isEnabled)
return;
- auto& thread_storage = threadStorage(getCurrentThreadId());
- if (thread_storage.blocks.openedList.empty())
+ if (THREAD_STORAGE->blocks.openedList.empty())
return;
- Block& lastBlock = thread_storage.blocks.openedList.top();
+ Block& lastBlock = THREAD_STORAGE->blocks.openedList.top();
if (!lastBlock.isFinished())
lastBlock.finish();
- thread_storage.storeBlock(lastBlock);
- thread_storage.blocks.openedList.pop();
+ THREAD_STORAGE->storeBlock(lastBlock);
+ THREAD_STORAGE->blocks.openedList.pop();
}
-void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime)
+void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime)
{
- auto thread_storage = _threadStorage(_thread_id);
- if (thread_storage == nullptr || thread_storage->sync.openedList.empty())
+ auto ts = findThreadStorage(_thread_id);
+ if (ts == nullptr || ts->sync.openedList.empty())
return;
- Block& lastBlock = thread_storage->sync.openedList.top();
+ Block& lastBlock = ts->sync.openedList.top();
lastBlock.finish(_endtime);
- thread_storage->storeCSwitch(lastBlock);
- thread_storage->sync.openedList.pop();
+ ts->storeCSwitch(lastBlock);
+ ts->sync.openedList.pop();
}
void ProfileManager::setEnabled(bool isEnable)
@@ -283,11 +271,11 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
if(infile.is_open())
{
- while (infile >> timestamp >> thread_from >> thread_to )
+ static const auto desc = addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
+ while (infile >> timestamp >> thread_from >> thread_to)
{
- static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
- _cswitchBeginBlock(timestamp, desc.id(), thread_from);
- _cswitchEndBlock(thread_to, timestamp);
+ beginContextSwitch(thread_from, timestamp, desc);
+ endContextSwitch(thread_to, timestamp);
}
}
@@ -385,15 +373,22 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
return blocks_number;
}
-void ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line)
+const char* ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line)
{
- auto& thread_storage = threadStorage(getCurrentThreadId());
- if (thread_storage.named)
- return;
+ if (THREAD_STORAGE == nullptr)
+ {
+ THREAD_STORAGE = &threadStorage(getCurrentThreadId());
+ }
- const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random);
- thread_storage.storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name));
- thread_storage.named = true;
+ if (!THREAD_STORAGE->named)
+ {
+ const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random);
+ THREAD_STORAGE->storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name));
+ THREAD_STORAGE->name = name;
+ THREAD_STORAGE->named = true;
+ }
+
+ return THREAD_STORAGE->name.c_str();
}
//////////////////////////////////////////////////////////////////////////
diff --git a/src/profile_manager.h b/src/profile_manager.h
index 7244e43..2408471 100644
--- a/src/profile_manager.h
+++ b/src/profile_manager.h
@@ -26,8 +26,8 @@ along with this program.If not, see .
#include
#include