mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-26 16:11:02 +08:00
(Core) Major update (file format NOT affected). Description:
1) Added macro EASY_CONST_NAME(name) to make possible to force EasyProfiler think that given block name is const and not changed during application execution (this rely to compile-time strings saved into a run-time variable); 2) Starting from now, EasyProfiler will not store partially finished frames - first, this means that profiler enabled during frame execution will skip all blocks from this frame, and second, this means that when dumping profiled information profiler will wait until all frames finish before dumping blocks.
This commit is contained in:
parent
5977dbda11
commit
e9bed4c839
@ -91,7 +91,8 @@ Block will be automatically completed by destructor.
|
||||
*/
|
||||
# define EASY_BLOCK(name, ...)\
|
||||
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
|
||||
EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__)));\
|
||||
EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__),\
|
||||
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
|
||||
::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
|
||||
|
||||
@ -121,7 +122,7 @@ Name of the block automatically created with function name.
|
||||
*/
|
||||
# define EASY_FUNCTION(...)\
|
||||
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
|
||||
EASY_UNIQUE_LINE_ID, __func__, __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__)));\
|
||||
EASY_UNIQUE_LINE_ID, __func__, __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__), false));\
|
||||
::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
|
||||
|
||||
@ -162,7 +163,8 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION.
|
||||
# define EASY_EVENT(name, ...)\
|
||||
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
|
||||
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
|
||||
__FILE__, __LINE__, ::profiler::BLOCK_TYPE_EVENT, ::profiler::extract_color(__VA_ARGS__)));\
|
||||
__FILE__, __LINE__, ::profiler::BLOCK_TYPE_EVENT, ::profiler::extract_color(__VA_ARGS__),\
|
||||
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
|
||||
::profiler::storeEvent(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));
|
||||
|
||||
/** Macro for enabling profiler.
|
||||
@ -515,7 +517,7 @@ namespace profiler {
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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);
|
||||
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, bool _copyName = false);
|
||||
|
||||
/** Stores event in the blocks list.
|
||||
|
||||
@ -639,7 +641,7 @@ namespace profiler {
|
||||
|
||||
}
|
||||
#else
|
||||
inline const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t)
|
||||
inline const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t, bool = false)
|
||||
{ return reinterpret_cast<const BaseBlockDescriptor*>(0xbad); }
|
||||
inline void endBlock() { }
|
||||
inline void setEnabled(bool) { }
|
||||
|
@ -86,22 +86,46 @@ namespace profiler {
|
||||
|
||||
namespace profiler {
|
||||
|
||||
template <const bool> struct NameSwitch;
|
||||
|
||||
class ForceConstStr EASY_FINAL {
|
||||
friend NameSwitch<true>;
|
||||
friend NameSwitch<false>;
|
||||
|
||||
const char* c_str;
|
||||
|
||||
ForceConstStr() = delete;
|
||||
ForceConstStr(const ForceConstStr&) = delete;
|
||||
ForceConstStr(ForceConstStr&&) = delete;
|
||||
ForceConstStr& operator = (const ForceConstStr&) = delete;
|
||||
ForceConstStr& operator = (ForceConstStr&&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
ForceConstStr(const char* _str) : c_str(_str) {}
|
||||
ForceConstStr(const ::std::string& _str) : c_str(_str.c_str()) {}
|
||||
};
|
||||
|
||||
template <const bool IS_REF> struct NameSwitch EASY_FINAL {
|
||||
static const char* runtime_name(const char* name) { return name; }
|
||||
static const char* runtime_name(const std::string& name) { return name.c_str(); }
|
||||
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
|
||||
static const char* runtime_name(const ForceConstStr&) { return ""; }
|
||||
|
||||
template <class T>
|
||||
static const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
|
||||
static const char* compiletime_name(const char*, const char* autoGeneratedName) { return autoGeneratedName; }
|
||||
static const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
|
||||
};
|
||||
|
||||
template <> struct NameSwitch<true> EASY_FINAL {
|
||||
static const char* runtime_name(const char*) { return ""; }
|
||||
static const char* runtime_name(const std::string& name) { return name.c_str(); }
|
||||
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
|
||||
static const char* runtime_name(const ForceConstStr&) { return ""; }
|
||||
|
||||
template <class T>
|
||||
static const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
|
||||
static const char* compiletime_name(const char* name, const char*) { return name; }
|
||||
static const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
|
||||
};
|
||||
|
||||
//***********************************************
|
||||
@ -160,6 +184,11 @@ namespace profiler {
|
||||
# define EASY_UNIQUE_LINE_ID __FILE__ ":" EASY_STRINGIFICATION(__LINE__)
|
||||
# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID)
|
||||
# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
|
||||
# define EASY_CONST_NAME(name) ::profiler::ForceConstStr(name)
|
||||
|
||||
#else
|
||||
|
||||
# define EASY_CONST_NAME(name)
|
||||
|
||||
#endif // BUILD_WITH_EASY_PROFILER
|
||||
|
||||
|
@ -66,9 +66,9 @@ using namespace profiler;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
|
||||
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MINOR) "." \
|
||||
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_PATCH)
|
||||
# define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
|
||||
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MINOR) "." \
|
||||
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_PATCH)
|
||||
|
||||
# define EASY_VERSION_INT(v_major, v_minor, v_patch) ((static_cast<uint32_t>(v_major) << 24) | (static_cast<uint32_t>(v_minor) << 16) | static_cast<uint32_t>(v_patch))
|
||||
extern const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y';
|
||||
@ -77,6 +77,12 @@ extern const uint32_t EASY_CURRENT_VERSION = EASY_VERSION_INT(EASY_PROFILER_VERS
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
# define EASY_PROF_DISABLED 0
|
||||
# define EASY_PROF_ENABLED 1
|
||||
# define EASY_PROF_DUMP 2
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//auto& MANAGER = ProfileManager::instance();
|
||||
# define MANAGER ProfileManager::instance()
|
||||
const uint8_t FORCE_ON_FLAG = profiler::FORCE_ON & ~profiler::ON;
|
||||
@ -88,6 +94,7 @@ decltype(LARGE_INTEGER::QuadPart) const CPU_FREQUENCY = ([](){ LARGE_INTEGER fre
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
|
||||
EASY_THREAD_LOCAL static int32_t THREAD_STACK_SIZE = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -127,9 +134,9 @@ EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
|
||||
extern "C" {
|
||||
|
||||
#if !defined(EASY_PROFILER_API_DISABLED)
|
||||
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)
|
||||
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, bool _copyName)
|
||||
{
|
||||
return MANAGER.addBlockDescriptor(_status, _autogenUniqueId, _name, _filename, _line, _block_type, _color);
|
||||
return MANAGER.addBlockDescriptor(_status, _autogenUniqueId, _name, _filename, _line, _block_type, _color, _copyName);
|
||||
}
|
||||
|
||||
PROFILER_API void endBlock()
|
||||
@ -201,7 +208,7 @@ extern "C" {
|
||||
return MANAGER.stopListen();
|
||||
}
|
||||
#else
|
||||
PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t) { return reinterpret_cast<const BaseBlockDescriptor*>(0xbad); }
|
||||
PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t, bool) { return reinterpret_cast<const BaseBlockDescriptor*>(0xbad); }
|
||||
PROFILER_API void endBlock() { }
|
||||
PROFILER_API void setEnabled(bool) { }
|
||||
PROFILER_API void storeEvent(const BaseBlockDescriptor*, const char*) { }
|
||||
@ -293,17 +300,15 @@ class BlockDescriptor : public BaseBlockDescriptor
|
||||
{
|
||||
friend ProfileManager;
|
||||
|
||||
EASY_BLOCK_DESC_STRING 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
|
||||
EASY_BLOCK_DESC_STRING m_filename; ///< Source file name where this block is declared
|
||||
uint16_t m_size; ///< Used memory size
|
||||
EASY_BLOCK_DESC_STRING 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
|
||||
|
||||
public:
|
||||
|
||||
BlockDescriptor(block_id_t _id, EasyBlockStatus _status, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
||||
: BaseBlockDescriptor(_id, _status, _line, _block_type, _color)
|
||||
, m_name(_name)
|
||||
, m_filename(_filename)
|
||||
, m_size(static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2))
|
||||
, m_name(_name)
|
||||
{
|
||||
}
|
||||
|
||||
@ -334,6 +339,7 @@ ThreadStorage::ThreadStorage() : id(getCurrentThreadId()), allowChildren(true),
|
||||
|
||||
{
|
||||
expired = ATOMIC_VAR_INIT(0);
|
||||
frame = ATOMIC_VAR_INIT(false);
|
||||
}
|
||||
|
||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
@ -402,6 +408,7 @@ ThreadGuard::~ThreadGuard()
|
||||
{
|
||||
bool isMarked = false;
|
||||
EASY_EVENT_RES(isMarked, "ThreadFinished", profiler::colors::Dark, ::profiler::FORCE_ON);
|
||||
THREAD_STORAGE->frame.store(false, std::memory_order_release);
|
||||
THREAD_STORAGE->expired.store(isMarked ? 2 : 1, std::memory_order_release);
|
||||
THREAD_STORAGE = nullptr;
|
||||
}
|
||||
@ -420,7 +427,7 @@ ProfileManager::ProfileManager() :
|
||||
, m_beginTime(0)
|
||||
, m_endTime(0)
|
||||
{
|
||||
m_isEnabled = ATOMIC_VAR_INIT(false);
|
||||
m_profilerStatus = ATOMIC_VAR_INIT(EASY_PROF_DISABLED);
|
||||
m_isEventTracingEnabled = ATOMIC_VAR_INIT(EASY_OPTION_EVENT_TRACING_ENABLED);
|
||||
m_isAlreadyListening = ATOMIC_VAR_INIT(false);
|
||||
m_stopListen = ATOMIC_VAR_INIT(false);
|
||||
@ -436,8 +443,15 @@ ProfileManager::~ProfileManager()
|
||||
stopListen();
|
||||
#endif
|
||||
|
||||
for (auto desc : m_descriptors)
|
||||
for (auto desc : m_descriptors) {
|
||||
#if EASY_BLOCK_DESC_FULL_COPY == 0
|
||||
if (desc)
|
||||
desc->~BlockDescriptor();
|
||||
free(desc);
|
||||
#else
|
||||
delete desc;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef EASY_MAGIC_STATIC_CPP11
|
||||
@ -482,7 +496,8 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
|
||||
const char* _filename,
|
||||
int _line,
|
||||
block_type_t _block_type,
|
||||
color_t _color)
|
||||
color_t _color,
|
||||
bool _copyName)
|
||||
{
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
|
||||
@ -491,8 +506,28 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
|
||||
if (it != m_descriptorsMap.end())
|
||||
return m_descriptors[it->second];
|
||||
|
||||
const auto nameLen = strlen(_name);
|
||||
m_usedMemorySize += sizeof(profiler::SerializedBlockDescriptor) + nameLen + strlen(_filename) + 2;
|
||||
|
||||
#if EASY_BLOCK_DESC_FULL_COPY == 0
|
||||
BlockDescriptor* desc = nullptr;
|
||||
|
||||
if (_copyName)
|
||||
{
|
||||
void* data = malloc(sizeof(BlockDescriptor) + nameLen + 1);
|
||||
char* name = reinterpret_cast<char*>(data) + sizeof(BlockDescriptor);
|
||||
strncpy(name, _name, nameLen);
|
||||
desc = ::new (data)BlockDescriptor(static_cast<block_id_t>(m_descriptors.size()), _defaultStatus, name, _filename, _line, _block_type, _color);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* data = malloc(sizeof(BlockDescriptor));
|
||||
desc = ::new (data)BlockDescriptor(static_cast<block_id_t>(m_descriptors.size()), _defaultStatus, _name, _filename, _line, _block_type, _color);
|
||||
}
|
||||
#else
|
||||
auto desc = new BlockDescriptor(static_cast<block_id_t>(m_descriptors.size()), _defaultStatus, _name, _filename, _line, _block_type, _color);
|
||||
m_usedMemorySize += desc->m_size;
|
||||
#endif
|
||||
|
||||
m_descriptors.emplace_back(desc);
|
||||
m_descriptorsMap.emplace(key, desc->id());
|
||||
|
||||
@ -503,11 +538,19 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
|
||||
|
||||
bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
|
||||
{
|
||||
if (!m_isEnabled.load(std::memory_order_acquire) || !(_desc->m_status & profiler::ON))
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
if (state == EASY_PROF_DISABLED || !(_desc->m_status & profiler::ON))
|
||||
return false;
|
||||
|
||||
if (THREAD_STORAGE == nullptr)
|
||||
if (state == EASY_PROF_DUMP)
|
||||
{
|
||||
if (THREAD_STORAGE == nullptr || THREAD_STORAGE->blocks.openedList.empty())
|
||||
return false;
|
||||
}
|
||||
else if (THREAD_STORAGE == nullptr)
|
||||
{
|
||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||
}
|
||||
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
if (!THREAD_STORAGE->allowChildren && !(_desc->m_status & FORCE_ON_FLAG))
|
||||
@ -576,11 +619,29 @@ void ProfileManager::storeBlockForce2(ThreadStorage& _registeredThread, const pr
|
||||
|
||||
void ProfileManager::beginBlock(Block& _block)
|
||||
{
|
||||
if (!m_isEnabled.load(std::memory_order_acquire))
|
||||
if (++THREAD_STACK_SIZE > 1)
|
||||
return;
|
||||
|
||||
if (THREAD_STORAGE == nullptr)
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
if (state == EASY_PROF_DISABLED)
|
||||
return;
|
||||
|
||||
THREAD_STACK_SIZE = 0;
|
||||
bool empty = true;
|
||||
if (state == EASY_PROF_DUMP)
|
||||
{
|
||||
if (THREAD_STORAGE == nullptr || THREAD_STORAGE->blocks.openedList.empty())
|
||||
return;
|
||||
empty = false;
|
||||
}
|
||||
else if (THREAD_STORAGE == nullptr)
|
||||
{
|
||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||
}
|
||||
else
|
||||
{
|
||||
empty = THREAD_STORAGE->blocks.openedList.empty();
|
||||
}
|
||||
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
if (THREAD_STORAGE->allowChildren)
|
||||
@ -602,6 +663,8 @@ void ProfileManager::beginBlock(Block& _block)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (empty)
|
||||
THREAD_STORAGE->frame.store(true, std::memory_order_release);
|
||||
THREAD_STORAGE->blocks.openedList.emplace(_block);
|
||||
}
|
||||
|
||||
@ -618,9 +681,10 @@ void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profil
|
||||
|
||||
void ProfileManager::endBlock()
|
||||
{
|
||||
if (!m_isEnabled.load(std::memory_order_acquire))
|
||||
if (--THREAD_STACK_SIZE > 0 || m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_DISABLED)
|
||||
return;
|
||||
|
||||
THREAD_STACK_SIZE = 0;
|
||||
if (THREAD_STORAGE == nullptr || THREAD_STORAGE->blocks.openedList.empty())
|
||||
return;
|
||||
|
||||
@ -637,9 +701,12 @@ void ProfileManager::endBlock()
|
||||
}
|
||||
|
||||
THREAD_STORAGE->blocks.openedList.pop();
|
||||
const bool empty = THREAD_STORAGE->blocks.openedList.empty();
|
||||
if (empty)
|
||||
THREAD_STORAGE->frame.store(false, std::memory_order_release);
|
||||
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
THREAD_STORAGE->allowChildren = THREAD_STORAGE->blocks.openedList.empty() || !(THREAD_STORAGE->blocks.openedList.top().get().m_status & profiler::OFF_RECURSIVE);
|
||||
THREAD_STORAGE->allowChildren = empty || !(THREAD_STORAGE->blocks.openedList.top().get().m_status & profiler::OFF_RECURSIVE);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -665,37 +732,40 @@ void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, processi
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ProfileManager::setEnabled(bool isEnable, bool _setTime)
|
||||
void ProfileManager::enableEventTracer()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_isEventTracingEnabled.load(std::memory_order_acquire))
|
||||
EasyEventTracer::instance().enable(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProfileManager::disableEventTracer()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EasyEventTracer::instance().disable();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProfileManager::setEnabled(bool isEnable)
|
||||
{
|
||||
guard_lock_t lock(m_dumpSpin);
|
||||
|
||||
auto time = getCurrentTime();
|
||||
const bool prev = m_isEnabled.exchange(isEnable, std::memory_order_release);
|
||||
if (prev == isEnable)
|
||||
const auto status = isEnable ? EASY_PROF_ENABLED : EASY_PROF_DISABLED;
|
||||
const auto prev = m_profilerStatus.exchange(status, std::memory_order_release);
|
||||
if (prev == status)
|
||||
return;
|
||||
|
||||
if (isEnable)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_isEventTracingEnabled.load(std::memory_order_acquire))
|
||||
EasyEventTracer::instance().enable(true);
|
||||
#endif
|
||||
|
||||
if (_setTime)
|
||||
{
|
||||
guard_lock_t lk(m_spin);
|
||||
m_beginTime = time;
|
||||
}
|
||||
enableEventTracer();
|
||||
m_beginTime = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EasyEventTracer::instance().disable();
|
||||
#endif
|
||||
|
||||
if (_setTime)
|
||||
{
|
||||
guard_lock_t lk(m_spin);
|
||||
m_endTime = time;
|
||||
}
|
||||
disableEventTracer();
|
||||
m_endTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,9 +776,9 @@ void ProfileManager::setEventTracingEnabled(bool _isEnable)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint8_t ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
||||
char ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
||||
{
|
||||
const uint8_t val = _registeredThread.expired.load(std::memory_order_acquire);
|
||||
const char val = _registeredThread.expired.load(std::memory_order_acquire);
|
||||
if (val != 0)
|
||||
return val;
|
||||
|
||||
@ -724,7 +794,7 @@ uint8_t ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
||||
if (hThread == nullptr || GetExitCodeThread(hThread, &exitCode) == FALSE || exitCode != STILL_ACTIVE)
|
||||
{
|
||||
// Thread has been expired
|
||||
_registeredThread.expired.store(true, std::memory_order_release);
|
||||
_registeredThread.expired.store(1, std::memory_order_release);
|
||||
if (hThread != nullptr)
|
||||
CloseHandle(hThread);
|
||||
return 1;
|
||||
@ -745,28 +815,45 @@ uint8_t ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
||||
uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bool _lockSpin)
|
||||
{
|
||||
const bool wasEnabled = m_isEnabled.load(std::memory_order_acquire);
|
||||
if (_lockSpin)
|
||||
m_dumpSpin.lock();
|
||||
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
|
||||
#ifndef _WIN32
|
||||
const bool eventTracingEnabled = m_isEventTracingEnabled.load(std::memory_order_acquire);
|
||||
#endif
|
||||
|
||||
if (wasEnabled)
|
||||
::profiler::setEnabled(false);
|
||||
if (state == EASY_PROF_ENABLED) {
|
||||
m_profilerStatus.store(EASY_PROF_DUMP, std::memory_order_release);
|
||||
disableEventTracer();
|
||||
m_endTime = getCurrentTime();
|
||||
}
|
||||
|
||||
|
||||
// This is to make sure that no new descriptors or new threads will be
|
||||
// added until we finish sending data.
|
||||
guard_lock_t lock1(m_storedSpin);
|
||||
guard_lock_t lock2(m_spin);
|
||||
//m_spin.lock();
|
||||
// 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));
|
||||
|
||||
// wait for all threads finish opened frames
|
||||
for (auto it = m_threads.begin(), end = m_threads.end(); it != end;)
|
||||
{
|
||||
if (!it->second.frame.load(std::memory_order_acquire))
|
||||
++it;
|
||||
else
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
m_profilerStatus.store(EASY_PROF_DISABLED, std::memory_order_release);
|
||||
m_spin.lock();
|
||||
m_storedSpin.lock();
|
||||
// TODO: think about better solution because this one is not 100% safe...
|
||||
|
||||
const profiler::timestamp_t now = getCurrentTime();
|
||||
@ -800,7 +887,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
||||
auto& t = it->second;
|
||||
uint32_t num = static_cast<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(t.sync.closedList.size());
|
||||
|
||||
const uint8_t expired = checkThreadExpired(t);
|
||||
const char expired = checkThreadExpired(t);
|
||||
if (num == 0 && (expired != 0 || !t.guarded)) {
|
||||
// Remove thread if it contains no profiled information and has been finished or is not guarded.
|
||||
m_threads.erase(it++);
|
||||
@ -911,8 +998,11 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
||||
++it;
|
||||
}
|
||||
|
||||
//if (wasEnabled)
|
||||
// ::profiler::setEnabled(true);
|
||||
m_storedSpin.unlock();
|
||||
m_spin.unlock();
|
||||
|
||||
if (_lockSpin)
|
||||
m_dumpSpin.unlock();
|
||||
|
||||
return blocks_number;
|
||||
}
|
||||
@ -920,7 +1010,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
||||
uint32_t ProfileManager::dumpBlocksToFile(const char* _filename)
|
||||
{
|
||||
profiler::OStream outputStream;
|
||||
const auto blocksNumber = dumpBlocksToStream(outputStream);
|
||||
const auto blocksNumber = dumpBlocksToStream(outputStream, true);
|
||||
|
||||
std::ofstream of(_filename, std::fstream::binary);
|
||||
of << outputStream.stream().str();
|
||||
@ -959,7 +1049,7 @@ const char* ProfileManager::registerThread(const char* name)
|
||||
|
||||
void ProfileManager::setBlockStatus(block_id_t _id, EasyBlockStatus _status)
|
||||
{
|
||||
if (m_isEnabled.load(std::memory_order_acquire))
|
||||
if (m_profilerStatus.load(std::memory_order_acquire) != EASY_PROF_ENABLED)
|
||||
return; // Changing blocks statuses is restricted while profile session is active
|
||||
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
@ -1023,7 +1113,7 @@ void ProfileManager::listen(uint16_t _port)
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
profiler::net::EasyProfilerStatus connectionReply(m_isEnabled.load(std::memory_order_acquire), m_isEventTracingEnabled.load(std::memory_order_acquire), wasLowPriorityET);
|
||||
profiler::net::EasyProfilerStatus connectionReply(m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_ENABLED, m_isEventTracingEnabled.load(std::memory_order_acquire), wasLowPriorityET);
|
||||
bytes = socket.send(&connectionReply, sizeof(connectionReply));
|
||||
hasConnect = bytes > 0;
|
||||
}
|
||||
@ -1061,11 +1151,14 @@ void ProfileManager::listen(uint16_t _port)
|
||||
#endif
|
||||
::profiler::timestamp_t t = 0;
|
||||
EASY_FORCE_EVENT(t, "StartCapture", profiler::colors::Green, profiler::OFF);
|
||||
ProfileManager::setEnabled(true, false);
|
||||
|
||||
m_spin.lock();
|
||||
m_beginTime = t;
|
||||
m_spin.unlock();
|
||||
m_dumpSpin.lock();
|
||||
const auto prev = m_profilerStatus.exchange(EASY_PROF_ENABLED, std::memory_order_release);
|
||||
if (prev != EASY_PROF_ENABLED) {
|
||||
enableEventTracer();
|
||||
m_beginTime = t;
|
||||
}
|
||||
m_dumpSpin.unlock();
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
@ -1079,19 +1172,23 @@ void ProfileManager::listen(uint16_t _port)
|
||||
#ifdef EASY_DEBUG_NET_PRINT
|
||||
printf("receive REQUEST_STOP_CAPTURE\n");
|
||||
#endif
|
||||
ProfileManager::setEnabled(false);
|
||||
|
||||
m_spin.lock();
|
||||
::profiler::timestamp_t t = m_endTime;
|
||||
m_spin.unlock();
|
||||
EASY_FORCE_EVENT2(t, "StopCapture", profiler::colors::Red, profiler::OFF);
|
||||
m_dumpSpin.lock();
|
||||
auto time = getCurrentTime();
|
||||
const auto prev = m_profilerStatus.exchange(EASY_PROF_DUMP, std::memory_order_release);
|
||||
if (prev == EASY_PROF_ENABLED) {
|
||||
disableEventTracer();
|
||||
m_endTime = time;
|
||||
}
|
||||
EASY_FORCE_EVENT2(m_endTime, "StopCapture", profiler::colors::Red, profiler::OFF);
|
||||
|
||||
//TODO
|
||||
//if connection aborted - ignore this part
|
||||
|
||||
profiler::net::DataMessage dm;
|
||||
profiler::OStream os;
|
||||
dumpBlocksToStream(os);
|
||||
dumpBlocksToStream(os, false);
|
||||
m_dumpSpin.unlock();
|
||||
|
||||
profiler::net::DataMessage dm;
|
||||
dm.size = (uint32_t)os.stream().str().length();
|
||||
|
||||
int packet_size = int(sizeof(dm)) + int(dm.size);
|
||||
|
@ -320,7 +320,8 @@ struct ThreadStorage
|
||||
#endif
|
||||
|
||||
const profiler::thread_id_t id;
|
||||
std::atomic<uint8_t> expired;
|
||||
std::atomic<char> expired;
|
||||
std::atomic_bool frame; ///< is new frame working
|
||||
bool allowChildren;
|
||||
bool named;
|
||||
bool guarded;
|
||||
@ -368,13 +369,14 @@ class ProfileManager
|
||||
profiler::timestamp_t m_endTime;
|
||||
profiler::spin_lock m_spin;
|
||||
profiler::spin_lock m_storedSpin;
|
||||
std::atomic_bool m_isEnabled;
|
||||
profiler::spin_lock m_dumpSpin;
|
||||
std::atomic<char> m_profilerStatus;
|
||||
std::atomic_bool m_isEventTracingEnabled;
|
||||
std::atomic_bool m_isAlreadyListening;
|
||||
std::atomic_bool m_isAlreadyListening;
|
||||
|
||||
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
|
||||
|
||||
uint32_t dumpBlocksToStream(profiler::OStream& _outputStream);
|
||||
uint32_t dumpBlocksToStream(profiler::OStream& _outputStream, bool _lockSpin);
|
||||
void setBlockStatus(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
|
||||
|
||||
std::thread m_listenThread;
|
||||
@ -395,12 +397,13 @@ public:
|
||||
const char* _filename,
|
||||
int _line,
|
||||
profiler::block_type_t _block_type,
|
||||
profiler::color_t _color);
|
||||
profiler::color_t _color,
|
||||
bool _copyName = false);
|
||||
|
||||
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
|
||||
void beginBlock(profiler::Block& _block);
|
||||
void endBlock();
|
||||
void setEnabled(bool isEnable, bool _setTime = true);
|
||||
void setEnabled(bool isEnable);
|
||||
void setEventTracingEnabled(bool _isEnable);
|
||||
uint32_t dumpBlocksToFile(const char* filename);
|
||||
const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard);
|
||||
@ -423,7 +426,10 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
uint8_t checkThreadExpired(ThreadStorage& _registeredThread);
|
||||
void enableEventTracer();
|
||||
void disableEventTracer();
|
||||
|
||||
char checkThreadExpired(ThreadStorage& _registeredThread);
|
||||
|
||||
void storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp);
|
||||
void storeBlockForce2(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
|
||||
|
Loading…
x
Reference in New Issue
Block a user