mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
#75 [Core] No more waiting behavior when dumping blocks. Current solution resolves possible dead-lock but restricts any Events out of Frame bounds (You can see that the last event for LoadingResources thread in the profiler_sample is always absent).
This commit is contained in:
parent
a9e6ac084b
commit
d049a1339e
@ -91,7 +91,7 @@ The Apache License, Version 2.0 (the "License");
|
|||||||
template <uint32_t ALIGNMENT>
|
template <uint32_t ALIGNMENT>
|
||||||
EASY_FORCE_INLINE bool is_aligned(void* ptr)
|
EASY_FORCE_INLINE bool is_aligned(void* ptr)
|
||||||
{
|
{
|
||||||
static_assert(ALIGNMENT % 2 == 0, "Alignment must be a power of two.");
|
static_assert((ALIGNMENT & 1) == 0, "Alignment must be a power of two.");
|
||||||
return ((uintptr_t)ptr & (ALIGNMENT-1)) == 0;
|
return ((uintptr_t)ptr & (ALIGNMENT-1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +119,7 @@ EASY_FORCE_INLINE void unaligned_zero32(void* ptr)
|
|||||||
|
|
||||||
EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
|
EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
|
||||||
{
|
{
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
*(uint64_t*)ptr = 0;
|
|
||||||
#else
|
|
||||||
// Assume unaligned is more common.
|
// Assume unaligned is more common.
|
||||||
if (!is_aligned<alignof(uint64_t)>(ptr)) {
|
if (!is_aligned<alignof(uint64_t)>(ptr)) {
|
||||||
((char*)ptr)[0] = 0;
|
((char*)ptr)[0] = 0;
|
||||||
@ -133,20 +131,21 @@ EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
|
|||||||
((char*)ptr)[6] = 0;
|
((char*)ptr)[6] = 0;
|
||||||
((char*)ptr)[7] = 0;
|
((char*)ptr)[7] = 0;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
*(uint64_t*)ptr = 0;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
*(uint64_t*)ptr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
EASY_FORCE_INLINE void unaligned_store16(void* ptr, T val)
|
EASY_FORCE_INLINE void unaligned_store16(void* ptr, T val)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 2, "16 bit type required.");
|
static_assert(sizeof(T) == 2, "16 bit type required.");
|
||||||
|
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
*(T*)ptr = val;
|
*(T*)ptr = val;
|
||||||
#else
|
#else
|
||||||
const char* const temp = (char*)&val;
|
const char* const temp = (const char*)&val;
|
||||||
((char*)ptr)[0] = temp[0];
|
((char*)ptr)[0] = temp[0];
|
||||||
((char*)ptr)[1] = temp[1];
|
((char*)ptr)[1] = temp[1];
|
||||||
#endif
|
#endif
|
||||||
@ -156,10 +155,11 @@ template <typename T>
|
|||||||
EASY_FORCE_INLINE void unaligned_store32(void* ptr, T val)
|
EASY_FORCE_INLINE void unaligned_store32(void* ptr, T val)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 4, "32 bit type required.");
|
static_assert(sizeof(T) == 4, "32 bit type required.");
|
||||||
|
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
*(T*)ptr = val;
|
*(T*)ptr = val;
|
||||||
#else
|
#else
|
||||||
const char* const temp = (char*)&val;
|
const char* const temp = (const char*)&val;
|
||||||
((char*)ptr)[0] = temp[0];
|
((char*)ptr)[0] = temp[0];
|
||||||
((char*)ptr)[1] = temp[1];
|
((char*)ptr)[1] = temp[1];
|
||||||
((char*)ptr)[2] = temp[2];
|
((char*)ptr)[2] = temp[2];
|
||||||
@ -171,12 +171,11 @@ template <typename T>
|
|||||||
EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
|
EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 8, "64 bit type required.");
|
static_assert(sizeof(T) == 8, "64 bit type required.");
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
|
||||||
*(T*)ptr = val;
|
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
#else
|
|
||||||
const char* const temp = (char*)&val;
|
|
||||||
// Assume unaligned is more common.
|
// Assume unaligned is more common.
|
||||||
if (!is_aligned<alignof(T)>(ptr)) {
|
if (!is_aligned<alignof(T)>(ptr)) {
|
||||||
|
const char* const temp = (const char*)&val;
|
||||||
((char*)ptr)[0] = temp[0];
|
((char*)ptr)[0] = temp[0];
|
||||||
((char*)ptr)[1] = temp[1];
|
((char*)ptr)[1] = temp[1];
|
||||||
((char*)ptr)[2] = temp[2];
|
((char*)ptr)[2] = temp[2];
|
||||||
@ -186,22 +185,23 @@ EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
|
|||||||
((char*)ptr)[6] = temp[6];
|
((char*)ptr)[6] = temp[6];
|
||||||
((char*)ptr)[7] = temp[7];
|
((char*)ptr)[7] = temp[7];
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
*(T*)ptr = val;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
*(T*)ptr = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
EASY_FORCE_INLINE T unaligned_load16(const void* ptr)
|
EASY_FORCE_INLINE T unaligned_load16(const void* ptr)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 2, "16 bit type required.");
|
static_assert(sizeof(T) == 2, "16 bit type required.");
|
||||||
|
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
return *(T*)ptr;
|
return *(const T*)ptr;
|
||||||
#else
|
#else
|
||||||
T value;
|
T value;
|
||||||
((char*)&value)[0] = ((char*)ptr)[0];
|
((char*)&value)[0] = ((const char*)ptr)[0];
|
||||||
((char*)&value)[1] = ((char*)ptr)[1];
|
((char*)&value)[1] = ((const char*)ptr)[1];
|
||||||
return value;
|
return value;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -210,28 +210,30 @@ template <typename T>
|
|||||||
EASY_FORCE_INLINE T unaligned_load16(const void* ptr, T* val)
|
EASY_FORCE_INLINE T unaligned_load16(const void* ptr, T* val)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 2, "16 bit type required.");
|
static_assert(sizeof(T) == 2, "16 bit type required.");
|
||||||
|
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
*val = *(T*)ptr;
|
*val = *(const T*)ptr;
|
||||||
return *val;
|
|
||||||
#else
|
#else
|
||||||
((char*)val)[0] = ((char*)ptr)[0];
|
((char*)val)[0] = ((const char*)ptr)[0];
|
||||||
((char*)val)[1] = ((char*)ptr)[1];
|
((char*)val)[1] = ((const char*)ptr)[1];
|
||||||
return *val;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return *val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
EASY_FORCE_INLINE T unaligned_load32(const void* ptr)
|
EASY_FORCE_INLINE T unaligned_load32(const void* ptr)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 4, "32 bit type required.");
|
static_assert(sizeof(T) == 4, "32 bit type required.");
|
||||||
|
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
return *(T*)ptr;
|
return *(const T*)ptr;
|
||||||
#else
|
#else
|
||||||
T value;
|
T value;
|
||||||
((char*)&value)[0] = ((char*)ptr)[0];
|
((char*)&value)[0] = ((const char*)ptr)[0];
|
||||||
((char*)&value)[1] = ((char*)ptr)[1];
|
((char*)&value)[1] = ((const char*)ptr)[1];
|
||||||
((char*)&value)[2] = ((char*)ptr)[2];
|
((char*)&value)[2] = ((const char*)ptr)[2];
|
||||||
((char*)&value)[3] = ((char*)ptr)[3];
|
((char*)&value)[3] = ((const char*)ptr)[3];
|
||||||
return value;
|
return value;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -240,65 +242,63 @@ template <typename T>
|
|||||||
EASY_FORCE_INLINE T unaligned_load32(const void* ptr, T* val)
|
EASY_FORCE_INLINE T unaligned_load32(const void* ptr, T* val)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 4, "32 bit type required.");
|
static_assert(sizeof(T) == 4, "32 bit type required.");
|
||||||
|
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
*val = *(T*)ptr;
|
*val = *(const T*)ptr;
|
||||||
#else
|
#else
|
||||||
((char*)&val)[0] = ((char*)ptr)[0];
|
((char*)&val)[0] = ((const char*)ptr)[0];
|
||||||
((char*)&val)[1] = ((char*)ptr)[1];
|
((char*)&val)[1] = ((const char*)ptr)[1];
|
||||||
((char*)&val)[2] = ((char*)ptr)[2];
|
((char*)&val)[2] = ((const char*)ptr)[2];
|
||||||
((char*)&val)[3] = ((char*)ptr)[3];
|
((char*)&val)[3] = ((const char*)ptr)[3];
|
||||||
return *val;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return *val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
EASY_FORCE_INLINE T unaligned_load64(const void* ptr)
|
EASY_FORCE_INLINE T unaligned_load64(const void* ptr)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 8, "64 bit type required.");
|
static_assert(sizeof(T) == 8, "64 bit type required.");
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
|
||||||
return *(T*)ptr;
|
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
#else
|
|
||||||
if (!is_aligned<alignof(T)>(ptr)) {
|
if (!is_aligned<alignof(T)>(ptr)) {
|
||||||
T value;
|
T value;
|
||||||
((char*)&value)[0] = ((char*)ptr)[0];
|
((char*)&value)[0] = ((const char*)ptr)[0];
|
||||||
((char*)&value)[1] = ((char*)ptr)[1];
|
((char*)&value)[1] = ((const char*)ptr)[1];
|
||||||
((char*)&value)[2] = ((char*)ptr)[2];
|
((char*)&value)[2] = ((const char*)ptr)[2];
|
||||||
((char*)&value)[3] = ((char*)ptr)[3];
|
((char*)&value)[3] = ((const char*)ptr)[3];
|
||||||
((char*)&value)[4] = ((char*)ptr)[4];
|
((char*)&value)[4] = ((const char*)ptr)[4];
|
||||||
((char*)&value)[5] = ((char*)ptr)[5];
|
((char*)&value)[5] = ((const char*)ptr)[5];
|
||||||
((char*)&value)[6] = ((char*)ptr)[6];
|
((char*)&value)[6] = ((const char*)ptr)[6];
|
||||||
((char*)&value)[7] = ((char*)ptr)[7];
|
((char*)&value)[7] = ((const char*)ptr)[7];
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return *(T*)ptr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return *(const T*)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
|
EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) == 8, "64 bit type required.");
|
static_assert(sizeof(T) == 8, "64 bit type required.");
|
||||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
|
||||||
*val = *(T*)ptr;
|
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||||
#else
|
|
||||||
if (!is_aligned<alignof(T)>(ptr)) {
|
if (!is_aligned<alignof(T)>(ptr)) {
|
||||||
((char*)&val)[0] = ((char*)ptr)[0];
|
((char*)&val)[0] = ((const char*)ptr)[0];
|
||||||
((char*)&val)[1] = ((char*)ptr)[1];
|
((char*)&val)[1] = ((const char*)ptr)[1];
|
||||||
((char*)&val)[2] = ((char*)ptr)[2];
|
((char*)&val)[2] = ((const char*)ptr)[2];
|
||||||
((char*)&val)[3] = ((char*)ptr)[3];
|
((char*)&val)[3] = ((const char*)ptr)[3];
|
||||||
((char*)&val)[4] = ((char*)ptr)[4];
|
((char*)&val)[4] = ((const char*)ptr)[4];
|
||||||
((char*)&val)[5] = ((char*)ptr)[5];
|
((char*)&val)[5] = ((const char*)ptr)[5];
|
||||||
((char*)&val)[6] = ((char*)ptr)[6];
|
((char*)&val)[6] = ((const char*)ptr)[6];
|
||||||
((char*)&val)[7] = ((char*)ptr)[7];
|
((char*)&val)[7] = ((const char*)ptr)[7];
|
||||||
return *val;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*val = *(T*)ptr;
|
|
||||||
return *val;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
*val = *(const T*)ptr;
|
||||||
|
return *val;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -380,16 +380,19 @@ class chunk_allocator
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Used in serialize(): workaround for no constexpr support in MSVC 2013.
|
// Used in serialize(): workaround for no constexpr support in MSVC 2013.
|
||||||
static const int_fast32_t MAX_CHUNK_OFFSET = N - sizeof(uint16_t);
|
EASY_STATIC_CONSTEXPR int_fast32_t MAX_CHUNK_OFFSET = N - sizeof(uint16_t);
|
||||||
static const uint16_t N_MINUS_ONE = N - 1;
|
EASY_STATIC_CONSTEXPR uint16_t N_MINUS_ONE = N - 1;
|
||||||
|
|
||||||
chunk_list m_chunks; ///< List of chunks.
|
chunk_list m_chunks; ///< List of chunks.
|
||||||
uint32_t m_size; ///< Number of elements stored(# of times allocate() has been called.)
|
const chunk* m_markedChunk; ///< Chunk marked by last closed frame
|
||||||
uint16_t m_chunkOffset; ///< Number of bytes used in the current chunk.
|
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.
|
||||||
|
uint16_t m_markedChunkOffset; ///< Last byte in marked chunk for serializing.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
chunk_allocator() : m_size(0), m_chunkOffset(0)
|
chunk_allocator() : m_markedChunk(nullptr), m_size(0), m_markedSize(0), m_chunkOffset(0), m_markedChunkOffset(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,10 +454,22 @@ public:
|
|||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t markedSize() const
|
||||||
|
{
|
||||||
|
return m_markedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool markedEmpty() const
|
||||||
|
{
|
||||||
|
return m_markedSize == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
|
m_markedSize = 0;
|
||||||
m_chunkOffset = 0;
|
m_chunkOffset = 0;
|
||||||
|
m_markedChunk = nullptr;
|
||||||
m_chunks.clear_all_except_last(); // There is always at least one chunk
|
m_chunks.clear_all_except_last(); // There is always at least one chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,11 +494,18 @@ public:
|
|||||||
// too small to cary more than a zero-sized element.
|
// too small to cary more than a zero-sized element.
|
||||||
|
|
||||||
chunk* current = m_chunks.last;
|
chunk* current = m_chunks.last;
|
||||||
|
bool isMarked;
|
||||||
do {
|
do {
|
||||||
|
|
||||||
|
isMarked = (current == m_markedChunk);
|
||||||
const char* data = current->data;
|
const char* data = current->data;
|
||||||
|
|
||||||
|
const int_fast32_t maxOffset = isMarked ? m_markedChunkOffset : MAX_CHUNK_OFFSET;
|
||||||
int_fast32_t chunkOffset = 0; // signed int so overflow is not checked.
|
int_fast32_t chunkOffset = 0; // signed int so overflow is not checked.
|
||||||
uint16_t payloadSize = unaligned_load16<uint16_t>(data);
|
auto payloadSize = unaligned_load16<uint16_t>(data);
|
||||||
while (chunkOffset < MAX_CHUNK_OFFSET && payloadSize != 0) {
|
|
||||||
|
while (chunkOffset < maxOffset && payloadSize != 0)
|
||||||
|
{
|
||||||
const uint16_t chunkSize = sizeof(uint16_t) + payloadSize;
|
const uint16_t chunkSize = sizeof(uint16_t) + payloadSize;
|
||||||
_outputStream.write(data, chunkSize);
|
_outputStream.write(data, chunkSize);
|
||||||
data += chunkSize;
|
data += chunkSize;
|
||||||
@ -492,11 +514,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
current = current->prev;
|
current = current->prev;
|
||||||
} while (current != nullptr);
|
|
||||||
|
} while (current != nullptr && !isMarked);
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void put_mark()
|
||||||
|
{
|
||||||
|
m_markedChunk = m_chunks.last;
|
||||||
|
m_markedSize = m_size;
|
||||||
|
m_markedChunkOffset = m_chunkOffset;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
chunk_allocator(const chunk_allocator&) = delete;
|
chunk_allocator(const chunk_allocator&) = delete;
|
||||||
|
@ -160,9 +160,9 @@ extern const uint32_t EASY_CURRENT_VERSION = EASY_VERSION_INT(EASY_PROFILER_VERS
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
# define EASY_PROF_DISABLED 0
|
# define EASY_PROF_DISABLED false//0
|
||||||
# define EASY_PROF_ENABLED 1
|
# define EASY_PROF_ENABLED true//1
|
||||||
# define EASY_PROF_DUMP 2
|
//# define EASY_PROF_DUMP 2
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -644,7 +644,7 @@ ThreadGuard::~ThreadGuard()
|
|||||||
{
|
{
|
||||||
bool isMarked = false;
|
bool isMarked = false;
|
||||||
EASY_EVENT_RES(isMarked, "ThreadFinished", EASY_COLOR_THREAD_END, ::profiler::FORCE_ON);
|
EASY_EVENT_RES(isMarked, "ThreadFinished", EASY_COLOR_THREAD_END, ::profiler::FORCE_ON);
|
||||||
THIS_THREAD->profiledFrameOpened.store(false, std::memory_order_release);
|
THIS_THREAD->markProfilingFrameEnded();
|
||||||
THIS_THREAD->expired.store(isMarked ? 2 : 1, std::memory_order_release);
|
THIS_THREAD->expired.store(isMarked ? 2 : 1, std::memory_order_release);
|
||||||
THIS_THREAD = nullptr;
|
THIS_THREAD = nullptr;
|
||||||
}
|
}
|
||||||
@ -810,12 +810,13 @@ bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, cons
|
|||||||
if (state == EASY_PROF_DISABLED || (_desc->m_status & profiler::ON) == 0)
|
if (state == EASY_PROF_DISABLED || (_desc->m_status & profiler::ON) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (state == EASY_PROF_DUMP)
|
/*if (state == EASY_PROF_DUMP)
|
||||||
{
|
{
|
||||||
if (THIS_THREAD == nullptr || THIS_THREAD->halt)
|
if (THIS_THREAD == nullptr || THIS_THREAD->halt)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (THIS_THREAD == nullptr)
|
else*/
|
||||||
|
if (THIS_THREAD == nullptr)
|
||||||
{
|
{
|
||||||
registerThread();
|
registerThread();
|
||||||
}
|
}
|
||||||
@ -837,12 +838,13 @@ bool ProfileManager::storeBlock(const profiler::BaseBlockDescriptor* _desc, cons
|
|||||||
if (state == EASY_PROF_DISABLED || (_desc->m_status & profiler::ON) == 0)
|
if (state == EASY_PROF_DISABLED || (_desc->m_status & profiler::ON) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (state == EASY_PROF_DUMP)
|
/*if (state == EASY_PROF_DUMP)
|
||||||
{
|
{
|
||||||
if (THIS_THREAD == nullptr || THIS_THREAD->halt)
|
if (THIS_THREAD == nullptr || THIS_THREAD->halt)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (THIS_THREAD == nullptr)
|
else*/
|
||||||
|
if (THIS_THREAD == nullptr)
|
||||||
{
|
{
|
||||||
registerThread();
|
registerThread();
|
||||||
}
|
}
|
||||||
@ -915,18 +917,19 @@ void ProfileManager::beginBlock(Block& _block)
|
|||||||
|
|
||||||
bool empty = true;
|
bool empty = true;
|
||||||
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
const auto state = m_profilerStatus.load(std::memory_order_acquire);
|
||||||
switch (state)
|
if (state ==
|
||||||
{
|
//switch (state)
|
||||||
case EASY_PROF_DISABLED:
|
//{
|
||||||
|
EASY_PROF_DISABLED)
|
||||||
{
|
{
|
||||||
_block.m_status = profiler::OFF;
|
_block.m_status = profiler::OFF;
|
||||||
THIS_THREAD->halt = false;
|
//THIS_THREAD->halt = false;
|
||||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||||
beginFrame();
|
beginFrame();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EASY_PROF_DUMP:
|
/*case EASY_PROF_DUMP:
|
||||||
{
|
{
|
||||||
const bool halt = THIS_THREAD->halt;
|
const bool halt = THIS_THREAD->halt;
|
||||||
if (halt || THIS_THREAD->blocks.openedList.empty())
|
if (halt || THIS_THREAD->blocks.openedList.empty())
|
||||||
@ -945,17 +948,18 @@ void ProfileManager::beginBlock(Block& _block)
|
|||||||
|
|
||||||
empty = false;
|
empty = false;
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
default:
|
//default:
|
||||||
|
else
|
||||||
{
|
{
|
||||||
empty = THIS_THREAD->blocks.openedList.empty();
|
empty = THIS_THREAD->blocks.openedList.empty();
|
||||||
break;
|
//break;
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
|
|
||||||
THIS_THREAD->stackSize = 0;
|
THIS_THREAD->stackSize = 0;
|
||||||
THIS_THREAD->halt = false;
|
//THIS_THREAD->halt = false;
|
||||||
|
|
||||||
auto blockStatus = _block.m_status;
|
auto blockStatus = _block.m_status;
|
||||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||||
@ -981,7 +985,7 @@ void ProfileManager::beginBlock(Block& _block)
|
|||||||
if (empty)
|
if (empty)
|
||||||
{
|
{
|
||||||
beginFrame();
|
beginFrame();
|
||||||
THIS_THREAD->profiledFrameOpened.store(true, std::memory_order_release);
|
THIS_THREAD->markProfilingFrameStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
THIS_THREAD->blocks.openedList.emplace_back(_block);
|
||||||
@ -1017,7 +1021,7 @@ void ProfileManager::endBlock()
|
|||||||
}
|
}
|
||||||
|
|
||||||
THIS_THREAD->stackSize = 0;
|
THIS_THREAD->stackSize = 0;
|
||||||
if (THIS_THREAD->halt || m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_DISABLED)
|
if (/*THIS_THREAD->halt ||*/ m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_DISABLED)
|
||||||
{
|
{
|
||||||
THIS_THREAD->popSilent();
|
THIS_THREAD->popSilent();
|
||||||
endFrame();
|
endFrame();
|
||||||
@ -1046,7 +1050,7 @@ void ProfileManager::endBlock()
|
|||||||
const bool empty = THIS_THREAD->blocks.openedList.empty();
|
const bool empty = THIS_THREAD->blocks.openedList.empty();
|
||||||
if (empty)
|
if (empty)
|
||||||
{
|
{
|
||||||
THIS_THREAD->profiledFrameOpened.store(false, std::memory_order_release);
|
THIS_THREAD->markProfilingFrameEnded();
|
||||||
endFrame();
|
endFrame();
|
||||||
#if EASY_ENABLE_BLOCK_STATUS != 0
|
#if EASY_ENABLE_BLOCK_STATUS != 0
|
||||||
THIS_THREAD->allowChildren = true;
|
THIS_THREAD->allowChildren = true;
|
||||||
@ -1192,7 +1196,7 @@ void ProfileManager::setEnabled(bool isEnable)
|
|||||||
|
|
||||||
auto time = getCurrentTime();
|
auto time = getCurrentTime();
|
||||||
const auto status = isEnable ? EASY_PROF_ENABLED : EASY_PROF_DISABLED;
|
const auto status = isEnable ? EASY_PROF_ENABLED : EASY_PROF_DISABLED;
|
||||||
const auto prev = m_profilerStatus.exchange(status, std::memory_order_release);
|
const auto prev = m_profilerStatus.exchange(status, std::memory_order_acq_rel);
|
||||||
if (prev == status)
|
if (prev == status)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1286,24 +1290,19 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (state == EASY_PROF_ENABLED) {
|
if (state == EASY_PROF_ENABLED) {
|
||||||
m_profilerStatus.store(EASY_PROF_DUMP, std::memory_order_release);
|
//m_profilerStatus.store(EASY_PROF_DUMP, std::memory_order_release);
|
||||||
|
m_profilerStatus.store(EASY_PROF_DISABLED, std::memory_order_release);
|
||||||
disableEventTracer();
|
disableEventTracer();
|
||||||
m_endTime = getCurrentTime();
|
m_endTime = getCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is to make sure that no new descriptors or new threads will be
|
|
||||||
// added until we finish sending data.
|
|
||||||
//m_spin.lock();
|
|
||||||
// This is the only place using both spins, so no dead-lock will occur
|
|
||||||
|
|
||||||
if (_async && m_stopDumping.load(std::memory_order_acquire))
|
if (_async && m_stopDumping.load(std::memory_order_acquire))
|
||||||
{
|
{
|
||||||
if (_lockSpin)
|
if (_lockSpin)
|
||||||
m_dumpSpin.unlock();
|
m_dumpSpin.unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
// Wait for some time to be sure that all operations which began before setEnabled(false) will be finished.
|
// 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 check into each store operation.
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
@ -1345,9 +1344,13 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
|
|||||||
|
|
||||||
EASY_LOGMSG("All threads have closed frames\n");
|
EASY_LOGMSG("All threads have closed frames\n");
|
||||||
EASY_LOGMSG("Disabled profiling\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();
|
m_spin.lock();
|
||||||
m_storedSpin.lock();
|
m_storedSpin.lock();
|
||||||
|
// This is the only place using both spins, so no dead-lock will occur
|
||||||
// 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 now = getCurrentTime();
|
||||||
@ -1421,7 +1424,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& thread = thread_it->second;
|
auto& thread = thread_it->second;
|
||||||
uint32_t num = static_cast<uint32_t>(thread.blocks.closedList.size()) + static_cast<uint32_t>(thread.sync.closedList.size());
|
uint32_t num = thread.blocks.closedList.markedSize() + thread.sync.closedList.size();
|
||||||
const char expired = ProfileManager::checkThreadExpired(thread);
|
const char expired = ProfileManager::checkThreadExpired(thread);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -1523,8 +1526,8 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
|
|||||||
if (!thread.sync.closedList.empty())
|
if (!thread.sync.closedList.empty())
|
||||||
thread.sync.closedList.serialize(_outputStream);
|
thread.sync.closedList.serialize(_outputStream);
|
||||||
|
|
||||||
_outputStream.write(thread.blocks.closedList.size());
|
_outputStream.write(thread.blocks.closedList.markedSize());
|
||||||
if (!thread.blocks.closedList.empty())
|
if (!thread.blocks.closedList.markedEmpty())
|
||||||
thread.blocks.closedList.serialize(_outputStream);
|
thread.blocks.closedList.serialize(_outputStream);
|
||||||
|
|
||||||
thread.clearClosed();
|
thread.clearClosed();
|
||||||
@ -1680,8 +1683,6 @@ void ProfileManager::stopListen()
|
|||||||
if (m_listenThread.joinable())
|
if (m_listenThread.joinable())
|
||||||
m_listenThread.join();
|
m_listenThread.join();
|
||||||
m_isAlreadyListening.store(false, std::memory_order_release);
|
m_isAlreadyListening.store(false, std::memory_order_release);
|
||||||
|
|
||||||
EASY_LOGMSG("Listening stopped\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProfileManager::isListening() const
|
bool ProfileManager::isListening() const
|
||||||
@ -1873,7 +1874,8 @@ void ProfileManager::listen(uint16_t _port)
|
|||||||
|
|
||||||
m_dumpSpin.lock();
|
m_dumpSpin.lock();
|
||||||
auto time = getCurrentTime();
|
auto time = getCurrentTime();
|
||||||
const auto prev = m_profilerStatus.exchange(EASY_PROF_DUMP, std::memory_order_release);
|
//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 (prev == EASY_PROF_ENABLED) {
|
||||||
disableEventTracer();
|
disableEventTracer();
|
||||||
m_endTime = time;
|
m_endTime = time;
|
||||||
@ -2009,6 +2011,8 @@ void ProfileManager::listen(uint16_t _port)
|
|||||||
m_stopDumping.store(true, std::memory_order_release);
|
m_stopDumping.store(true, std::memory_order_release);
|
||||||
join(dumpingResult);
|
join(dumpingResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EASY_LOGMSG("Listening stopped\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -104,7 +104,7 @@ class ProfileManager
|
|||||||
profiler::spin_lock m_storedSpin;
|
profiler::spin_lock m_storedSpin;
|
||||||
profiler::spin_lock m_dumpSpin;
|
profiler::spin_lock m_dumpSpin;
|
||||||
std::atomic<profiler::thread_id_t> m_mainThreadId;
|
std::atomic<profiler::thread_id_t> m_mainThreadId;
|
||||||
std::atomic<char> m_profilerStatus;
|
std::atomic_bool m_profilerStatus;
|
||||||
std::atomic_bool m_isEventTracingEnabled;
|
std::atomic_bool m_isEventTracingEnabled;
|
||||||
std::atomic_bool m_isAlreadyListening;
|
std::atomic_bool m_isAlreadyListening;
|
||||||
std::atomic_bool m_frameMaxReset;
|
std::atomic_bool m_frameMaxReset;
|
||||||
|
@ -53,7 +53,7 @@ ThreadStorage::ThreadStorage()
|
|||||||
, named(false)
|
, named(false)
|
||||||
, guarded(false)
|
, guarded(false)
|
||||||
, frameOpened(false)
|
, frameOpened(false)
|
||||||
, halt(false)
|
//, halt(false)
|
||||||
{
|
{
|
||||||
expired = ATOMIC_VAR_INIT(0);
|
expired = ATOMIC_VAR_INIT(0);
|
||||||
profiledFrameOpened = ATOMIC_VAR_INIT(false);
|
profiledFrameOpened = ATOMIC_VAR_INIT(false);
|
||||||
@ -69,7 +69,7 @@ void ThreadStorage::storeValue(profiler::timestamp_t _timestamp, profiler::block
|
|||||||
char* cdata = reinterpret_cast<char*>(data);
|
char* cdata = reinterpret_cast<char*>(data);
|
||||||
memcpy(cdata + sizeof(profiler::ArbitraryValue), _data, _size);
|
memcpy(cdata + sizeof(profiler::ArbitraryValue), _data, _size);
|
||||||
|
|
||||||
blocks.usedMemorySize += serializedDataSize;
|
blocks.frameMemorySize += serializedDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||||
@ -98,7 +98,7 @@ void ThreadStorage::storeBlock(const profiler::Block& block)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
::new (data) profiler::SerializedBlock(block, nameLength);
|
::new (data) profiler::SerializedBlock(block, nameLength);
|
||||||
blocks.usedMemorySize += serializedDataSize;
|
blocks.frameMemorySize += serializedDataSize;
|
||||||
|
|
||||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
||||||
if (expanded)
|
if (expanded)
|
||||||
@ -109,7 +109,7 @@ void ThreadStorage::storeBlock(const profiler::Block& block)
|
|||||||
serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + 1);
|
serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + 1);
|
||||||
data = blocks.closedList.allocate(serializedDataSize);
|
data = blocks.closedList.allocate(serializedDataSize);
|
||||||
::new (data) profiler::SerializedBlock(b, 0);
|
::new (data) profiler::SerializedBlock(b, 0);
|
||||||
blocks.usedMemorySize += serializedDataSize;
|
blocks.frameMemorySize += serializedDataSize;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -155,3 +155,16 @@ profiler::timestamp_t ThreadStorage::endFrame()
|
|||||||
frameOpened = false;
|
frameOpened = false;
|
||||||
return getCurrentTime() - frameStartTime;
|
return getCurrentTime() - frameStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThreadStorage::markProfilingFrameStarted()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -63,10 +63,12 @@ struct BlocksList
|
|||||||
std::vector<T> openedList;
|
std::vector<T> openedList;
|
||||||
chunk_allocator<N> closedList;
|
chunk_allocator<N> closedList;
|
||||||
uint64_t usedMemorySize = 0;
|
uint64_t usedMemorySize = 0;
|
||||||
|
uint64_t frameMemorySize = 0;
|
||||||
|
|
||||||
void clearClosed() {
|
void clearClosed() {
|
||||||
//closedList.clear();
|
//closedList.clear();
|
||||||
usedMemorySize = 0;
|
usedMemorySize = 0;
|
||||||
|
frameMemorySize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -90,8 +92,8 @@ public:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1 + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data
|
EASY_CONSTEXPR uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1 + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data
|
||||||
const uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1 + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
|
EASY_CONSTEXPR uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1 + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
|
||||||
|
|
||||||
struct ThreadStorage EASY_FINAL
|
struct ThreadStorage EASY_FINAL
|
||||||
{
|
{
|
||||||
@ -109,7 +111,7 @@ struct ThreadStorage EASY_FINAL
|
|||||||
bool named; ///< True if thread name was set
|
bool named; ///< True if thread name was set
|
||||||
bool guarded; ///< True if thread has been registered using ThreadGuard
|
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 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.
|
//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 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 storeBlock(const profiler::Block& _block);
|
||||||
@ -119,6 +121,8 @@ struct ThreadStorage EASY_FINAL
|
|||||||
|
|
||||||
void beginFrame();
|
void beginFrame();
|
||||||
profiler::timestamp_t endFrame();
|
profiler::timestamp_t endFrame();
|
||||||
|
void markProfilingFrameStarted();
|
||||||
|
void markProfilingFrameEnded();
|
||||||
|
|
||||||
ThreadStorage();
|
ThreadStorage();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user