0
0
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:
Victor Zarubkin 2016-11-20 17:09:50 +03:00
parent 63f77efcf1
commit 7ae518e1d0
4 changed files with 102 additions and 27 deletions

View File

@ -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*) { }

View File

@ -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);
}));

View File

@ -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);

View File

@ -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);