0
0
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:
Victor Zarubkin 2018-01-08 02:56:51 +03:00
parent 2c008b77ed
commit 22c61a42b5
6 changed files with 224 additions and 235 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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