mirror of
https://github.com/yse/easy_profiler.git
synced 2025-01-14 00:27:55 +08:00
(profiler core) Manually check if thread exist or not. Changed EASY_THREAD behavior: it does not create ThreadGuard and can be invoked from every function you like. Added macro EASY_THREAD_SCOPE which behaves like an old EASY_THREAD macro (creates ThreadGuard).
This commit is contained in:
parent
63f77efcf1
commit
7ae518e1d0
@ -176,10 +176,24 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION.
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_THREAD(name)\
|
||||
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = 0;\
|
||||
if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\
|
||||
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name);
|
||||
|
||||
/** Macro for current thread registration and creating a thread guard object.
|
||||
|
||||
\note If this thread has been already registered then nothing happens.
|
||||
|
||||
\note Also creates thread guard which marks thread as "expired" on it's destructor
|
||||
and creates "ThreadFinished" profiler event.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_THREAD_SCOPE(name)\
|
||||
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = 0;\
|
||||
::profiler::ThreadGuard EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__);\
|
||||
if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\
|
||||
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name,\
|
||||
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThreadScoped(name,\
|
||||
EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__));
|
||||
|
||||
/** Macro for main thread registration.
|
||||
@ -291,6 +305,7 @@ Otherwise, no log messages will be printed.
|
||||
# define EASY_PROFILER_DISABLE
|
||||
# define EASY_EVENT(...)
|
||||
# define EASY_THREAD(...)
|
||||
# define EASY_THREAD_SCOPE(...)
|
||||
# define EASY_MAIN_THREAD
|
||||
# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled)
|
||||
# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority)
|
||||
@ -497,7 +512,15 @@ namespace profiler {
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API const char* registerThread(const char* _name, ThreadGuard&);
|
||||
PROFILER_API const char* registerThreadScoped(const char* _name, ThreadGuard&);
|
||||
|
||||
/** Register current thread and give it a name.
|
||||
|
||||
\note Only first call of registerThread() for the current thread will have an effect.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API const char* registerThread(const char* _name);
|
||||
|
||||
/** Enable or disable event tracing.
|
||||
|
||||
@ -575,7 +598,8 @@ namespace profiler {
|
||||
inline void storeEvent(const BaseBlockDescriptor*, const char*) { }
|
||||
inline void beginBlock(Block&) { }
|
||||
inline uint32_t dumpBlocksToFile(const char*) { return 0; }
|
||||
inline const char* registerThread(const char*, ThreadGuard&) { return ""; }
|
||||
inline const char* registerThreadScoped(const char*, ThreadGuard&) { return ""; }
|
||||
inline const char* registerThread(const char*) { return ""; }
|
||||
inline void setEventTracingEnabled(bool) { }
|
||||
inline void setLowPriorityEventTracing(bool) { }
|
||||
inline void setContextSwitchLogFilename(const char*) { }
|
||||
|
@ -402,7 +402,7 @@ namespace profiler {
|
||||
*/
|
||||
m_processThread = ::std::move(::std::thread([this]()
|
||||
{
|
||||
EASY_THREAD("EasyProfiler.ETW");
|
||||
EASY_THREAD_SCOPE("EasyProfiler.ETW");
|
||||
ProcessTrace(&m_openedHandle, 1, 0, 0);
|
||||
}));
|
||||
|
||||
|
@ -135,11 +135,16 @@ extern "C" {
|
||||
return MANAGER.dumpBlocksToFile(filename);
|
||||
}
|
||||
|
||||
PROFILER_API const char* registerThread(const char* name, ThreadGuard& threadGuard)
|
||||
PROFILER_API const char* registerThreadScoped(const char* name, ThreadGuard& threadGuard)
|
||||
{
|
||||
return MANAGER.registerThread(name, threadGuard);
|
||||
}
|
||||
|
||||
PROFILER_API const char* registerThread(const char* name)
|
||||
{
|
||||
return MANAGER.registerThread(name);
|
||||
}
|
||||
|
||||
PROFILER_API void setEventTracingEnabled(bool _isEnable)
|
||||
{
|
||||
MANAGER.setEventTracingEnabled(_isEnable);
|
||||
@ -180,7 +185,8 @@ extern "C" {
|
||||
PROFILER_API void storeEvent(const BaseBlockDescriptor*, const char*) { }
|
||||
PROFILER_API void beginBlock(Block&) { }
|
||||
PROFILER_API uint32_t dumpBlocksToFile(const char*) { return 0; }
|
||||
PROFILER_API const char* registerThread(const char*, ThreadGuard&) { return ""; }
|
||||
PROFILER_API const char* registerThreadScoped(const char*, ThreadGuard&) { return ""; }
|
||||
PROFILER_API const char* registerThread(const char*) { return ""; }
|
||||
PROFILER_API void setEventTracingEnabled(bool) { }
|
||||
PROFILER_API void setLowPriorityEventTracing(bool) { }
|
||||
PROFILER_API void setContextSwitchLogFilename(const char*) { }
|
||||
@ -299,6 +305,11 @@ public:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ThreadStorage::ThreadStorage() : id(getCurrentThreadId()), allowChildren(true), named(false)
|
||||
{
|
||||
expired = ATOMIC_VAR_INIT(false);
|
||||
}
|
||||
|
||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
{
|
||||
#if EASY_MEASURE_STORAGE_EXPAND != 0
|
||||
@ -638,6 +649,40 @@ void ProfileManager::setEventTracingEnabled(bool _isEnable)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
||||
{
|
||||
if (_registeredThread.expired.load(std::memory_order_acquire))
|
||||
return true;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Check thread for Windows
|
||||
|
||||
DWORD exitCode = 0;
|
||||
auto hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, _registeredThread.id);
|
||||
if (hThread == nullptr || GetExitCodeThread(hThread, &exitCode) == FALSE || exitCode != STILL_ACTIVE)
|
||||
{
|
||||
// Thread has been expired
|
||||
_registeredThread.expired.store(true, std::memory_order_release);
|
||||
if (hThread != nullptr)
|
||||
CloseHandle(hThread);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hThread != nullptr)
|
||||
CloseHandle(hThread);
|
||||
|
||||
#else
|
||||
|
||||
// TODO: Check thread for Linux
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
||||
{
|
||||
const bool wasEnabled = m_isEnabled.load(std::memory_order_acquire);
|
||||
@ -686,10 +731,11 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
||||
uint32_t blocks_number = 0;
|
||||
for (auto it = m_threads.begin(), end = m_threads.end(); it != end;)
|
||||
{
|
||||
const auto& t = it->second;
|
||||
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) {
|
||||
const bool expired = checkThreadExpired(t) || t.expired.load(std::memory_order_acquire);
|
||||
if (expired && num == 0) {
|
||||
// Thread has been finished and contains no profiled information.
|
||||
// Remove it now.
|
||||
m_threads.erase(it++);
|
||||
@ -813,20 +859,25 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* _filename)
|
||||
|
||||
const char* ProfileManager::registerThread(const char* name, ThreadGuard& threadGuard)
|
||||
{
|
||||
const bool isNewThread = THREAD_STORAGE == nullptr;
|
||||
if (isNewThread)
|
||||
{
|
||||
const auto id = getCurrentThreadId();
|
||||
THREAD_STORAGE = &threadStorage(id);
|
||||
threadGuard.m_id = THREAD_STORAGE->id = id;
|
||||
if (THREAD_STORAGE == nullptr)
|
||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||
|
||||
if (!THREAD_STORAGE->named) {
|
||||
THREAD_STORAGE->named = true;
|
||||
THREAD_STORAGE->name = name;
|
||||
}
|
||||
|
||||
if (!THREAD_STORAGE->named)
|
||||
{
|
||||
if (!isNewThread) {
|
||||
threadGuard.m_id = THREAD_STORAGE->id = getCurrentThreadId();
|
||||
}
|
||||
threadGuard.m_id = THREAD_STORAGE->id;
|
||||
|
||||
return THREAD_STORAGE->name.c_str();
|
||||
}
|
||||
|
||||
const char* ProfileManager::registerThread(const char* name)
|
||||
{
|
||||
if (THREAD_STORAGE == nullptr)
|
||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||
|
||||
if (!THREAD_STORAGE->named) {
|
||||
THREAD_STORAGE->named = true;
|
||||
THREAD_STORAGE->name = name;
|
||||
}
|
||||
@ -872,7 +923,7 @@ void ProfileManager::stopListenSignalToCapture()
|
||||
|
||||
void ProfileManager::listen()
|
||||
{
|
||||
EASY_THREAD("EasyProfiler.Listen");
|
||||
EASY_THREAD_SCOPE("EasyProfiler.Listen");
|
||||
|
||||
EasySocket socket;
|
||||
profiler::net::Message replyMessage(profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING);
|
||||
|
@ -309,19 +309,16 @@ struct ThreadStorage
|
||||
BlocksList<std::reference_wrapper<profiler::Block>, SIZEOF_CSWITCH * (uint16_t)128U> blocks;
|
||||
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> sync;
|
||||
std::string name;
|
||||
profiler::thread_id_t id = 0;
|
||||
const profiler::thread_id_t id;
|
||||
std::atomic_bool expired;
|
||||
bool allowChildren = true;
|
||||
bool named = false;
|
||||
bool allowChildren;
|
||||
bool named;
|
||||
|
||||
void storeBlock(const profiler::Block& _block);
|
||||
void storeCSwitch(const profiler::Block& _block);
|
||||
void clearClosed();
|
||||
|
||||
ThreadStorage()
|
||||
{
|
||||
expired = ATOMIC_VAR_INIT(false);
|
||||
}
|
||||
ThreadStorage();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -392,6 +389,7 @@ public:
|
||||
void setEventTracingEnabled(bool _isEnable);
|
||||
uint32_t dumpBlocksToFile(const char* filename);
|
||||
const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard);
|
||||
const char* registerThread(const char* name);
|
||||
|
||||
void setContextSwitchLogFilename(const char* name)
|
||||
{
|
||||
@ -411,6 +409,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
bool 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