0
0
mirror of https://github.com/yse/easy_profiler.git synced 2025-01-14 00:27:55 +08:00

#0 Build fix + reduced number of thread-local variables

This commit is contained in:
Victor Zarubkin 2017-09-30 20:45:06 +03:00
parent 000888f4af
commit d5f2ef0c6c
4 changed files with 66 additions and 46 deletions

View File

@ -80,19 +80,17 @@ message(STATUS " Implicit thread registration = ${EASY_OPTION_IMPLICIT_THREAD_R
if (WIN32)
message(STATUS " Event tracing = ${EASY_OPTION_EVENT_TRACING}")
message(STATUS " Event tracing has low priority = ${EASY_OPTION_LOW_PRIORITY_EVENT_TRACING}")
else ()
elseif (NO_CXX11_THREAD_LOCAL_SUPPORT)
if (EASY_OPTION_IMPLICIT_THREAD_REGISTRATION)
message(STATUS " WARNING! Implicit thread registration for Unix systems can lead to memory leak")
message(STATUS " because there is no possibility to check if thread is alive and remove dead threads.")
endif ()
if (NO_CXX11_THREAD_LOCAL_SUPPORT)
message(STATUS " Removing empty unguarded threads = ${EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS}")
if (EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS)
message(STATUS " WARNING! Removing empty unguarded threads may lead to an application crash!")
message(STATUS " But fixes potential memory leak on Unix systems.")
else ()
message(STATUS " WARNING! There is a possibility of memory leak without removing empty unguarded threads.")
endif ()
message(STATUS " Removing empty unguarded threads = ${EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS}")
if (EASY_OPTION_REMOVE_EMPTY_UNGUARDED_THREADS)
message(STATUS " WARNING! Removing empty unguarded threads may lead to an application crash!")
message(STATUS " But fixes potential memory leak on Unix systems.")
else ()
message(STATUS " WARNING! There is a possibility of memory leak without removing empty unguarded threads.")
endif ()
endif ()
message(STATUS " Log messages = ${EASY_OPTION_LOG}")

View File

@ -229,10 +229,6 @@ const profiler::color_t EASY_COLOR_END = 0xfff44336; // profiler::colors::Red
//////////////////////////////////////////////////////////////////////////
EASY_THREAD_LOCAL static ::ThreadStorage* THIS_THREAD = nullptr;
EASY_THREAD_LOCAL static int32_t THIS_THREAD_STACK_SIZE = 0;
EASY_THREAD_LOCAL static profiler::timestamp_t THIS_THREAD_FRAME_T = 0ULL;
EASY_THREAD_LOCAL static bool THIS_THREAD_FRAME = false;
EASY_THREAD_LOCAL static bool THIS_THREAD_HALT = false;
EASY_THREAD_LOCAL static bool THIS_THREAD_IS_MAIN = false;
EASY_THREAD_LOCAL static profiler::timestamp_t THIS_THREAD_FRAME_T_MAX = 0ULL;
@ -636,7 +632,7 @@ ThreadGuard::~ThreadGuard()
{
bool isMarked = false;
EASY_EVENT_RES(isMarked, "ThreadFinished", EASY_COLOR_THREAD_END, ::profiler::FORCE_ON);
THIS_THREAD->frame.store(false, std::memory_order_release);
THIS_THREAD->profiledFrameOpened.store(false, std::memory_order_release);
THIS_THREAD->expired.store(isMarked ? 2 : 1, std::memory_order_release);
THIS_THREAD = nullptr;
}
@ -890,7 +886,7 @@ void ProfileManager::beginBlock(Block& _block)
if (THIS_THREAD == nullptr)
registerThread();
if (++THIS_THREAD_STACK_SIZE > 1)
if (++THIS_THREAD->stackSize > 1)
{
_block.m_status = profiler::OFF;
THIS_THREAD->blocks.openedList.emplace_back(_block);
@ -900,8 +896,8 @@ void ProfileManager::beginBlock(Block& _block)
const auto state = m_profilerStatus.load(std::memory_order_acquire);
if (state == EASY_PROF_DISABLED)
{
THIS_THREAD_HALT = false;
_block.m_status = profiler::OFF;
THIS_THREAD->halt = false;
THIS_THREAD->blocks.openedList.emplace_back(_block);
beginFrame();
return;
@ -910,14 +906,15 @@ void ProfileManager::beginBlock(Block& _block)
bool empty = true;
if (state == EASY_PROF_DUMP)
{
if (THIS_THREAD_HALT || THIS_THREAD->blocks.openedList.empty())
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 (!THIS_THREAD_HALT)
if (!halt)
{
THIS_THREAD_HALT = true;
THIS_THREAD->halt = true;
beginFrame();
}
@ -931,8 +928,8 @@ void ProfileManager::beginBlock(Block& _block)
empty = THIS_THREAD->blocks.openedList.empty();
}
THIS_THREAD_HALT = false;
THIS_THREAD_STACK_SIZE = 0;
THIS_THREAD->stackSize = 0;
THIS_THREAD->halt = false;
#if EASY_ENABLE_BLOCK_STATUS != 0
if (THIS_THREAD->allowChildren)
@ -957,7 +954,7 @@ void ProfileManager::beginBlock(Block& _block)
if (empty)
{
beginFrame();
THIS_THREAD->frame.store(true, std::memory_order_release);
THIS_THREAD->profiledFrameOpened.store(true, std::memory_order_release);
}
THIS_THREAD->blocks.openedList.emplace_back(_block);
@ -986,14 +983,14 @@ void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profil
void ProfileManager::endBlock()
{
if (--THIS_THREAD_STACK_SIZE > 0)
if (--THIS_THREAD->stackSize > 0)
{
THIS_THREAD->popSilent();
return;
}
THIS_THREAD_STACK_SIZE = 0;
if (THIS_THREAD_HALT || m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_DISABLED)
THIS_THREAD->stackSize = 0;
if (THIS_THREAD->halt || m_profilerStatus.load(std::memory_order_acquire) == EASY_PROF_DISABLED)
{
THIS_THREAD->popSilent();
endFrame();
@ -1022,7 +1019,7 @@ void ProfileManager::endBlock()
const bool empty = THIS_THREAD->blocks.openedList.empty();
if (empty)
{
THIS_THREAD->frame.store(false, std::memory_order_release);
THIS_THREAD->profiledFrameOpened.store(false, std::memory_order_release);
endFrame();
#if EASY_ENABLE_BLOCK_STATUS != 0
THIS_THREAD->allowChildren = true;
@ -1074,21 +1071,15 @@ void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, processi
void ProfileManager::beginFrame()
{
if (!THIS_THREAD_FRAME)
{
THIS_THREAD_FRAME_T = getCurrentTime();
THIS_THREAD_FRAME = true;
}
THIS_THREAD->beginFrame();
}
void ProfileManager::endFrame()
{
if (!THIS_THREAD_FRAME)
if (!THIS_THREAD->frameOpened)
return;
const profiler::timestamp_t duration = getCurrentTime() - THIS_THREAD_FRAME_T;
THIS_THREAD_FRAME = false;
const profiler::timestamp_t duration = THIS_THREAD->endFrame();
if (THIS_THREAD_FRAME_T_RESET_MAX)
{
@ -1301,7 +1292,7 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
EASY_LOG_ONLY(bool logged = false);
for (auto it = m_threads.begin(), end = m_threads.end(); it != end;)
{
if (!it->second.frame.load(std::memory_order_acquire))
if (!it->second.profiledFrameOpened.load(std::memory_order_acquire))
{
++it;
EASY_LOG_ONLY(logged = false);

View File

@ -45,10 +45,19 @@ The Apache License, Version 2.0 (the "License");
#include "current_thread.h"
#include "current_time.h"
ThreadStorage::ThreadStorage() : nonscopedBlocks(16), id(getCurrentThreadId()), allowChildren(true), named(false), guarded(false)
ThreadStorage::ThreadStorage()
: nonscopedBlocks(16)
, frameStartTime(0)
, id(getCurrentThreadId())
, stackSize(0)
, allowChildren(true)
, named(false)
, guarded(false)
, frameOpened(false)
, halt(false)
{
expired = ATOMIC_VAR_INIT(0);
frame = ATOMIC_VAR_INIT(false);
profiledFrameOpened = ATOMIC_VAR_INIT(false);
}
void ThreadStorage::storeBlock(const profiler::Block& block)
@ -119,3 +128,18 @@ void ThreadStorage::popSilent()
blocks.openedList.pop_back();
}
}
void ThreadStorage::beginFrame()
{
if (!frameOpened)
{
frameStartTime = getCurrentTime();
frameOpened = true;
}
}
profiler::timestamp_t ThreadStorage::endFrame()
{
frameOpened = false;
return getCurrentTime() - frameStartTime;
}

View File

@ -47,6 +47,7 @@ The Apache License, Version 2.0 (the "License");
#include <vector>
#include <string>
#include <atomic>
#include <type_traits>
#include "stack_buffer.h"
#include "chunk_allocator.h"
@ -96,20 +97,26 @@ struct ThreadStorage
BlocksList<std::reference_wrapper<profiler::Block>, SIZEOF_BLOCK * (uint16_t)128U> blocks;
BlocksList<CSwitchBlock, SIZEOF_CSWITCH * (uint16_t)128U> sync;
std::string name; ///< Thread name
const profiler::thread_id_t id; ///< Thread ID
std::atomic<char> expired; ///< Is thread expired
std::atomic_bool frame; ///< Is new frame 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
std::string name; ///< Thread name
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 storeBlock(const profiler::Block& _block);
void storeCSwitch(const CSwitchBlock& _block);
void clearClosed();
void popSilent();
void beginFrame();
profiler::timestamp_t endFrame();
ThreadStorage();
private: