mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
(Core) Monitoring threads, removing threads without blocks, events and context switches;
* (Core) Context switch events also register threads for current process; * (Core) Writing process id into output file (old files still could be opened);
This commit is contained in:
parent
039e0a6efa
commit
29f81d1244
@ -1,4 +1,4 @@
|
|||||||
# easy_profiler [![version](https://img.shields.io/badge/version-1.0.0%20beta-009688.svg)](https://github.com/yse/easy_profiler/releases)
|
# easy_profiler [![version](https://img.shields.io/badge/version-1.0.1%20beta-009688.svg)](https://github.com/yse/easy_profiler/releases)
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/yse/easy_profiler.svg?branch=develop)](https://travis-ci.org/yse/easy_profiler)
|
[![Build Status](https://travis-ci.org/yse/easy_profiler.svg?branch=develop)](https://travis-ci.org/yse/easy_profiler)
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ namespace profiler {
|
|||||||
if (time > TRACING_END_TIME.load(::std::memory_order_acquire))
|
if (time > TRACING_END_TIME.load(::std::memory_order_acquire))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
processid_t pid = 0;
|
||||||
const char* process_name = "";
|
const char* process_name = "";
|
||||||
|
|
||||||
// Trying to get target process name and id
|
// Trying to get target process name and id
|
||||||
@ -138,7 +139,7 @@ namespace profiler {
|
|||||||
auto hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, _contextSwitchEvent->NewThreadId);
|
auto hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, _contextSwitchEvent->NewThreadId);
|
||||||
if (hThread != nullptr)
|
if (hThread != nullptr)
|
||||||
{
|
{
|
||||||
auto pid = GetProcessIdOfThread(hThread);
|
pid = GetProcessIdOfThread(hThread);
|
||||||
auto pinfo = &PROCESS_INFO_TABLE[pid];
|
auto pinfo = &PROCESS_INFO_TABLE[pid];
|
||||||
|
|
||||||
if (pinfo->valid == 0)
|
if (pinfo->valid == 0)
|
||||||
@ -204,7 +205,7 @@ namespace profiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, process_name);
|
MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, process_name);
|
||||||
MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time);
|
MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, pid, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -190,15 +190,16 @@ namespace profiler {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BlocksTree::children_t children; ///< List of children indexes
|
BlocksTree::children_t children; ///< List of children indexes
|
||||||
BlocksTree::children_t sync; ///< List of context-switch events
|
BlocksTree::children_t sync; ///< List of context-switch events
|
||||||
BlocksTree::children_t events; ///< List of events indexes
|
BlocksTree::children_t events; ///< List of events indexes
|
||||||
std::string thread_name; ///< Name of this thread
|
std::string thread_name; ///< Name of this thread
|
||||||
::profiler::timestamp_t active_time; ///< Active time of this thread (sum of all children duration)
|
::profiler::timestamp_t active_time; ///< Active time of this thread (sum of all children duration)
|
||||||
::profiler::thread_id_t thread_id; ///< System Id of this thread
|
::profiler::thread_id_t thread_id; ///< System Id of this thread
|
||||||
uint16_t depth; ///< Maximum stack depth (number of levels)
|
::profiler::block_index_t blocks_number; ///< Total blocks number including their children
|
||||||
|
uint16_t depth; ///< Maximum stack depth (number of levels)
|
||||||
|
|
||||||
BlocksTreeRoot() : active_time(0), thread_id(0), depth(0)
|
BlocksTreeRoot() : active_time(0), thread_id(0), blocks_number(0), depth(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +210,7 @@ namespace profiler {
|
|||||||
, thread_name(::std::move(that.thread_name))
|
, thread_name(::std::move(that.thread_name))
|
||||||
, active_time(that.active_time)
|
, active_time(that.active_time)
|
||||||
, thread_id(that.thread_id)
|
, thread_id(that.thread_id)
|
||||||
|
, blocks_number(that.blocks_number)
|
||||||
, depth(that.depth)
|
, depth(that.depth)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -221,6 +223,7 @@ namespace profiler {
|
|||||||
thread_name = ::std::move(that.thread_name);
|
thread_name = ::std::move(that.thread_name);
|
||||||
active_time = that.active_time;
|
active_time = that.active_time;
|
||||||
thread_id = that.thread_id;
|
thread_id = that.thread_id;
|
||||||
|
blocks_number = that.blocks_number;
|
||||||
depth = that.depth;
|
depth = that.depth;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,8 @@
|
|||||||
#include "event_trace_win.h"
|
#include "event_trace_win.h"
|
||||||
#include "current_time.h"
|
#include "current_time.h"
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
#ifndef _WIN32
|
#undef min
|
||||||
#include <signal.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -93,20 +92,34 @@ EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef BUILD_WITH_EASY_PROFILER
|
#ifdef BUILD_WITH_EASY_PROFILER
|
||||||
|
# define EASY_EVENT_RES(res, name, ...)\
|
||||||
|
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), MANAGER.addBlockDescriptor(\
|
||||||
|
::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__)));\
|
||||||
|
res = MANAGER.storeBlock(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name))
|
||||||
|
|
||||||
# define EASY_FORCE_EVENT(timestamp, name, ...)\
|
# define EASY_FORCE_EVENT(timestamp, name, ...)\
|
||||||
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), addBlockDescriptor(\
|
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), addBlockDescriptor(\
|
||||||
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
|
::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__)));\
|
||||||
storeBlockForce(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name), timestamp);
|
storeBlockForce(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name), timestamp)
|
||||||
|
|
||||||
# define EASY_FORCE_EVENT2(timestamp, name, ...)\
|
# define EASY_FORCE_EVENT2(timestamp, name, ...)\
|
||||||
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), addBlockDescriptor(\
|
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), addBlockDescriptor(\
|
||||||
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
|
::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__)));\
|
||||||
storeBlockForce2(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name), timestamp);
|
storeBlockForce2(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name), timestamp)
|
||||||
|
|
||||||
|
# define EASY_FORCE_EVENT3(ts, timestamp, name, ...)\
|
||||||
|
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), addBlockDescriptor(\
|
||||||
|
::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__)));\
|
||||||
|
storeBlockForce2(ts, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name), timestamp)
|
||||||
#else
|
#else
|
||||||
|
# define EASY_EVENT_RES(res, name, ...)
|
||||||
# define EASY_FORCE_EVENT(timestamp, name, ...)
|
# define EASY_FORCE_EVENT(timestamp, name, ...)
|
||||||
# define EASY_FORCE_EVENT2(timestamp, name, ...)
|
# define EASY_FORCE_EVENT2(timestamp, name, ...)
|
||||||
|
# define EASY_FORCE_EVENT3(ts, timestamp, name, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -314,14 +327,13 @@ public:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ThreadStorage::ThreadStorage() : id(getCurrentThreadId()), allowChildren(true), named(false)
|
ThreadStorage::ThreadStorage() : id(getCurrentThreadId()), allowChildren(true), named(false), guarded(false)
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
, pthread_id(pthread_self())
|
, pthread_id(pthread_self())
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
expired = ATOMIC_VAR_INIT(false);
|
expired = ATOMIC_VAR_INIT(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||||
@ -388,8 +400,9 @@ ThreadGuard::~ThreadGuard()
|
|||||||
#ifndef EASY_PROFILER_API_DISABLED
|
#ifndef EASY_PROFILER_API_DISABLED
|
||||||
if (m_id != 0 && THREAD_STORAGE != nullptr && THREAD_STORAGE->id == m_id)
|
if (m_id != 0 && THREAD_STORAGE != nullptr && THREAD_STORAGE->id == m_id)
|
||||||
{
|
{
|
||||||
EASY_EVENT("ThreadFinished", profiler::colors::Dark);
|
bool isMarked = false;
|
||||||
THREAD_STORAGE->expired.store(true, std::memory_order_release);
|
EASY_EVENT_RES(isMarked, "ThreadFinished", profiler::colors::Dark, ::profiler::FORCE_ON);
|
||||||
|
THREAD_STORAGE->expired.store(isMarked ? 2 : 1, std::memory_order_release);
|
||||||
THREAD_STORAGE = nullptr;
|
THREAD_STORAGE = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -397,7 +410,15 @@ ThreadGuard::~ThreadGuard()
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ProfileManager::ProfileManager()
|
ProfileManager::ProfileManager() :
|
||||||
|
#ifdef _WIN32
|
||||||
|
m_processId(GetProcessId(GetCurrentProcess()))
|
||||||
|
#else
|
||||||
|
m_processId((processid_t)getpid())
|
||||||
|
#endif
|
||||||
|
, m_usedMemorySize(0)
|
||||||
|
, m_beginTime(0)
|
||||||
|
, m_endTime(0)
|
||||||
{
|
{
|
||||||
m_isEnabled = ATOMIC_VAR_INIT(false);
|
m_isEnabled = ATOMIC_VAR_INIT(false);
|
||||||
m_isEventTracingEnabled = ATOMIC_VAR_INIT(EASY_EVENT_TRACING_ENABLED);
|
m_isEventTracingEnabled = ATOMIC_VAR_INIT(EASY_EVENT_TRACING_ENABLED);
|
||||||
@ -422,6 +443,8 @@ class ProfileManagerInstance {
|
|||||||
} PROFILE_MANAGER;
|
} PROFILE_MANAGER;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ProfileManager& ProfileManager::instance()
|
ProfileManager& ProfileManager::instance()
|
||||||
{
|
{
|
||||||
#ifndef EASY_MAGIC_STATIC_CPP11
|
#ifndef EASY_MAGIC_STATIC_CPP11
|
||||||
@ -434,9 +457,10 @@ ProfileManager& ProfileManager::instance()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadStorage& ProfileManager::threadStorage(profiler::thread_id_t _thread_id)
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ThreadStorage& ProfileManager::_threadStorage(profiler::thread_id_t _thread_id)
|
||||||
{
|
{
|
||||||
guard_lock_t lock(m_spin);
|
|
||||||
return m_threads[_thread_id];
|
return m_threads[_thread_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,6 +470,8 @@ ThreadStorage* ProfileManager::_findThreadStorage(profiler::thread_id_t _thread_
|
|||||||
return it != m_threads.end() ? &it->second : nullptr;
|
return it != m_threads.end() ? &it->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _defaultStatus,
|
const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _defaultStatus,
|
||||||
const char* _autogenUniqueId,
|
const char* _autogenUniqueId,
|
||||||
const char* _name,
|
const char* _name,
|
||||||
@ -469,17 +495,19 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
|
||||||
{
|
{
|
||||||
if (!m_isEnabled.load(std::memory_order_acquire) || !(_desc->m_status & profiler::ON))
|
if (!m_isEnabled.load(std::memory_order_acquire) || !(_desc->m_status & profiler::ON))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (THREAD_STORAGE == nullptr)
|
if (THREAD_STORAGE == nullptr)
|
||||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||||
|
|
||||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||||
if (!THREAD_STORAGE->allowChildren)
|
if (!THREAD_STORAGE->allowChildren && !(_desc->m_status & FORCE_ON_FLAG))
|
||||||
return;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
profiler::Block b(_desc, _runtimeName);
|
profiler::Block b(_desc, _runtimeName);
|
||||||
@ -487,8 +515,12 @@ void ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, cons
|
|||||||
b.m_end = b.m_begin;
|
b.m_end = b.m_begin;
|
||||||
|
|
||||||
THREAD_STORAGE->storeBlock(b);
|
THREAD_STORAGE->storeBlock(b);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ProfileManager::storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp)
|
void ProfileManager::storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp)
|
||||||
{
|
{
|
||||||
if (!(_desc->m_status & profiler::ON))
|
if (!(_desc->m_status & profiler::ON))
|
||||||
@ -498,7 +530,7 @@ void ProfileManager::storeBlockForce(const profiler::BaseBlockDescriptor* _desc,
|
|||||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||||
|
|
||||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||||
if (!THREAD_STORAGE->allowChildren)
|
if (!THREAD_STORAGE->allowChildren && !(_desc->m_status & FORCE_ON_FLAG))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -519,7 +551,7 @@ void ProfileManager::storeBlockForce2(const profiler::BaseBlockDescriptor* _desc
|
|||||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||||
|
|
||||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||||
if (!THREAD_STORAGE->allowChildren)
|
if (!THREAD_STORAGE->allowChildren && !(_desc->m_status & FORCE_ON_FLAG))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -529,6 +561,15 @@ void ProfileManager::storeBlockForce2(const profiler::BaseBlockDescriptor* _desc
|
|||||||
THREAD_STORAGE->storeBlock(b);
|
THREAD_STORAGE->storeBlock(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProfileManager::storeBlockForce2(ThreadStorage& _registeredThread, const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp)
|
||||||
|
{
|
||||||
|
profiler::Block b(_desc, _runtimeName);
|
||||||
|
b.m_end = b.m_begin = _timestamp;
|
||||||
|
_registeredThread.storeBlock(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ProfileManager::beginBlock(Block& _block)
|
void ProfileManager::beginBlock(Block& _block)
|
||||||
{
|
{
|
||||||
if (!m_isEnabled.load(std::memory_order_acquire))
|
if (!m_isEnabled.load(std::memory_order_acquire))
|
||||||
@ -569,16 +610,7 @@ void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profil
|
|||||||
ts->sync.openedList.emplace(_time, _target_thread_id, _target_process);
|
ts->sync.openedList.emplace(_time, _target_thread_id, _target_process);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, bool _lockSpin)
|
//////////////////////////////////////////////////////////////////////////
|
||||||
{
|
|
||||||
auto ts = _lockSpin ? findThreadStorage(_thread_id) : _findThreadStorage(_thread_id);
|
|
||||||
if (ts != nullptr)
|
|
||||||
{
|
|
||||||
profiler::Block b(_time, _target_thread_id, "");
|
|
||||||
b.finish(_time);
|
|
||||||
ts->storeCSwitch(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileManager::endBlock()
|
void ProfileManager::endBlock()
|
||||||
{
|
{
|
||||||
@ -607,9 +639,16 @@ void ProfileManager::endBlock()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime, bool _lockSpin)
|
void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin)
|
||||||
{
|
{
|
||||||
auto ts = _lockSpin ? findThreadStorage(_thread_id) : _findThreadStorage(_thread_id);
|
ThreadStorage* ts = nullptr;
|
||||||
|
if (_process_id == m_processId)
|
||||||
|
// If thread owned by current process then create new ThreadStorage if there is no one
|
||||||
|
ts = _lockSpin ? &threadStorage(_thread_id) : &_threadStorage(_thread_id);
|
||||||
|
else
|
||||||
|
// If thread owned by another process OR _process_id IS UNKNOWN then do not create ThreadStorage for this
|
||||||
|
ts = _lockSpin ? findThreadStorage(_thread_id) : _findThreadStorage(_thread_id);
|
||||||
|
|
||||||
if (ts == nullptr || ts->sync.openedList.empty())
|
if (ts == nullptr || ts->sync.openedList.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -620,6 +659,8 @@ void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler
|
|||||||
ts->sync.openedList.pop();
|
ts->sync.openedList.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ProfileManager::setEnabled(bool isEnable, bool _setTime)
|
void ProfileManager::setEnabled(bool isEnable, bool _setTime)
|
||||||
{
|
{
|
||||||
auto time = getCurrentTime();
|
auto time = getCurrentTime();
|
||||||
@ -661,10 +702,14 @@ void ProfileManager::setEventTracingEnabled(bool _isEnable)
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
uint8_t ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
||||||
{
|
{
|
||||||
if (_registeredThread.expired.load(std::memory_order_acquire))
|
const uint8_t val = _registeredThread.expired.load(std::memory_order_acquire);
|
||||||
return true;
|
if (val != 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
if (_registeredThread.guarded)
|
||||||
|
return 0;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
@ -678,19 +723,20 @@ bool ProfileManager::checkThreadExpired(ThreadStorage& _registeredThread)
|
|||||||
_registeredThread.expired.store(true, std::memory_order_release);
|
_registeredThread.expired.store(true, std::memory_order_release);
|
||||||
if (hThread != nullptr)
|
if (hThread != nullptr)
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hThread != nullptr)
|
if (hThread != nullptr)
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
return false;
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
return false;//pthread_kill(_registeredThread.pthread_id, 0) != 0;
|
return 0;//pthread_kill(_registeredThread.pthread_id, 0) != 0;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -719,6 +765,8 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
// TODO: think about better solution because this one is not 100% safe...
|
// TODO: think about better solution because this one is not 100% safe...
|
||||||
|
|
||||||
|
const profiler::timestamp_t now = getCurrentTime();
|
||||||
|
const profiler::timestamp_t endtime = m_endTime == 0 ? now : std::min(now, m_endTime);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (eventTracingEnabled)
|
if (eventTracingEnabled)
|
||||||
@ -731,9 +779,10 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
std::ifstream infile(m_csInfoFilename.c_str());
|
std::ifstream infile(m_csInfoFilename.c_str());
|
||||||
if(infile.is_open()) {
|
if(infile.is_open()) {
|
||||||
std::string next_task_name;
|
std::string next_task_name;
|
||||||
while (infile >> timestamp >> thread_from >> thread_to >> next_task_name) {
|
pid_t process_to = 0;
|
||||||
|
while (infile >> timestamp >> thread_from >> thread_to >> next_task_name >> process_to) {
|
||||||
beginContextSwitch(thread_from, timestamp, thread_to, next_task_name.c_str(), false);
|
beginContextSwitch(thread_from, timestamp, thread_to, next_task_name.c_str(), false);
|
||||||
endContextSwitch(thread_to, timestamp, false);
|
endContextSwitch(thread_to, (processid_t)process_to, timestamp, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -745,16 +794,20 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
for (auto it = m_threads.begin(), end = m_threads.end(); it != end;)
|
for (auto it = m_threads.begin(), end = m_threads.end(); it != end;)
|
||||||
{
|
{
|
||||||
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());
|
uint32_t num = static_cast<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(t.sync.closedList.size());
|
||||||
|
|
||||||
const bool expired = checkThreadExpired(t) || t.expired.load(std::memory_order_acquire);
|
const uint8_t expired = checkThreadExpired(t);
|
||||||
if (expired && num == 0) {
|
if (num == 0 && (expired != 0 || !t.guarded)) {
|
||||||
// Thread has been finished and contains no profiled information.
|
// Remove thread if it contains no profiled information and has been finished or is not guarded.
|
||||||
// Remove it now.
|
|
||||||
m_threads.erase(it++);
|
m_threads.erase(it++);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expired == 1) {
|
||||||
|
EASY_FORCE_EVENT3(t, endtime, "ThreadExpired", profiler::colors::Dark);
|
||||||
|
++num;
|
||||||
|
}
|
||||||
|
|
||||||
usedMemorySize += t.blocks.usedMemorySize + t.sync.usedMemorySize;
|
usedMemorySize += t.blocks.usedMemorySize + t.sync.usedMemorySize;
|
||||||
blocks_number += num;
|
blocks_number += num;
|
||||||
++it;
|
++it;
|
||||||
@ -763,6 +816,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
// Write profiler signature and version
|
// Write profiler signature and version
|
||||||
_outputStream.write(PROFILER_SIGNATURE);
|
_outputStream.write(PROFILER_SIGNATURE);
|
||||||
_outputStream.write(EASY_CURRENT_VERSION);
|
_outputStream.write(EASY_CURRENT_VERSION);
|
||||||
|
_outputStream.write(m_processId);
|
||||||
|
|
||||||
// Write CPU frequency to let GUI calculate real time value from CPU clocks
|
// Write CPU frequency to let GUI calculate real time value from CPU clocks
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -847,7 +901,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
|
|||||||
t.blocks.openedList.clear();
|
t.blocks.openedList.clear();
|
||||||
t.sync.openedList.clear();
|
t.sync.openedList.clear();
|
||||||
|
|
||||||
if (t.expired.load(std::memory_order_acquire))
|
if (t.expired.load(std::memory_order_acquire) != 0)
|
||||||
m_threads.erase(it++); // Remove expired thread after writing all profiled information
|
m_threads.erase(it++); // Remove expired thread after writing all profiled information
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
@ -875,6 +929,7 @@ const char* ProfileManager::registerThread(const char* name, ThreadGuard& thread
|
|||||||
if (THREAD_STORAGE == nullptr)
|
if (THREAD_STORAGE == nullptr)
|
||||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||||
|
|
||||||
|
THREAD_STORAGE->guarded = true;
|
||||||
if (!THREAD_STORAGE->named) {
|
if (!THREAD_STORAGE->named) {
|
||||||
THREAD_STORAGE->named = true;
|
THREAD_STORAGE->named = true;
|
||||||
THREAD_STORAGE->name = name;
|
THREAD_STORAGE->name = name;
|
||||||
|
@ -320,9 +320,10 @@ struct ThreadStorage
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
const profiler::thread_id_t id;
|
const profiler::thread_id_t id;
|
||||||
std::atomic_bool expired;
|
std::atomic<uint8_t> expired;
|
||||||
bool allowChildren;
|
bool allowChildren;
|
||||||
bool named;
|
bool named;
|
||||||
|
bool guarded;
|
||||||
|
|
||||||
void storeBlock(const profiler::Block& _block);
|
void storeBlock(const profiler::Block& _block);
|
||||||
void storeCSwitch(const profiler::Block& _block);
|
void storeCSwitch(const profiler::Block& _block);
|
||||||
@ -333,6 +334,8 @@ struct ThreadStorage
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef uint32_t processid_t;
|
||||||
|
|
||||||
class BlockDescriptor;
|
class BlockDescriptor;
|
||||||
|
|
||||||
class ProfileManager
|
class ProfileManager
|
||||||
@ -355,12 +358,14 @@ class ProfileManager
|
|||||||
typedef std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t> descriptors_map_t;
|
typedef std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t> descriptors_map_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const processid_t m_processId;
|
||||||
|
|
||||||
map_of_threads_stacks m_threads;
|
map_of_threads_stacks m_threads;
|
||||||
block_descriptors_t m_descriptors;
|
block_descriptors_t m_descriptors;
|
||||||
descriptors_map_t m_descriptorsMap;
|
descriptors_map_t m_descriptorsMap;
|
||||||
uint64_t m_usedMemorySize = 0;
|
uint64_t m_usedMemorySize;
|
||||||
profiler::timestamp_t m_beginTime = 0;
|
profiler::timestamp_t m_beginTime;
|
||||||
profiler::timestamp_t m_endTime = 0;
|
profiler::timestamp_t m_endTime;
|
||||||
profiler::spin_lock m_spin;
|
profiler::spin_lock m_spin;
|
||||||
profiler::spin_lock m_storedSpin;
|
profiler::spin_lock m_storedSpin;
|
||||||
std::atomic_bool m_isEnabled;
|
std::atomic_bool m_isEnabled;
|
||||||
@ -392,7 +397,7 @@ public:
|
|||||||
profiler::block_type_t _block_type,
|
profiler::block_type_t _block_type,
|
||||||
profiler::color_t _color);
|
profiler::color_t _color);
|
||||||
|
|
||||||
void storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
|
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
|
||||||
void beginBlock(profiler::Block& _block);
|
void beginBlock(profiler::Block& _block);
|
||||||
void endBlock();
|
void endBlock();
|
||||||
void setEnabled(bool isEnable, bool _setTime = true);
|
void setEnabled(bool isEnable, bool _setTime = true);
|
||||||
@ -412,22 +417,28 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, const char* _target_process, bool _lockSpin = true);
|
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, const char* _target_process, bool _lockSpin = true);
|
||||||
void storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, bool _lockSpin = true);
|
void endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin = true);
|
||||||
void endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime, bool _lockSpin = true);
|
|
||||||
void startListen(uint16_t _port);
|
void startListen(uint16_t _port);
|
||||||
void stopListen();
|
void stopListen();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool checkThreadExpired(ThreadStorage& _registeredThread);
|
uint8_t checkThreadExpired(ThreadStorage& _registeredThread);
|
||||||
|
|
||||||
void storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp);
|
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);
|
void storeBlockForce2(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
|
||||||
|
void storeBlockForce2(ThreadStorage& _registeredThread, const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
|
||||||
|
|
||||||
ThreadStorage& threadStorage(profiler::thread_id_t _thread_id);
|
ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id);
|
||||||
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
|
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
|
||||||
|
|
||||||
ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
|
inline ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
|
||||||
|
{
|
||||||
|
guard_lock_t lock(m_spin);
|
||||||
|
return _threadStorage(_thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
|
||||||
{
|
{
|
||||||
guard_lock_t lock(m_spin);
|
guard_lock_t lock(m_spin);
|
||||||
return _findThreadStorage(_thread_id);
|
return _findThreadStorage(_thread_id);
|
||||||
|
@ -67,14 +67,18 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef uint32_t processid_t;
|
||||||
|
|
||||||
extern const uint32_t PROFILER_SIGNATURE;
|
extern const uint32_t PROFILER_SIGNATURE;
|
||||||
extern const uint32_t EASY_CURRENT_VERSION;
|
extern const uint32_t EASY_CURRENT_VERSION;
|
||||||
|
|
||||||
# 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))
|
# 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))
|
||||||
|
const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0);
|
||||||
const uint32_t COMPATIBLE_VERSIONS[] = {
|
const uint32_t COMPATIBLE_VERSIONS[] = {
|
||||||
EASY_CURRENT_VERSION,
|
EASY_V_100,
|
||||||
EASY_VERSION_INT(0, 1, 0)
|
EASY_VERSION_INT(0, 1, 0)
|
||||||
};
|
};
|
||||||
|
// WARNING: Modify isCompatibleVersion(uint32_t _version) if COMPATIBLE_VERSIONS_NUM == 0
|
||||||
const uint16_t COMPATIBLE_VERSIONS_NUM = sizeof(COMPATIBLE_VERSIONS) / sizeof(uint32_t);
|
const uint16_t COMPATIBLE_VERSIONS_NUM = sizeof(COMPATIBLE_VERSIONS) / sizeof(uint32_t);
|
||||||
# undef EASY_VERSION_INT
|
# undef EASY_VERSION_INT
|
||||||
|
|
||||||
@ -112,7 +116,9 @@ bool isCompatibleVersion(uint32_t _version)
|
|||||||
{
|
{
|
||||||
if (_version == EASY_CURRENT_VERSION)
|
if (_version == EASY_CURRENT_VERSION)
|
||||||
return true;
|
return true;
|
||||||
return COMPATIBLE_VERSIONS_NUM > 1 && ::std::binary_search(COMPATIBLE_VERSIONS + 1, COMPATIBLE_VERSIONS + COMPATIBLE_VERSIONS_NUM, _version);
|
|
||||||
|
return ::std::binary_search(COMPATIBLE_VERSIONS, COMPATIBLE_VERSIONS + COMPATIBLE_VERSIONS_NUM,
|
||||||
|
_version, [](uint32_t _a, uint32_t _b){ return _a > _b; });
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void write(::std::stringstream& _stream, const char* _value, size_t _size)
|
inline void write(::std::stringstream& _stream, const char* _value, size_t _size)
|
||||||
@ -369,6 +375,10 @@ extern "C" {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processid_t pid = 0;
|
||||||
|
if (version > EASY_V_100)
|
||||||
|
inFile.read((char*)&pid, sizeof(processid_t));
|
||||||
|
|
||||||
int64_t file_cpu_frequency = 0LL;
|
int64_t file_cpu_frequency = 0LL;
|
||||||
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
|
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
|
||||||
uint64_t cpu_frequency = file_cpu_frequency;
|
uint64_t cpu_frequency = file_cpu_frequency;
|
||||||
@ -669,6 +679,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++root.blocks_number;
|
||||||
root.children.emplace_back(block_index);// ::std::move(tree));
|
root.children.emplace_back(block_index);// ::std::move(tree));
|
||||||
if (desc->type() == ::profiler::BLOCK_TYPE_EVENT)
|
if (desc->type() == ::profiler::BLOCK_TYPE_EVENT)
|
||||||
root.events.emplace_back(block_index);
|
root.events.emplace_back(block_index);
|
||||||
|
@ -1 +1 @@
|
|||||||
1.0.0
|
1.0.1
|
Loading…
x
Reference in New Issue
Block a user