0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-28 01:04:41 +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:
Victor Zarubkin 2016-12-12 22:26:32 +03:00
parent 039e0a6efa
commit 29f81d1244
7 changed files with 151 additions and 70 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +1 @@
1.0.0 1.0.1