mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-10 10:41:50 +00:00
b0fc0d5dcc
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.
285 lines
7.1 KiB
C++
285 lines
7.1 KiB
C++
#if defined _MSC_VER || defined __CYGWIN__ || defined _WIN32
|
|
# ifndef WIN32_LEAN_AND_MEAN
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# endif
|
|
# ifndef NOMINMAX
|
|
# define NOMINMAX
|
|
# endif
|
|
#endif
|
|
#ifdef _MSC_VER
|
|
# pragma warning(disable:4996)
|
|
#endif
|
|
#if defined _WIN32 || defined __CYGWIN__
|
|
# include <windows.h>
|
|
# include <malloc.h>
|
|
#else
|
|
# include <pthread.h>
|
|
# include <string.h>
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef __linux__
|
|
# ifdef __ANDROID__
|
|
# include <sys/types.h>
|
|
# else
|
|
# include <sys/syscall.h>
|
|
# endif
|
|
# include <fcntl.h>
|
|
#elif defined __FreeBSD__
|
|
# include <sys/thr.h>
|
|
#elif defined __NetBSD__ || defined __DragonFly__
|
|
# include <sys/lwp.h>
|
|
#endif
|
|
|
|
#ifdef __MINGW32__
|
|
# define __STDC_FORMAT_MACROS
|
|
#endif
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "TracySystem.hpp"
|
|
|
|
#if defined _WIN32 || defined __CYGWIN__
|
|
extern "C" typedef HRESULT (WINAPI *t_SetThreadDescription)( HANDLE, PCWSTR );
|
|
extern "C" typedef HRESULT (WINAPI *t_GetThreadDescription)( HANDLE, PWSTR* );
|
|
#endif
|
|
|
|
#ifdef TRACY_ENABLE
|
|
# include <atomic>
|
|
# include "TracyAlloc.hpp"
|
|
#endif
|
|
|
|
namespace tracy
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
TRACY_API uint64_t GetThreadHandleImpl()
|
|
{
|
|
#if defined _WIN32 || defined __CYGWIN__
|
|
static_assert( sizeof( decltype( GetCurrentThreadId() ) ) <= sizeof( uint64_t ), "Thread handle too big to fit in protocol" );
|
|
return uint64_t( GetCurrentThreadId() );
|
|
#elif defined __APPLE__
|
|
uint64_t id;
|
|
pthread_threadid_np( pthread_self(), &id );
|
|
return id;
|
|
#elif defined __ANDROID__
|
|
return (uint64_t)gettid();
|
|
#elif defined __linux__
|
|
return (uint64_t)syscall( SYS_gettid );
|
|
#elif defined __FreeBSD__
|
|
long id;
|
|
thr_self( &id );
|
|
return id;
|
|
#elif defined __NetBSD__
|
|
return _lwp_self();
|
|
#elif defined __DragonFly__
|
|
return lwp_gettid();
|
|
#elif defined __OpenBSD__
|
|
return getthrid();
|
|
#else
|
|
static_assert( sizeof( decltype( pthread_self() ) ) <= sizeof( uint64_t ), "Thread handle too big to fit in protocol" );
|
|
return uint64_t( pthread_self() );
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef TRACY_ENABLE
|
|
struct ThreadNameData
|
|
{
|
|
uint64_t id;
|
|
const char* name;
|
|
ThreadNameData* next;
|
|
};
|
|
std::atomic<ThreadNameData*>& GetThreadNameData();
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
# pragma pack( push, 8 )
|
|
struct THREADNAME_INFO
|
|
{
|
|
DWORD dwType;
|
|
LPCSTR szName;
|
|
DWORD dwThreadID;
|
|
DWORD dwFlags;
|
|
};
|
|
# pragma pack(pop)
|
|
|
|
void ThreadNameMsvcMagic( const THREADNAME_INFO& info )
|
|
{
|
|
__try
|
|
{
|
|
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
|
|
TRACY_API void SetThreadName( const char* name )
|
|
{
|
|
#if defined _WIN32 || defined __CYGWIN__
|
|
static auto _SetThreadDescription = (t_SetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "SetThreadDescription" );
|
|
if( _SetThreadDescription )
|
|
{
|
|
wchar_t buf[256];
|
|
mbstowcs( buf, name, 256 );
|
|
_SetThreadDescription( GetCurrentThread(), buf );
|
|
}
|
|
else
|
|
{
|
|
# if defined _MSC_VER
|
|
THREADNAME_INFO info;
|
|
info.dwType = 0x1000;
|
|
info.szName = name;
|
|
info.dwThreadID = GetCurrentThreadId();
|
|
info.dwFlags = 0;
|
|
ThreadNameMsvcMagic( info );
|
|
# endif
|
|
}
|
|
#elif defined _GNU_SOURCE && !defined __EMSCRIPTEN__ && !defined __CYGWIN__
|
|
{
|
|
const auto sz = strlen( name );
|
|
if( sz <= 15 )
|
|
{
|
|
pthread_setname_np( pthread_self(), name );
|
|
}
|
|
else
|
|
{
|
|
char buf[16];
|
|
memcpy( buf, name, 15 );
|
|
buf[15] = '\0';
|
|
pthread_setname_np( pthread_self(), buf );
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef TRACY_ENABLE
|
|
{
|
|
const auto sz = strlen( name );
|
|
char* buf = (char*)tracy_malloc( sz+1 );
|
|
memcpy( buf, name, sz );
|
|
buf[sz] = '\0';
|
|
auto data = (ThreadNameData*)tracy_malloc( sizeof( ThreadNameData ) );
|
|
data->id = detail::GetThreadHandleImpl();
|
|
data->name = buf;
|
|
data->next = GetThreadNameData().load( std::memory_order_relaxed );
|
|
while( !GetThreadNameData().compare_exchange_weak( data->next, data, std::memory_order_release, std::memory_order_relaxed ) ) {}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
TRACY_API const char* GetThreadName( uint64_t id )
|
|
{
|
|
static char buf[256];
|
|
#ifdef TRACY_ENABLE
|
|
auto ptr = GetThreadNameData().load( std::memory_order_relaxed );
|
|
while( ptr )
|
|
{
|
|
if( ptr->id == id )
|
|
{
|
|
return ptr->name;
|
|
}
|
|
ptr = ptr->next;
|
|
}
|
|
#else
|
|
# if defined _WIN32 || defined __CYGWIN__
|
|
static auto _GetThreadDescription = (t_GetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetThreadDescription" );
|
|
if( _GetThreadDescription )
|
|
{
|
|
auto hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)id );
|
|
if( hnd != 0 )
|
|
{
|
|
PWSTR tmp;
|
|
_GetThreadDescription( hnd, &tmp );
|
|
auto ret = wcstombs( buf, tmp, 256 );
|
|
CloseHandle( hnd );
|
|
if( ret != 0 )
|
|
{
|
|
return buf;
|
|
}
|
|
}
|
|
}
|
|
# elif defined __linux__
|
|
int cs, fd;
|
|
char path[32];
|
|
# ifdef __ANDROID__
|
|
int tid = gettid();
|
|
# else
|
|
int tid = (int) syscall( SYS_gettid );
|
|
# endif
|
|
snprintf( path, sizeof( path ), "/proc/self/task/%d/comm", tid );
|
|
sprintf( buf, "%" PRIu64, id );
|
|
# ifndef __ANDROID__
|
|
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &cs );
|
|
# endif
|
|
if ( ( fd = open( path, O_RDONLY ) ) > 0) {
|
|
int len = read( fd, buf, 255 );
|
|
if( len > 0 )
|
|
{
|
|
buf[len] = 0;
|
|
if( len > 1 && buf[len-1] == '\n' )
|
|
{
|
|
buf[len-1] = 0;
|
|
}
|
|
}
|
|
close( fd );
|
|
}
|
|
# ifndef __ANDROID__
|
|
pthread_setcancelstate( cs, 0 );
|
|
# endif
|
|
return buf;
|
|
# endif
|
|
#endif
|
|
sprintf( buf, "%" PRIu64, id );
|
|
return buf;
|
|
}
|
|
|
|
TRACY_API const char* GetEnvVar( const char* name )
|
|
{
|
|
#if defined _WIN32 || defined __CYGWIN__
|
|
// unfortunately getenv() on Windows is just fundamentally broken. It caches the entire
|
|
// environment block once on startup, then never refreshes it again. If any environment
|
|
// strings are added or modified after startup of the CRT, those changes will not be
|
|
// seen by getenv(). This removes the possibility of an app using this SDK from
|
|
// programmatically setting any of the behaviour controlling envvars here.
|
|
//
|
|
// To work around this, we'll instead go directly to the Win32 environment strings APIs
|
|
// to get the current value.
|
|
static char buffer[1024];
|
|
DWORD const kBufferSize = DWORD(sizeof(buffer) / sizeof(buffer[0]));
|
|
DWORD count = GetEnvironmentVariableA(name, buffer, kBufferSize);
|
|
|
|
if( count == 0 )
|
|
return nullptr;
|
|
|
|
if( count >= kBufferSize )
|
|
{
|
|
char* buf = reinterpret_cast<char*>(_alloca(count + 1));
|
|
count = GetEnvironmentVariableA(name, buf, count + 1);
|
|
memcpy(buffer, buf, kBufferSize);
|
|
buffer[kBufferSize - 1] = 0;
|
|
}
|
|
|
|
return buffer;
|
|
#else
|
|
return getenv(name);
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
TRACY_API void ___tracy_set_thread_name( const char* name ) { tracy::SetThreadName( name ); }
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|