mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 00:31:02 +08:00
#75 [Core] No waiting when dumping blocks. All events should now be stored properly.
This commit is contained in:
parent
2c008b77ed
commit
22c61a42b5
@ -312,6 +312,9 @@ class chunk_allocator
|
||||
{
|
||||
chunk* last;
|
||||
|
||||
chunk_list(const chunk_list&) = delete;
|
||||
chunk_list(chunk_list&&) = delete;
|
||||
|
||||
chunk_list() : last(nullptr)
|
||||
{
|
||||
static_assert(sizeof(char) == 1, "easy_profiler logic error: sizeof(char) != 1 for this platform! Please, contact easy_profiler authors to resolve your problem.");
|
||||
@ -358,9 +361,6 @@ class chunk_allocator
|
||||
|
||||
private:
|
||||
|
||||
chunk_list(const chunk_list&) = delete;
|
||||
chunk_list(chunk_list&&) = delete;
|
||||
|
||||
void free_last()
|
||||
{
|
||||
auto p = last;
|
||||
@ -384,7 +384,7 @@ class chunk_allocator
|
||||
EASY_STATIC_CONSTEXPR uint16_t N_MINUS_ONE = N - 1;
|
||||
|
||||
chunk_list m_chunks; ///< List of chunks.
|
||||
const chunk* m_markedChunk; ///< Chunk marked by last closed frame
|
||||
chunk* m_markedChunk; ///< Chunk marked by last closed frame
|
||||
uint32_t m_size; ///< Number of elements stored(# of times allocate() has been called.)
|
||||
uint32_t m_markedSize; ///< Number of elements to the moment when put_mark() has been called.
|
||||
uint16_t m_chunkOffset; ///< Number of bytes used in the current chunk.
|
||||
@ -392,6 +392,9 @@ class chunk_allocator
|
||||
|
||||
public:
|
||||
|
||||
chunk_allocator(const chunk_allocator&) = delete;
|
||||
chunk_allocator(chunk_allocator&&) = delete;
|
||||
|
||||
chunk_allocator() : m_markedChunk(nullptr), m_size(0), m_markedSize(0), m_chunkOffset(0), m_markedChunkOffset(0)
|
||||
{
|
||||
}
|
||||
@ -527,10 +530,66 @@ public:
|
||||
m_markedChunkOffset = m_chunkOffset;
|
||||
}
|
||||
|
||||
private:
|
||||
void* marked_allocate(uint16_t n)
|
||||
{
|
||||
chunk* marked = m_markedChunk;
|
||||
if (marked == nullptr || (marked == m_chunks.last && m_markedSize == m_size))
|
||||
{
|
||||
auto data = allocate(n);
|
||||
put_mark();
|
||||
return data;
|
||||
}
|
||||
|
||||
chunk_allocator(const chunk_allocator&) = delete;
|
||||
chunk_allocator(chunk_allocator&&) = delete;
|
||||
++m_markedSize;
|
||||
|
||||
uint16_t chunkOffset = m_markedChunkOffset;
|
||||
if ((chunkOffset + n + sizeof(uint16_t)) <= N)
|
||||
{
|
||||
// Temp to avoid extra load due to this* aliasing.
|
||||
char* data = marked->data + chunkOffset;
|
||||
chunkOffset += n + sizeof(uint16_t);
|
||||
m_markedChunkOffset = chunkOffset;
|
||||
|
||||
unaligned_store16(data, n);
|
||||
data += sizeof(uint16_t);
|
||||
|
||||
// If there is enough space for at least another payload size,
|
||||
// set it to zero.
|
||||
if (chunkOffset < N_MINUS_ONE)
|
||||
unaligned_zero16(data + n);
|
||||
|
||||
if (marked == m_chunks.last && chunkOffset > m_chunkOffset)
|
||||
m_chunkOffset = chunkOffset;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
chunkOffset = n + sizeof(uint16_t);
|
||||
m_markedChunkOffset = chunkOffset;
|
||||
|
||||
chunk* last = m_chunks.last;
|
||||
if (marked == last)
|
||||
{
|
||||
m_chunks.emplace_back();
|
||||
last = m_chunks.last;
|
||||
m_chunkOffset = chunkOffset;
|
||||
m_size = m_markedSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
do last = last->prev; while (last->prev != m_markedChunk);
|
||||
}
|
||||
|
||||
m_markedChunk = last;
|
||||
char* data = last->data;
|
||||
unaligned_store16(data, n);
|
||||
data += sizeof(uint16_t);
|
||||
|
||||
// We assume here that it takes more than one element to fill a chunk.
|
||||
unaligned_zero16(data + n);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}; // END of class chunk_allocator.
|
||||
|
||||
|
@ -160,12 +160,6 @@ extern const uint32_t EASY_CURRENT_VERSION = EASY_VERSION_INT(EASY_PROFILER_VERS
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
# define EASY_PROF_DISABLED false//0
|
||||
# define EASY_PROF_ENABLED true//1
|
||||
//# define EASY_PROF_DUMP 2
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//auto& MANAGER = ProfileManager::instance();
|
||||
# define MANAGER ProfileManager::instance()
|
||||
EASY_CONSTEXPR uint8_t FORCE_ON_FLAG = profiler::FORCE_ON & ~profiler::ON;
|
||||
@ -181,7 +175,7 @@ const decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER fre
|
||||
# ifndef __APPLE__
|
||||
# include <time.h>
|
||||
# endif
|
||||
int64_t calculate_cpu_frequency()
|
||||
static int64_t calculate_cpu_frequency()
|
||||
{
|
||||
double g_TicksPerNanoSec;
|
||||
uint64_t begin = 0, end = 0;
|
||||
@ -272,7 +266,7 @@ thread_local static profiler::ThreadGuard THIS_THREAD_GUARD; // thread guard for
|
||||
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::BlockType::Event, ::profiler::extract_color(__VA_ARGS__)));\
|
||||
storeBlockForce2(ts, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name), timestamp)
|
||||
ts.storeBlockForce(profiler::Block(timestamp, timestamp, EASY_UNIQUE_DESC(__LINE__)->id(), EASY_RUNTIME_NAME(name)))
|
||||
#else
|
||||
# ifndef EASY_PROFILER_API_DISABLED
|
||||
# define EASY_PROFILER_API_DISABLED
|
||||
@ -644,7 +638,8 @@ ThreadGuard::~ThreadGuard()
|
||||
{
|
||||
bool isMarked = false;
|
||||
EASY_EVENT_RES(isMarked, "ThreadFinished", EASY_COLOR_THREAD_END, ::profiler::FORCE_ON);
|
||||
THIS_THREAD->markProfilingFrameEnded();
|
||||
//THIS_THREAD->markProfilingFrameEnded();
|
||||
THIS_THREAD->putMark();
|
||||
THIS_THREAD->expired.store(isMarked ? 2 : 1, std::memory_order_release);
|
||||
THIS_THREAD = nullptr;
|
||||
}
|
||||
@ -663,7 +658,7 @@ ProfileManager::ProfileManager() :
|
||||
, m_beginTime(0)
|
||||
, m_endTime(0)
|
||||
{
|
||||
m_profilerStatus = ATOMIC_VAR_INIT(EASY_PROF_DISABLED);
|
||||
m_profilerStatus = ATOMIC_VAR_INIT(false);
|
||||
m_isEventTracingEnabled = ATOMIC_VAR_INIT(EASY_OPTION_EVENT_TRACING_ENABLED);
|
||||
m_isAlreadyListening = ATOMIC_VAR_INIT(false);
|
||||
m_stopDumping = ATOMIC_VAR_INIT(false);
|
||||
@ -788,15 +783,18 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
|
||||
|
||||
void ProfileManager::storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data, size_t _size, bool _isArray, ValueId _vin)
|
||||
{
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
if (state != EASY_PROF_ENABLED || (_desc->m_status & profiler::ON) == 0)
|
||||
if (!isEnabled() || (_desc->m_status & profiler::ON) == 0)
|
||||
return;
|
||||
|
||||
if (THIS_THREAD == nullptr)
|
||||
registerThread();
|
||||
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
if (!THIS_THREAD->allowChildren && (_desc->m_status & FORCE_ON_FLAG) == 0)
|
||||
if (THIS_THREAD->stackSize > 0 || (!THIS_THREAD->allowChildren && (_desc->m_status & FORCE_ON_FLAG) == 0))
|
||||
return;
|
||||
#else
|
||||
if (THIS_THREAD->stackSize > 0)
|
||||
// Prevent from store values until frame, which has been opened when profiler was disabled, finish
|
||||
return;
|
||||
#endif
|
||||
|
||||
@ -807,51 +805,42 @@ void ProfileManager::storeValue(const BaseBlockDescriptor* _desc, DataType _type
|
||||
|
||||
bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
|
||||
{
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
if (state == EASY_PROF_DISABLED || (_desc->m_status & profiler::ON) == 0)
|
||||
if (!isEnabled() || (_desc->m_status & profiler::ON) == 0)
|
||||
return false;
|
||||
|
||||
/*if (state == EASY_PROF_DUMP)
|
||||
{
|
||||
if (THIS_THREAD == nullptr || THIS_THREAD->halt)
|
||||
return false;
|
||||
}
|
||||
else*/
|
||||
if (THIS_THREAD == nullptr)
|
||||
{
|
||||
registerThread();
|
||||
}
|
||||
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
if (!THIS_THREAD->allowChildren && (_desc->m_status & FORCE_ON_FLAG) == 0)
|
||||
if (THIS_THREAD->stackSize > 0 || (!THIS_THREAD->allowChildren && (_desc->m_status & FORCE_ON_FLAG) == 0))
|
||||
return false;
|
||||
#else
|
||||
if (THIS_THREAD->stackSize > 0)
|
||||
// Prevent from store block until frame, which has been opened when profiler was disabled, finish
|
||||
return false;
|
||||
#endif
|
||||
|
||||
const auto time = getCurrentTime();
|
||||
THIS_THREAD->storeBlock(profiler::Block(time, time, _desc->id(), _runtimeName));
|
||||
THIS_THREAD->putMarkIfEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime)
|
||||
{
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
if (state == EASY_PROF_DISABLED || (_desc->m_status & profiler::ON) == 0)
|
||||
if (!isEnabled() || (_desc->m_status & profiler::ON) == 0)
|
||||
return false;
|
||||
|
||||
/*if (state == EASY_PROF_DUMP)
|
||||
{
|
||||
if (THIS_THREAD == nullptr || THIS_THREAD->halt)
|
||||
return false;
|
||||
}
|
||||
else*/
|
||||
if (THIS_THREAD == nullptr)
|
||||
{
|
||||
registerThread();
|
||||
}
|
||||
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
if (!THIS_THREAD->allowChildren && (_desc->m_status & FORCE_ON_FLAG) == 0)
|
||||
if (THIS_THREAD->stackSize > 0 || (!THIS_THREAD->allowChildren && (_desc->m_status & FORCE_ON_FLAG) == 0))
|
||||
return false;
|
||||
#else
|
||||
if (THIS_THREAD->stackSize > 0)
|
||||
// Prevent from store block until frame, which has been opened when profiler was disabled, finish
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@ -859,6 +848,8 @@ bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, cons
|
||||
THIS_THREAD->storeBlock(b);
|
||||
b.m_end = b.m_begin;
|
||||
|
||||
THIS_THREAD->putMarkIfEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -879,6 +870,7 @@ void ProfileManager::storeBlockForce(const profiler::BaseBlockDescriptor* _desc,
|
||||
|
||||
_timestamp = getCurrentTime();
|
||||
THIS_THREAD->storeBlock(profiler::Block(_timestamp, _timestamp, _desc->id(), _runtimeName));
|
||||
THIS_THREAD->putMark();
|
||||
}
|
||||
|
||||
void ProfileManager::storeBlockForce2(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp)
|
||||
@ -895,11 +887,7 @@ void ProfileManager::storeBlockForce2(const profiler::BaseBlockDescriptor* _desc
|
||||
#endif
|
||||
|
||||
THIS_THREAD->storeBlock(profiler::Block(_timestamp, _timestamp, _desc->id(), _runtimeName));
|
||||
}
|
||||
|
||||
void ProfileManager::storeBlockForce2(ThreadStorage& _registeredThread, const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp)
|
||||
{
|
||||
_registeredThread.storeBlock(profiler::Block(_timestamp, _timestamp, _desc->id(), _runtimeName));
|
||||
THIS_THREAD->putMark();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -911,58 +899,28 @@ void ProfileManager::beginBlock(Block& _block)
|
||||
|
||||
if (++THIS_THREAD->stackSize > 1)
|
||||
{
|
||||
// _block is a sibling of current opened frame and this frame has been opened
|
||||
// before profiler was enabled. This _block should be ignored.
|
||||
_block.m_status = profiler::OFF;
|
||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||
return;
|
||||
}
|
||||
|
||||
bool empty = true;
|
||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||
if (state ==
|
||||
//switch (state)
|
||||
//{
|
||||
EASY_PROF_DISABLED)
|
||||
{
|
||||
_block.m_status = profiler::OFF;
|
||||
//THIS_THREAD->halt = false;
|
||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||
beginFrame();
|
||||
return;
|
||||
}
|
||||
if (!isEnabled())
|
||||
{
|
||||
// _block is a top-level block (a.k.a. frame).
|
||||
// It should be ignored because profiler is disabled.
|
||||
_block.m_status = profiler::OFF;
|
||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||
beginFrame(); // FPS counter
|
||||
return;
|
||||
}
|
||||
|
||||
/*case EASY_PROF_DUMP:
|
||||
{
|
||||
const bool halt = THIS_THREAD->halt;
|
||||
if (halt || THIS_THREAD->blocks.openedList.empty())
|
||||
{
|
||||
_block.m_status = profiler::OFF;
|
||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||
|
||||
if (!halt)
|
||||
{
|
||||
THIS_THREAD->halt = true;
|
||||
beginFrame();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
empty = false;
|
||||
break;
|
||||
}*/
|
||||
|
||||
//default:
|
||||
else
|
||||
{
|
||||
empty = THIS_THREAD->blocks.openedList.empty();
|
||||
//break;
|
||||
}
|
||||
//}
|
||||
// Profiler is enabled. Begin block.
|
||||
|
||||
THIS_THREAD->stackSize = 0;
|
||||
//THIS_THREAD->halt = false;
|
||||
|
||||
auto blockStatus = _block.m_status;
|
||||
const auto blockStatus = _block.m_status;
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
if (THIS_THREAD->allowChildren)
|
||||
{
|
||||
@ -983,11 +941,8 @@ void ProfileManager::beginBlock(Block& _block)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (empty)
|
||||
{
|
||||
beginFrame();
|
||||
THIS_THREAD->markProfilingFrameStarted();
|
||||
}
|
||||
if (THIS_THREAD->blocks.openedList.empty())
|
||||
beginFrame(); // FPS counter
|
||||
|
||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||
}
|
||||
@ -1017,22 +972,25 @@ void ProfileManager::endBlock()
|
||||
{
|
||||
if (--THIS_THREAD->stackSize > 0)
|
||||
{
|
||||
// Just pop child blocks from stack until frame, which
|
||||
// has been opened before profiler was enabled, finish.
|
||||
THIS_THREAD->popSilent();
|
||||
return;
|
||||
}
|
||||
|
||||
THIS_THREAD->stackSize = 0;
|
||||
if (/*THIS_THREAD->halt ||*/ m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_DISABLED)
|
||||
if (!isEnabled())
|
||||
{
|
||||
THIS_THREAD->popSilent();
|
||||
endFrame();
|
||||
endFrame(); // FPS counter
|
||||
return;
|
||||
}
|
||||
|
||||
if (THIS_THREAD->blocks.openedList.empty())
|
||||
auto& currentThreadStack = THIS_THREAD->blocks.openedList;
|
||||
if (currentThreadStack.empty())
|
||||
return;
|
||||
|
||||
Block& top = THIS_THREAD->blocks.openedList.back();
|
||||
Block& top = currentThreadStack.back();
|
||||
if (top.m_status & profiler::ON)
|
||||
{
|
||||
if (!top.finished())
|
||||
@ -1041,29 +999,27 @@ void ProfileManager::endBlock()
|
||||
}
|
||||
else
|
||||
{
|
||||
top.m_end = top.m_begin; // this is to restrict endBlock() call inside ~Block()
|
||||
// This is to restrict endBlock() call inside ~Block()
|
||||
top.m_end = top.m_begin;
|
||||
}
|
||||
|
||||
if (!top.m_isScoped)
|
||||
THIS_THREAD->nonscopedBlocks.pop();
|
||||
|
||||
THIS_THREAD->blocks.openedList.pop_back();
|
||||
const bool empty = THIS_THREAD->blocks.openedList.empty();
|
||||
if (empty)
|
||||
currentThreadStack.pop_back();
|
||||
if (currentThreadStack.empty())
|
||||
{
|
||||
THIS_THREAD->markProfilingFrameEnded();
|
||||
endFrame();
|
||||
THIS_THREAD->putMark();
|
||||
endFrame(); // FPS counter
|
||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||
THIS_THREAD->allowChildren = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
THIS_THREAD->allowChildren =
|
||||
((THIS_THREAD->blocks.openedList.back().get().m_status & profiler::OFF_RECURSIVE) == 0);
|
||||
}
|
||||
#else
|
||||
}
|
||||
((currentThreadStack.back().get().m_status & profiler::OFF_RECURSIVE) == 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin)
|
||||
@ -1114,7 +1070,8 @@ void ProfileManager::endFrame()
|
||||
|
||||
const profiler::timestamp_t duration = THIS_THREAD->endFrame();
|
||||
|
||||
if (THIS_THREAD_FRAME_T_RESET_MAX) THIS_THREAD_FRAME_T_MAX = 0;
|
||||
if (THIS_THREAD_FRAME_T_RESET_MAX)
|
||||
THIS_THREAD_FRAME_T_MAX = 0;
|
||||
THIS_THREAD_FRAME_T_RESET_MAX = false;
|
||||
|
||||
THIS_THREAD_FRAME_T_CUR = duration;
|
||||
@ -1125,7 +1082,7 @@ void ProfileManager::endFrame()
|
||||
|
||||
if (THIS_THREAD_IS_MAIN)
|
||||
{
|
||||
if (m_frameAvgReset.exchange(false, std::memory_order_release) || THIS_THREAD_FRAME_T_RESET_AVG)
|
||||
if (m_frameAvgReset.exchange(false, std::memory_order_acq_rel) || THIS_THREAD_FRAME_T_RESET_AVG)
|
||||
{
|
||||
if (THIS_THREAD_N_FRAMES > 0)
|
||||
m_frameAvg.store(THIS_THREAD_FRAME_T_ACC / THIS_THREAD_N_FRAMES, std::memory_order_release);
|
||||
@ -1141,7 +1098,7 @@ void ProfileManager::endFrame()
|
||||
}
|
||||
|
||||
const auto maxDuration = m_frameMax.load(std::memory_order_acquire);
|
||||
if (m_frameMaxReset.exchange(false, std::memory_order_release) || duration > maxDuration)
|
||||
if (m_frameMaxReset.exchange(false, std::memory_order_acq_rel) || duration > maxDuration)
|
||||
m_frameMax.store(duration, std::memory_order_release);
|
||||
|
||||
m_frameCur.store(duration, std::memory_order_release);
|
||||
@ -1196,9 +1153,7 @@ void ProfileManager::setEnabled(bool isEnable)
|
||||
guard_lock_t lock(m_dumpSpin);
|
||||
|
||||
auto time = getCurrentTime();
|
||||
const auto status = isEnable ? EASY_PROF_ENABLED : EASY_PROF_DISABLED;
|
||||
const auto prev = m_profilerStatus.exchange(status, std::memory_order_acq_rel);
|
||||
if (prev == status)
|
||||
if (m_profilerStatus.exchange(isEnable, std::memory_order_acq_rel) == isEnable)
|
||||
return;
|
||||
|
||||
if (isEnable)
|
||||
@ -1215,11 +1170,6 @@ void ProfileManager::setEnabled(bool isEnable)
|
||||
}
|
||||
}
|
||||
|
||||
bool ProfileManager::isEnabled() const
|
||||
{
|
||||
return m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_ENABLED;
|
||||
}
|
||||
|
||||
void ProfileManager::setEventTracingEnabled(bool _isEnable)
|
||||
{
|
||||
m_isEventTracingEnabled.store(_isEnable, std::memory_order_release);
|
||||
@ -1284,15 +1234,13 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
|
||||
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 (state == EASY_PROF_ENABLED) {
|
||||
//m_profilerStatus.store(EASY_PROF_DUMP, std::memory_order_release);
|
||||
m_profilerStatus.store(EASY_PROF_DISABLED, std::memory_order_release);
|
||||
if (isEnabled())
|
||||
{
|
||||
m_profilerStatus.store(false, std::memory_order_release);
|
||||
disableEventTracer();
|
||||
m_endTime = getCurrentTime();
|
||||
}
|
||||
@ -1303,50 +1251,13 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
|
||||
m_dumpSpin.unlock();
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
||||
// 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.
|
||||
// This is much better than inserting spin-lock or atomic variable store/load into each storeBlock operation.
|
||||
//
|
||||
// Note: this means - wait for all ThreadStorage::storeBlock() to finish.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
|
||||
// wait for all threads finish opened frames
|
||||
EASY_LOG_ONLY(bool logged = false);
|
||||
for (auto thread_it = m_threads.begin(), end = m_threads.end(); thread_it != end;)
|
||||
{
|
||||
if (_async && m_stopDumping.load(std::memory_order_acquire))
|
||||
{
|
||||
if (_lockSpin)
|
||||
m_dumpSpin.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!thread_it->second.profiledFrameOpened.load(std::memory_order_acquire))
|
||||
{
|
||||
++thread_it;
|
||||
EASY_LOG_ONLY(logged = false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EASY_LOG_ONLY(
|
||||
if (!logged)
|
||||
{
|
||||
logged = true;
|
||||
if (thread_it->second.named)
|
||||
EASY_WARNING("Waiting for thread \"" << thread_it->second.name << "\" finish opened frame (which is top EASY_BLOCK for this thread)...\n");
|
||||
else
|
||||
EASY_WARNING("Waiting for thread " << thread_it->first << " finish opened frame (which is top EASY_BLOCK for this thread)...\n");
|
||||
}
|
||||
);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
m_profilerStatus.store(EASY_PROF_DISABLED, std::memory_order_release);
|
||||
|
||||
EASY_LOGMSG("All threads have closed frames\n");
|
||||
EASY_LOGMSG("Disabled profiling\n");
|
||||
*/
|
||||
|
||||
// This is to make sure that no new descriptors or new threads will be
|
||||
// added until we finish sending data.
|
||||
m_spin.lock();
|
||||
@ -1657,7 +1568,7 @@ const char* ProfileManager::registerThread(const char* name)
|
||||
|
||||
void ProfileManager::setBlockStatus(block_id_t _id, EasyBlockStatus _status)
|
||||
{
|
||||
if (m_profilerStatus.load(std::memory_order_acquire) != EASY_PROF_DISABLED)
|
||||
if (isEnabled())
|
||||
return; // Changing blocks statuses is restricted while profile session is active
|
||||
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
@ -1671,7 +1582,7 @@ void ProfileManager::setBlockStatus(block_id_t _id, EasyBlockStatus _status)
|
||||
|
||||
void ProfileManager::startListen(uint16_t _port)
|
||||
{
|
||||
if (!m_isAlreadyListening.exchange(true, std::memory_order_release))
|
||||
if (!m_isAlreadyListening.exchange(true, std::memory_order_acq_rel))
|
||||
{
|
||||
m_stopListen.store(false, std::memory_order_release);
|
||||
m_listenThread = std::thread(&ProfileManager::listen, this, _port);
|
||||
@ -1741,9 +1652,7 @@ void ProfileManager::listen(uint16_t _port)
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
const profiler::net::EasyProfilerStatus connectionReply(
|
||||
m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_ENABLED,
|
||||
m_isEventTracingEnabled.load(std::memory_order_acquire), wasLowPriorityET);
|
||||
const profiler::net::EasyProfilerStatus connectionReply(isEnabled(), isEventTracingEnabled(), wasLowPriorityET);
|
||||
|
||||
bytes = socket.send(&connectionReply, sizeof(profiler::net::EasyProfilerStatus));
|
||||
hasConnect = bytes > 0;
|
||||
@ -1852,8 +1761,8 @@ void ProfileManager::listen(uint16_t _port)
|
||||
EASY_FORCE_EVENT(t, "StartCapture", EASY_COLOR_START, profiler::OFF);
|
||||
|
||||
m_dumpSpin.lock();
|
||||
const auto prev = m_profilerStatus.exchange(EASY_PROF_ENABLED, std::memory_order_release);
|
||||
if (prev != EASY_PROF_ENABLED) {
|
||||
if (!m_profilerStatus.exchange(true, std::memory_order_acq_rel))
|
||||
{
|
||||
enableEventTracer();
|
||||
m_beginTime = t;
|
||||
}
|
||||
@ -1875,9 +1784,8 @@ void ProfileManager::listen(uint16_t _port)
|
||||
|
||||
m_dumpSpin.lock();
|
||||
auto time = getCurrentTime();
|
||||
//const auto prev = m_profilerStatus.exchange(EASY_PROF_DUMP, std::memory_order_release);
|
||||
const auto prev = m_profilerStatus.exchange(EASY_PROF_DISABLED, std::memory_order_acq_rel);
|
||||
if (prev == EASY_PROF_ENABLED) {
|
||||
if (m_profilerStatus.exchange(false, std::memory_order_acq_rel))
|
||||
{
|
||||
disableEventTracer();
|
||||
m_endTime = time;
|
||||
}
|
||||
@ -1958,8 +1866,7 @@ void ProfileManager::listen(uint16_t _port)
|
||||
EASY_ERROR("Can not send block descriptions. Bad std::stringstream.tellp() == -1");
|
||||
}
|
||||
|
||||
replyMessage.type = profiler::net::MessageType::Reply_Blocks_Description_End
|
||||
;
|
||||
replyMessage.type = profiler::net::MessageType::Reply_Blocks_Description_End;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
@ -1969,21 +1876,16 @@ void ProfileManager::listen(uint16_t _port)
|
||||
case profiler::net::MessageType::Change_Block_Status:
|
||||
{
|
||||
auto data = reinterpret_cast<const profiler::net::BlockStatusMessage*>(message);
|
||||
|
||||
EASY_LOGMSG("receive MessageType::ChangeBLock_Status id=" << data->id << " status=" << data->status << std::endl);
|
||||
|
||||
setBlockStatus(data->id, static_cast<::profiler::EasyBlockStatus>(data->status));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case profiler::net::MessageType::Change_Event_Tracing_Status:
|
||||
{
|
||||
auto data = reinterpret_cast<const profiler::net::BoolMessage*>(message);
|
||||
|
||||
EASY_LOGMSG("receive MessageType::Change_Event_Tracing_Status on=" << data->flag << std::endl);
|
||||
|
||||
m_isEventTracingEnabled.store(data->flag, std::memory_order_release);
|
||||
setEventTracingEnabled(data->flag);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -149,8 +149,12 @@ public:
|
||||
profiler::timestamp_t maxFrameDuration();
|
||||
profiler::timestamp_t avgFrameDuration();
|
||||
profiler::timestamp_t curFrameDuration() const;
|
||||
|
||||
void setEnabled(bool isEnable);
|
||||
bool isEnabled() const;
|
||||
EASY_FORCE_INLINE bool isEnabled() const {
|
||||
return m_profilerStatus.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void setEventTracingEnabled(bool _isEnable);
|
||||
bool isEventTracingEnabled() const;
|
||||
uint32_t dumpBlocksToFile(const char* filename);
|
||||
@ -187,7 +191,6 @@ private:
|
||||
|
||||
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(ThreadStorage& _registeredThread, const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
|
||||
|
||||
ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id);
|
||||
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
|
||||
|
@ -53,10 +53,8 @@ ThreadStorage::ThreadStorage()
|
||||
, named(false)
|
||||
, guarded(false)
|
||||
, frameOpened(false)
|
||||
//, halt(false)
|
||||
{
|
||||
expired = ATOMIC_VAR_INIT(0);
|
||||
profiledFrameOpened = ATOMIC_VAR_INIT(false);
|
||||
}
|
||||
|
||||
void ThreadStorage::storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, size_t _size, bool _isArray, profiler::ValueId _vin)
|
||||
@ -70,6 +68,8 @@ void ThreadStorage::storeValue(profiler::timestamp_t _timestamp, profiler::block
|
||||
memcpy(cdata + sizeof(profiler::ArbitraryValue), _data, _size);
|
||||
|
||||
blocks.frameMemorySize += serializedDataSize;
|
||||
|
||||
putMarkIfEmpty();
|
||||
}
|
||||
|
||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
@ -83,7 +83,10 @@ void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
EASY_THREAD_LOCAL static profiler::timestamp_t endTime = 0ULL;
|
||||
#endif
|
||||
|
||||
uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
const uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND == 0
|
||||
const
|
||||
#endif
|
||||
uint16_t serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + nameLength + 1);
|
||||
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
||||
@ -114,10 +117,21 @@ void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThreadStorage::storeBlockForce(const profiler::Block& block)
|
||||
{
|
||||
const uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
const uint16_t serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + nameLength + 1);
|
||||
|
||||
void* data = blocks.closedList.marked_allocate(serializedDataSize);
|
||||
::new (data) profiler::SerializedBlock(block, nameLength);
|
||||
blocks.usedMemorySize += serializedDataSize;
|
||||
}
|
||||
|
||||
void ThreadStorage::storeCSwitch(const CSwitchBlock& block)
|
||||
{
|
||||
uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
uint16_t serializedDataSize = static_cast<uint16_t>(sizeof(profiler::CSwitchEvent) + nameLength + 1);
|
||||
const uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
const uint16_t serializedDataSize = static_cast<uint16_t>(sizeof(profiler::CSwitchEvent) + nameLength + 1);
|
||||
|
||||
void* data = sync.closedList.allocate(serializedDataSize);
|
||||
::new (data) profiler::SerializedCSwitch(block, nameLength);
|
||||
sync.usedMemorySize += serializedDataSize;
|
||||
@ -156,15 +170,15 @@ profiler::timestamp_t ThreadStorage::endFrame()
|
||||
return getCurrentTime() - frameStartTime;
|
||||
}
|
||||
|
||||
void ThreadStorage::markProfilingFrameStarted()
|
||||
void ThreadStorage::putMark()
|
||||
{
|
||||
profiledFrameOpened.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
void ThreadStorage::markProfilingFrameEnded()
|
||||
{
|
||||
profiledFrameOpened.store(false, std::memory_order_release);
|
||||
blocks.closedList.put_mark();
|
||||
blocks.usedMemorySize += blocks.frameMemorySize;
|
||||
blocks.frameMemorySize = 0;
|
||||
}
|
||||
|
||||
void ThreadStorage::putMarkIfEmpty()
|
||||
{
|
||||
if (!frameOpened)
|
||||
putMark();
|
||||
}
|
||||
|
@ -105,29 +105,25 @@ struct ThreadStorage EASY_FINAL
|
||||
profiler::timestamp_t frameStartTime; ///< Current frame start time. Used to calculate FPS.
|
||||
const profiler::thread_id_t id; ///< Thread ID
|
||||
std::atomic<char> expired; ///< Is thread expired
|
||||
std::atomic_bool profiledFrameOpened; ///< Is new profiled frame opened (this is true when profiling is enabled and there is an opened frame) \sa frameOpened
|
||||
int32_t stackSize; ///< Current thread stack depth. Used when switching profiler state to begin collecting blocks only when new frame would be opened.
|
||||
bool allowChildren; ///< False if one of previously opened blocks has OFF_RECURSIVE or ON_WITHOUT_CHILDREN status
|
||||
bool named; ///< True if thread name was set
|
||||
bool guarded; ///< True if thread has been registered using ThreadGuard
|
||||
bool frameOpened; ///< Is new frame opened (this does not depend on profiling status) \sa profiledFrameOpened
|
||||
//bool halt; ///< This is set to true when new frame started while dumping blocks. Used to restrict collecting blocks during dumping process.
|
||||
|
||||
void storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, size_t _size, bool _isArray, profiler::ValueId _vin);
|
||||
void storeBlock(const profiler::Block& _block);
|
||||
void storeBlockForce(const profiler::Block& _block);
|
||||
void storeCSwitch(const CSwitchBlock& _block);
|
||||
void clearClosed();
|
||||
void popSilent();
|
||||
|
||||
void beginFrame();
|
||||
profiler::timestamp_t endFrame();
|
||||
void markProfilingFrameStarted();
|
||||
void markProfilingFrameEnded();
|
||||
void putMark();
|
||||
void putMarkIfEmpty();
|
||||
|
||||
ThreadStorage();
|
||||
|
||||
private:
|
||||
|
||||
ThreadStorage(const ThreadStorage&) = delete;
|
||||
ThreadStorage(ThreadStorage&&) = delete;
|
||||
|
||||
|
@ -54,6 +54,21 @@
|
||||
|
||||
#include "common_functions.h"
|
||||
|
||||
template <class T>
|
||||
static QString toString(const profiler::ArbitraryValue& _serializedValue) {
|
||||
return QString::number(_serializedValue.toValue<T>()->value());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static double toReal(const profiler::ArbitraryValue& _serializedValue, int _index) {
|
||||
return static_cast<double>(_serializedValue.toArray<T>()->at(_index));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static double toReal(const profiler::ArbitraryValue& _serializedValue) {
|
||||
return static_cast<double>(_serializedValue.toValue<T>()->value());
|
||||
}
|
||||
|
||||
namespace profiler_gui {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -272,17 +287,17 @@ namespace profiler_gui {
|
||||
switch (_serializedValue.type())
|
||||
{
|
||||
case ::profiler::DataType::Bool: return _serializedValue.toValue<bool>()->value() ? QStringLiteral("true") : QStringLiteral("false");
|
||||
case ::profiler::DataType::Char: return QChar(_serializedValue.toValue<char>()->value());
|
||||
case ::profiler::DataType::Char: return QChar(_serializedValue.toValue<char> ()->value());
|
||||
case ::profiler::DataType::Int8: return QChar(_serializedValue.toValue<int8_t>()->value());
|
||||
case ::profiler::DataType::Uint8: return QString::number(_serializedValue.toValue<uint8_t>()->value());
|
||||
case ::profiler::DataType::Int16: return QString::number(_serializedValue.toValue<int16_t>()->value());
|
||||
case ::profiler::DataType::Uint16: return QString::number(_serializedValue.toValue<uint16_t>()->value());
|
||||
case ::profiler::DataType::Int32: return QString::number(_serializedValue.toValue<int32_t>()->value());
|
||||
case ::profiler::DataType::Uint32: return QString::number(_serializedValue.toValue<uint32_t>()->value());
|
||||
case ::profiler::DataType::Int64: return QString::number(_serializedValue.toValue<int64_t>()->value());
|
||||
case ::profiler::DataType::Uint64: return QString::number(_serializedValue.toValue<uint64_t>()->value());
|
||||
case ::profiler::DataType::Float: return QString::number(_serializedValue.toValue<float>()->value());
|
||||
case ::profiler::DataType::Double: return QString::number(_serializedValue.toValue<double>()->value());
|
||||
case ::profiler::DataType::Uint8: return toString<uint8_t> (_serializedValue);
|
||||
case ::profiler::DataType::Int16: return toString<int16_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint16: return toString<uint16_t>(_serializedValue);
|
||||
case ::profiler::DataType::Int32: return toString<int32_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint32: return toString<uint32_t>(_serializedValue);
|
||||
case ::profiler::DataType::Int64: return toString<int64_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint64: return toString<uint64_t>(_serializedValue);
|
||||
case ::profiler::DataType::Float: return toString<float> (_serializedValue);
|
||||
case ::profiler::DataType::Double: return toString<double> (_serializedValue);
|
||||
case ::profiler::DataType::String: return _serializedValue.data();
|
||||
default: return QStringLiteral("Unknown");
|
||||
}
|
||||
@ -300,16 +315,16 @@ namespace profiler_gui {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
|
||||
case ::profiler::DataType::Char: return static_cast<double>(_serializedValue.toArray<char>()->at(_index));
|
||||
case ::profiler::DataType::Int8: return static_cast<double>(_serializedValue.toArray<int8_t>()->at(_index));
|
||||
case ::profiler::DataType::Uint8: return static_cast<double>(_serializedValue.toArray<uint8_t>()->at(_index));
|
||||
case ::profiler::DataType::Int16: return static_cast<double>(_serializedValue.toArray<int16_t>()->at(_index));
|
||||
case ::profiler::DataType::Uint16: return static_cast<double>(_serializedValue.toArray<uint16_t>()->at(_index));
|
||||
case ::profiler::DataType::Int32: return static_cast<double>(_serializedValue.toArray<int32_t>()->at(_index));
|
||||
case ::profiler::DataType::Uint32: return static_cast<double>(_serializedValue.toArray<uint32_t>()->at(_index));
|
||||
case ::profiler::DataType::Int64: return static_cast<double>(_serializedValue.toArray<int64_t>()->at(_index));
|
||||
case ::profiler::DataType::Uint64: return static_cast<double>(_serializedValue.toArray<uint64_t>()->at(_index));
|
||||
case ::profiler::DataType::Float: return static_cast<double>(_serializedValue.toArray<float>()->at(_index));
|
||||
case ::profiler::DataType::Char: return toReal<char> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Int8: return toReal<int8_t> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Uint8: return toReal<uint8_t> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Int16: return toReal<int16_t> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Uint16: return toReal<uint16_t>(_serializedValue, _index);
|
||||
case ::profiler::DataType::Int32: return toReal<int32_t> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Uint32: return toReal<uint32_t>(_serializedValue, _index);
|
||||
case ::profiler::DataType::Int64: return toReal<int64_t> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Uint64: return toReal<uint64_t>(_serializedValue, _index);
|
||||
case ::profiler::DataType::Float: return toReal<float> (_serializedValue, _index);
|
||||
case ::profiler::DataType::Double: return _serializedValue.toArray<double>()->at(_index);
|
||||
case ::profiler::DataType::String: return static_cast<double>(_serializedValue.data()[_index]);
|
||||
default: return 0;
|
||||
@ -324,16 +339,16 @@ namespace profiler_gui {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
|
||||
case ::profiler::DataType::Char: return static_cast<double>(_serializedValue.toValue<char>()->value());
|
||||
case ::profiler::DataType::Int8: return static_cast<double>(_serializedValue.toValue<int8_t>()->value());
|
||||
case ::profiler::DataType::Uint8: return static_cast<double>(_serializedValue.toValue<uint8_t>()->value());
|
||||
case ::profiler::DataType::Int16: return static_cast<double>(_serializedValue.toValue<int16_t>()->value());
|
||||
case ::profiler::DataType::Uint16: return static_cast<double>(_serializedValue.toValue<uint16_t>()->value());
|
||||
case ::profiler::DataType::Int32: return static_cast<double>(_serializedValue.toValue<int32_t>()->value());
|
||||
case ::profiler::DataType::Uint32: return static_cast<double>(_serializedValue.toValue<uint32_t>()->value());
|
||||
case ::profiler::DataType::Int64: return static_cast<double>(_serializedValue.toValue<int64_t>()->value());
|
||||
case ::profiler::DataType::Uint64: return static_cast<double>(_serializedValue.toValue<uint64_t>()->value());
|
||||
case ::profiler::DataType::Float: return static_cast<double>(_serializedValue.toValue<float>()->value());
|
||||
case ::profiler::DataType::Char: return toReal<char> (_serializedValue);
|
||||
case ::profiler::DataType::Int8: return toReal<int8_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint8: return toReal<uint8_t> (_serializedValue);
|
||||
case ::profiler::DataType::Int16: return toReal<int16_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint16: return toReal<uint16_t>(_serializedValue);
|
||||
case ::profiler::DataType::Int32: return toReal<int32_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint32: return toReal<uint32_t>(_serializedValue);
|
||||
case ::profiler::DataType::Int64: return toReal<int64_t> (_serializedValue);
|
||||
case ::profiler::DataType::Uint64: return toReal<uint64_t>(_serializedValue);
|
||||
case ::profiler::DataType::Float: return toReal<float> (_serializedValue);
|
||||
case ::profiler::DataType::Double: return _serializedValue.toValue<double>()->value();
|
||||
case ::profiler::DataType::String: return static_cast<double>(_serializedValue.data()[_index]);
|
||||
default: return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user