mirror of
https://github.com/wolfpld/tracy.git
synced 2025-03-20 07:40:02 +08:00
Check if rpmalloc has to be initialized before each operation.
The C++11 spec states in [basic.stc.thread] thread storage duration: 2. A variable with thread storage duration shall be initialized before its first odr-use (3.2) and, if constructed, shall be destroyed on thread exit. Previously Tracy relied on the TLS data being initialized: - During thread creation (MSVC). - Or during first use in a thread, but the initialization was performed for the whole TLS block. It seems that new compilers are more granular with how they perform the initialization, hence rpmalloc init has to be checked before each allocation, as it cannot be "folded" into, for example, initialization of the profiler itself.
This commit is contained in:
@@ -119,45 +119,6 @@ extern "C" typedef BOOL (WINAPI *t_GetLogicalProcessorInformationEx)( LOGICAL_PR
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
# if ( defined _WIN32 || defined __CYGWIN__ ) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
BOOL CALLBACK InitOnceCallback( PINIT_ONCE /*initOnce*/, PVOID /*Parameter*/, PVOID* /*Context*/)
|
||||
{
|
||||
rpmalloc_initialize();
|
||||
return TRUE;
|
||||
}
|
||||
INIT_ONCE InitOnce = INIT_ONCE_STATIC_INIT;
|
||||
# elif defined __linux__
|
||||
void InitOnceCallback()
|
||||
{
|
||||
rpmalloc_initialize();
|
||||
}
|
||||
pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
||||
# else
|
||||
void InitOnceCallback()
|
||||
{
|
||||
rpmalloc_initialize();
|
||||
}
|
||||
std::once_flag once_flag;
|
||||
# endif
|
||||
}
|
||||
|
||||
struct RPMallocInit
|
||||
{
|
||||
RPMallocInit()
|
||||
{
|
||||
# if ( defined _WIN32 || defined __CYGWIN__ ) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
InitOnceExecuteOnce( &InitOnce, InitOnceCallback, nullptr, nullptr );
|
||||
# elif defined __linux__
|
||||
pthread_once( &once_control, InitOnceCallback );
|
||||
# else
|
||||
std::call_once( once_flag, InitOnceCallback );
|
||||
# endif
|
||||
rpmalloc_thread_initialize();
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef TRACY_DELAYED_INIT
|
||||
|
||||
struct InitTimeWrapper
|
||||
@@ -965,12 +926,6 @@ TRACY_API int64_t GetFrequencyQpc()
|
||||
#ifdef TRACY_DELAYED_INIT
|
||||
struct ThreadNameData;
|
||||
TRACY_API moodycamel::ConcurrentQueue<QueueItem>& GetQueue();
|
||||
TRACY_API void InitRPMallocThread();
|
||||
|
||||
void InitRPMallocThread()
|
||||
{
|
||||
RPMallocInit rpinit;
|
||||
}
|
||||
|
||||
struct ProfilerData
|
||||
{
|
||||
@@ -992,7 +947,6 @@ struct ProducerWrapper
|
||||
struct ProfilerThreadData
|
||||
{
|
||||
ProfilerThreadData( ProfilerData& data ) : token( data ), gpuCtx( { nullptr } ) {}
|
||||
RPMallocInit rpmalloc_init;
|
||||
ProducerWrapper token;
|
||||
GpuCtxWrapper gpuCtx;
|
||||
# ifdef TRACY_ON_DEMAND
|
||||
@@ -1004,7 +958,6 @@ struct ProfilerThreadData
|
||||
ProfilerData* s_profilerData = nullptr;
|
||||
TRACY_API void StartupProfiler()
|
||||
{
|
||||
RPMallocInit init;
|
||||
s_profilerData = (ProfilerData*)tracy_malloc( sizeof( ProfilerData ) );
|
||||
new (s_profilerData) ProfilerData();
|
||||
s_profilerData->profiler.SpawnWorkerThreads();
|
||||
@@ -1022,6 +975,8 @@ TRACY_API void ShutdownProfiler()
|
||||
rpmalloc_finalize();
|
||||
}
|
||||
# else
|
||||
std::atomic<int> RpInitDone { 0 };
|
||||
std::atomic<int> RpInitLock { 0 };
|
||||
static std::atomic<int> profilerDataLock { 0 };
|
||||
static std::atomic<ProfilerData*> profilerData { nullptr };
|
||||
|
||||
@@ -1035,7 +990,6 @@ static ProfilerData& GetProfilerData()
|
||||
ptr = profilerData.load( std::memory_order_acquire );
|
||||
if( !ptr )
|
||||
{
|
||||
RPMallocInit init;
|
||||
ptr = (ProfilerData*)tracy_malloc( sizeof( ProfilerData ) );
|
||||
new (ptr) ProfilerData();
|
||||
profilerData.store( ptr, std::memory_order_release );
|
||||
@@ -1072,7 +1026,6 @@ public:
|
||||
void* p = pthread_getspecific(m_key);
|
||||
if (!p)
|
||||
{
|
||||
RPMallocInit init;
|
||||
p = (ProfilerThreadData*)tracy_malloc( sizeof( ProfilerThreadData ) );
|
||||
new (p) ProfilerThreadData(GetProfilerData());
|
||||
pthread_setspecific(m_key, p);
|
||||
@@ -1124,18 +1077,12 @@ namespace
|
||||
# endif
|
||||
|
||||
#else
|
||||
TRACY_API void InitRPMallocThread()
|
||||
{
|
||||
rpmalloc_thread_initialize();
|
||||
}
|
||||
|
||||
// MSVC static initialization order solution. gcc/clang uses init_order() to avoid all this.
|
||||
|
||||
// 1a. But s_queue is needed for initialization of variables in point 2.
|
||||
extern moodycamel::ConcurrentQueue<QueueItem> s_queue;
|
||||
|
||||
thread_local RPMallocInit init_order(106) s_rpmalloc_thread_init;
|
||||
|
||||
// 2. If these variables would be in the .CRT$XCB section, they would be initialized only in main thread.
|
||||
thread_local moodycamel::ProducerToken init_order(107) s_token_detail( s_queue );
|
||||
thread_local ProducerWrapper init_order(108) s_token { s_queue.get_explicit_producer( s_token_detail ) };
|
||||
@@ -1148,7 +1095,8 @@ thread_local ThreadHandleWrapper init_order(104) s_threadHandle { detail::GetThr
|
||||
# endif
|
||||
|
||||
static InitTimeWrapper init_order(101) s_initTime { SetupHwTimer() };
|
||||
static RPMallocInit init_order(102) s_rpmalloc_init;
|
||||
std::atomic<int> init_order(102) RpInitDone( 0 );
|
||||
std::atomic<int> init_order(102) RpInitLock( 0 );
|
||||
moodycamel::ConcurrentQueue<QueueItem> init_order(103) s_queue( QueuePrealloc );
|
||||
std::atomic<uint32_t> init_order(104) s_lockCounter( 0 );
|
||||
std::atomic<uint8_t> init_order(104) s_gpuCtxCounter( 0 );
|
||||
@@ -3614,19 +3562,6 @@ TRACY_API uint64_t ___tracy_alloc_srcloc_name( uint32_t line, const char* source
|
||||
return tracy::Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );
|
||||
}
|
||||
|
||||
// thread_locals are not initialized on thread creation. At least on GNU/Linux. Instead they are
|
||||
// initialized on their first ODR-use. This means that the allocator is not automagically
|
||||
// initialized every time a thread is created. As thus, expose to the C API users a simple API to
|
||||
// call every time they create a thread. Here we can then put all sorts of per-thread
|
||||
// initialization.
|
||||
TRACY_API void ___tracy_init_thread(void) {
|
||||
#ifdef TRACY_DELAYED_INIT
|
||||
(void)tracy::GetProfilerThreadData();
|
||||
#else
|
||||
(void)tracy::s_rpmalloc_thread_init;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user