2017-10-16 19:34:39 +00:00
# ifdef TRACY_ENABLE
2019-01-19 11:03:30 +00:00
# ifdef _WIN32
2018-12-24 18:49:53 +00:00
# ifndef NOMINMAX
# define NOMINMAX
# endif
2018-12-24 18:50:52 +00:00
# include <winsock2.h>
# include <windows.h>
# include <tlhelp32.h>
2019-01-20 16:17:09 +00:00
# include <inttypes.h>
2019-07-10 00:01:08 +00:00
# include <intrin.h>
2017-09-14 17:25:16 +00:00
# else
# include <sys / time.h>
2019-11-21 01:14:08 +00:00
# include <sys / param.h>
2017-09-14 17:25:16 +00:00
# endif
2018-08-19 16:15:14 +00:00
# ifdef __CYGWIN__
# include <windows.h>
2019-08-13 14:20:24 +00:00
# include <unistd.h>
2019-11-07 18:08:43 +00:00
# include <tlhelp32.h>
2018-08-19 16:15:14 +00:00
# endif
2017-10-03 21:17:16 +00:00
# ifdef _GNU_SOURCE
# include <errno.h>
# endif
2018-08-20 12:30:56 +00:00
# ifdef __linux__
# include <dirent.h>
2019-11-05 19:15:53 +00:00
# include <signal.h>
# include <pthread.h>
2018-08-20 12:30:56 +00:00
# include <sys / types.h>
# include <sys / syscall.h>
# endif
2019-11-21 01:14:08 +00:00
# if defined __APPLE__ || defined BSD
2019-02-20 12:52:55 +00:00
# include <sys / types.h>
# include <sys / sysctl.h>
2019-02-20 12:13:29 +00:00
# endif
2020-07-30 23:51:31 +00:00
# if defined __APPLE__
# include "TargetConditionals.h"
2021-01-31 18:34:39 +00:00
# include <mach-o / dyld.h>
2020-07-30 23:51:31 +00:00
# endif
2020-11-21 20:05:39 +00:00
# ifdef __ANDROID__
# include <sys / mman.h>
# include <stdio.h>
# include <stdint.h>
# include <algorithm>
# include <vector>
# endif
2019-11-05 19:15:53 +00:00
# include <algorithm>
2017-09-10 15:43:56 +00:00
# include <assert.h>
2019-11-05 19:15:53 +00:00
# include <atomic>
2017-09-23 19:09:46 +00:00
# include <chrono>
2017-09-14 17:25:16 +00:00
# include <limits>
2019-11-05 19:15:53 +00:00
# include <new>
2017-10-30 13:59:05 +00:00
# include <stdlib.h>
2017-09-19 00:19:20 +00:00
# include <string.h>
2021-01-31 16:42:44 +00:00
# include <sys/stat.h>
2019-08-15 00:28:35 +00:00
# include <thread>
2017-09-10 15:43:56 +00:00
2018-03-31 12:03:55 +00:00
# include "../common/TracyAlign.hpp"
2017-09-11 20:51:47 +00:00
# include "../common/TracySocket.hpp"
2017-09-12 23:31:55 +00:00
# include "../common/TracySystem.hpp"
2021-05-31 00:22:13 +00:00
# include "../common/TracyYield.hpp"
2019-05-01 10:57:42 +00:00
# include "../common/tracy_lz4.hpp"
2017-10-14 14:59:43 +00:00
# include "tracy_rpmalloc.hpp"
2018-06-18 23:17:19 +00:00
# include "TracyCallstack.hpp"
2019-06-27 15:09:47 +00:00
# include "TracyDxt1.hpp"
2017-09-24 14:02:09 +00:00
# include "TracyScoped.hpp"
2017-09-10 15:43:56 +00:00
# include "TracyProfiler.hpp"
2017-10-16 19:13:57 +00:00
# include "TracyThread.hpp"
2019-07-03 19:01:34 +00:00
# include "TracyArmCpuTable.hpp"
2019-08-16 17:22:23 +00:00
# include "TracySysTrace.hpp"
2019-01-14 19:55:37 +00:00
# include "../TracyC.h"
2017-09-10 15:43:56 +00:00
2020-03-08 13:34:09 +00:00
# ifdef TRACY_PORT
# ifndef TRACY_DATA_PORT
# define TRACY_DATA_PORT TRACY_PORT
# endif
# ifndef TRACY_BROADCAST_PORT
# define TRACY_BROADCAST_PORT TRACY_PORT
# endif
# endif
2019-02-19 20:51:41 +00:00
# ifdef __APPLE__
2019-02-19 19:43:14 +00:00
# define TRACY_DELAYED_INIT
2017-10-08 22:39:12 +00:00
# else
2019-02-19 19:43:14 +00:00
# ifdef __GNUC__
# define init_order( val ) __attribute__ ((init_priority(val)))
# else
# define init_order(x)
# endif
2017-10-08 22:39:12 +00:00
# endif
2019-01-19 11:03:30 +00:00
# if defined _WIN32 || defined __CYGWIN__
2018-08-19 16:15:14 +00:00
# include <lmcons.h>
2018-08-19 16:43:26 +00:00
extern " C " typedef LONG ( WINAPI * t_RtlGetVersion ) ( PRTL_OSVERSIONINFOW ) ;
2019-11-29 17:29:09 +00:00
extern " C " typedef BOOL ( WINAPI * t_GetLogicalProcessorInformationEx ) ( LOGICAL_PROCESSOR_RELATIONSHIP , PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX , PDWORD ) ;
2018-08-19 16:15:14 +00:00
# else
# include <unistd.h>
# include <limits.h>
# endif
2018-08-19 16:52:04 +00:00
# if defined __linux__
# include <sys / sysinfo.h>
2018-08-19 17:00:01 +00:00
# include <sys / utsname.h>
2018-08-19 16:52:04 +00:00
# endif
2018-08-19 16:15:14 +00:00
2019-07-10 00:09:19 +00:00
# if !defined _WIN32 && !defined __CYGWIN__ && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )
# include <cpuid.h>
# endif
2019-11-05 20:40:35 +00:00
# if !( ( ( defined _WIN32 || defined __CYGWIN__ ) && _WIN32_WINNT >= _WIN32_WINNT_VISTA ) || defined __linux__ )
# include <mutex>
# endif
2017-09-10 15:43:56 +00:00
namespace tracy
{
2020-01-30 18:38:05 +00:00
# ifndef TRACY_DELAYED_INIT
2017-10-16 23:07:34 +00:00
struct InitTimeWrapper
{
int64_t val ;
} ;
2019-02-19 19:43:14 +00:00
struct ProducerWrapper
{
tracy : : moodycamel : : ConcurrentQueue < QueueItem > : : ExplicitProducer * ptr ;
} ;
2019-06-26 17:32:52 +00:00
struct ThreadHandleWrapper
{
uint64_t val ;
} ;
2019-02-19 19:43:14 +00:00
# endif
2021-04-09 22:35:44 +00:00
2020-05-06 16:52:36 +00:00
# if defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
2019-07-10 00:01:08 +00:00
static inline void CpuId ( uint32_t * regs , uint32_t leaf )
{
2020-06-03 18:11:15 +00:00
memset ( regs , 0 , sizeof ( uint32_t ) * 4 ) ;
2019-08-04 09:00:38 +00:00
# if defined _WIN32 || defined __CYGWIN__
2019-07-10 00:01:08 +00:00
__cpuidex ( ( int * ) regs , leaf , 0 ) ;
# else
__get_cpuid ( leaf , regs , regs + 1 , regs + 2 , regs + 3 ) ;
# endif
}
static void InitFailure ( const char * msg )
{
# if defined _WIN32 || defined __CYGWIN__
2019-08-08 17:18:05 +00:00
bool hasConsole = false ;
bool reopen = false ;
const auto attached = AttachConsole ( ATTACH_PARENT_PROCESS ) ;
if ( attached )
{
hasConsole = true ;
reopen = true ;
}
else
{
const auto err = GetLastError ( ) ;
if ( err = = ERROR_ACCESS_DENIED )
{
hasConsole = true ;
}
}
if ( hasConsole )
{
fprintf ( stderr , " Tracy Profiler initialization failure: %s \n " , msg ) ;
if ( reopen )
{
freopen ( " CONOUT$ " , " w " , stderr ) ;
fprintf ( stderr , " Tracy Profiler initialization failure: %s \n " , msg ) ;
}
}
else
{
MessageBoxA ( nullptr , msg , " Tracy Profiler initialization failure " , MB_ICONSTOP ) ;
}
2019-07-10 00:01:08 +00:00
# else
fprintf ( stderr , " Tracy Profiler initialization failure: %s \n " , msg ) ;
# endif
exit ( 0 ) ;
}
static int64_t SetupHwTimer ( )
{
2021-01-29 10:20:23 +00:00
# if !defined TRACY_TIMER_QPC && !defined TRACY_TIMER_FALLBACK
2019-07-10 00:01:08 +00:00
uint32_t regs [ 4 ] ;
2020-06-10 14:25:19 +00:00
CpuId ( regs , 1 ) ;
2020-06-08 17:35:42 +00:00
if ( ! ( regs [ 3 ] & ( 1 < < 4 ) ) ) InitFailure ( " CPU doesn't support RDTSC instruction. " ) ;
2019-07-10 00:01:08 +00:00
CpuId ( regs , 0x80000007 ) ;
2019-08-08 17:21:39 +00:00
if ( ! ( regs [ 3 ] & ( 1 < < 8 ) ) )
{
2021-04-09 22:33:01 +00:00
const char * noCheck = GetEnvVar ( " TRACY_NO_INVARIANT_CHECK " ) ;
2019-08-08 17:21:39 +00:00
if ( ! noCheck | | noCheck [ 0 ] ! = ' 1 ' )
{
2020-09-20 17:47:00 +00:00
# if defined _WIN32 || defined __CYGWIN__
2021-01-28 17:49:17 +00:00
InitFailure ( " CPU doesn't support invariant TSC. \n Define TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*. \n Alternatively you may rebuild the application with the TRACY_TIMER_QPC or TRACY_TIMER_FALLBACK define to use lower resolution timer. " ) ;
2020-09-20 17:47:00 +00:00
# else
2021-01-28 17:49:17 +00:00
InitFailure ( " CPU doesn't support invariant TSC. \n Define TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*. \n Alternatively you may rebuild the application with the TRACY_TIMER_FALLBACK define to use lower resolution timer. " ) ;
2020-09-20 17:47:00 +00:00
# endif
2019-08-08 17:21:39 +00:00
}
}
2020-04-07 20:01:31 +00:00
# endif
2019-07-10 00:01:08 +00:00
return Profiler : : GetTime ( ) ;
}
2018-04-27 14:58:45 +00:00
# else
static int64_t SetupHwTimer ( )
{
return Profiler : : GetTime ( ) ;
}
# endif
2017-10-03 21:17:16 +00:00
static const char * GetProcessName ( )
{
2018-08-01 17:18:40 +00:00
const char * processName = " unknown " ;
2019-01-19 11:03:30 +00:00
# ifdef _WIN32
2017-10-03 21:17:16 +00:00
static char buf [ _MAX_PATH ] ;
GetModuleFileNameA ( nullptr , buf , _MAX_PATH ) ;
const char * ptr = buf ;
while ( * ptr ! = ' \0 ' ) ptr + + ;
while ( ptr > buf & & * ptr ! = ' \\ ' & & * ptr ! = ' / ' ) ptr - - ;
if ( ptr > buf ) ptr + + ;
2018-08-01 17:18:40 +00:00
processName = ptr ;
2017-10-30 13:59:05 +00:00
# elif defined __ANDROID__
# if __ANDROID_API__ >= 21
auto buf = getprogname ( ) ;
2018-08-01 17:18:40 +00:00
if ( buf ) processName = buf ;
2017-10-30 13:59:05 +00:00
# endif
2017-11-10 18:46:31 +00:00
# elif defined _GNU_SOURCE || defined __CYGWIN__
2021-02-11 17:12:59 +00:00
if ( program_invocation_short_name ) processName = program_invocation_short_name ;
2019-11-21 01:16:12 +00:00
# elif defined __APPLE__ || defined BSD
2019-02-21 10:40:56 +00:00
auto buf = getprogname ( ) ;
if ( buf ) processName = buf ;
2018-08-01 12:07:30 +00:00
# endif
2018-08-01 17:18:40 +00:00
return processName ;
2017-10-03 21:17:16 +00:00
}
2021-01-31 16:37:54 +00:00
static const char * GetProcessExecutablePath ( )
{
# ifdef _WIN32
static char buf [ _MAX_PATH ] ;
GetModuleFileNameA ( nullptr , buf , _MAX_PATH ) ;
return buf ;
2021-02-01 14:24:31 +00:00
# elif defined __ANDROID__
return nullptr ;
2021-01-31 16:37:54 +00:00
# elif defined _GNU_SOURCE || defined __CYGWIN__
return program_invocation_name ;
2021-01-31 18:34:39 +00:00
# elif defined __APPLE__
static char buf [ 1024 ] ;
uint32_t size = 1024 ;
_NSGetExecutablePath ( buf , & size ) ;
return buf ;
2021-01-31 19:27:32 +00:00
# elif defined __DragonFly__
static char buf [ 1024 ] ;
readlink ( " /proc/curproc/file " , buf , 1024 ) ;
return buf ;
# elif defined __FreeBSD__
static char buf [ 1024 ] ;
int mib [ 4 ] ;
mib [ 0 ] = CTL_KERN ;
mib [ 1 ] = KERN_PROC ;
mib [ 2 ] = KERN_PROC_PATHNAME ;
mib [ 3 ] = - 1 ;
size_t cb = 1024 ;
sysctl ( mib , 4 , buf , & cb , nullptr , 0 ) ;
return buf ;
# elif defined __NetBSD__
static char buf [ 1024 ] ;
readlink ( " /proc/curproc/exe " , buf , 1024 ) ;
return buf ;
2021-01-31 16:37:54 +00:00
# else
return nullptr ;
# endif
}
2020-07-30 23:46:16 +00:00
# if defined __linux__ && defined __ARM_ARCH
2019-07-03 19:01:34 +00:00
static uint32_t GetHex ( char * & ptr , int skip )
{
uint32_t ret ;
ptr + = skip ;
char * end ;
if ( ptr [ 0 ] = = ' 0 ' & & ptr [ 1 ] = = ' x ' )
{
ptr + = 2 ;
ret = strtol ( ptr , & end , 16 ) ;
}
else
{
ret = strtol ( ptr , & end , 10 ) ;
}
ptr = end ;
return ret ;
}
2020-07-30 23:46:16 +00:00
# endif
2019-07-03 19:01:34 +00:00
2018-08-19 16:15:14 +00:00
static const char * GetHostInfo ( )
{
static char buf [ 1024 ] ;
auto ptr = buf ;
2019-01-19 11:03:30 +00:00
# if defined _WIN32 || defined __CYGWIN__
2020-04-07 19:35:37 +00:00
t_RtlGetVersion RtlGetVersion = ( t_RtlGetVersion ) GetProcAddress ( GetModuleHandleA ( " ntdll.dll " ) , " RtlGetVersion " ) ;
2018-08-19 16:43:26 +00:00
if ( ! RtlGetVersion )
{
2019-01-19 11:03:30 +00:00
# ifdef __CYGWIN__
2018-08-19 16:43:26 +00:00
ptr + = sprintf ( ptr , " OS: Windows (Cygwin) \n " ) ;
2019-01-19 11:03:30 +00:00
# elif defined __MINGW32__
ptr + = sprintf ( ptr , " OS: Windows (MingW) \n " ) ;
# else
ptr + = sprintf ( ptr , " OS: Windows \n " ) ;
2018-08-19 16:43:26 +00:00
# endif
}
else
{
RTL_OSVERSIONINFOW ver = { sizeof ( RTL_OSVERSIONINFOW ) } ;
RtlGetVersion ( & ver ) ;
2019-01-19 11:03:30 +00:00
# ifdef __CYGWIN__
2018-08-19 16:43:26 +00:00
ptr + = sprintf ( ptr , " OS: Windows %i.%i.%i (Cygwin) \n " , ver . dwMajorVersion , ver . dwMinorVersion , ver . dwBuildNumber ) ;
2019-01-19 11:03:30 +00:00
# elif defined __MINGW32__
ptr + = sprintf ( ptr , " OS: Windows %i.%i.%i (MingW) \n " , ( int ) ver . dwMajorVersion , ( int ) ver . dwMinorVersion , ( int ) ver . dwBuildNumber ) ;
# else
ptr + = sprintf ( ptr , " OS: Windows %i.%i.%i \n " , ver . dwMajorVersion , ver . dwMinorVersion , ver . dwBuildNumber ) ;
2018-08-19 16:43:26 +00:00
# endif
}
2018-08-19 16:15:14 +00:00
# elif defined __linux__
2018-08-19 17:00:01 +00:00
struct utsname utsName ;
uname ( & utsName ) ;
2018-08-19 16:15:14 +00:00
# if defined __ANDROID__
2018-08-19 17:00:01 +00:00
ptr + = sprintf ( ptr , " OS: Linux %s (Android) \n " , utsName . release ) ;
2018-08-19 16:15:14 +00:00
# else
2018-08-19 17:00:01 +00:00
ptr + = sprintf ( ptr , " OS: Linux %s \n " , utsName . release ) ;
2018-08-19 16:15:14 +00:00
# endif
# elif defined __APPLE__
2019-02-20 11:43:48 +00:00
# if TARGET_OS_IPHONE == 1
2018-08-19 16:15:14 +00:00
ptr + = sprintf ( ptr , " OS: Darwin (iOS) \n " ) ;
2019-02-20 11:43:48 +00:00
# elif TARGET_OS_MAC == 1
2018-08-19 16:15:14 +00:00
ptr + = sprintf ( ptr , " OS: Darwin (OSX) \n " ) ;
# else
ptr + = sprintf ( ptr , " OS: Darwin (unknown) \n " ) ;
# endif
# elif defined __DragonFly__
ptr + = sprintf ( ptr , " OS: BSD (DragonFly) \n " ) ;
# elif defined __FreeBSD__
ptr + = sprintf ( ptr , " OS: BSD (FreeBSD) \n " ) ;
# elif defined __NetBSD__
ptr + = sprintf ( ptr , " OS: BSD (NetBSD) \n " ) ;
# elif defined __OpenBSD__
ptr + = sprintf ( ptr , " OS: BSD (OpenBSD) \n " ) ;
# else
ptr + = sprintf ( ptr , " OS: unknown \n " ) ;
# endif
# if defined _MSC_VER
2019-07-25 17:03:58 +00:00
# if defined __clang__
ptr + = sprintf ( ptr , " Compiler: MSVC clang-cl %i.%i.%i \n " , __clang_major__ , __clang_minor__ , __clang_patchlevel__ ) ;
# else
2018-08-19 16:15:14 +00:00
ptr + = sprintf ( ptr , " Compiler: MSVC %i \n " , _MSC_VER ) ;
2019-07-25 17:03:58 +00:00
# endif
2018-08-19 16:15:14 +00:00
# elif defined __clang__
ptr + = sprintf ( ptr , " Compiler: clang %i.%i.%i \n " , __clang_major__ , __clang_minor__ , __clang_patchlevel__ ) ;
# elif defined __GNUC__
ptr + = sprintf ( ptr , " Compiler: gcc %i.%i \n " , __GNUC__ , __GNUC_MINOR__ ) ;
# else
ptr + = sprintf ( ptr , " Compiler: unknown \n " ) ;
# endif
2019-01-19 13:03:43 +00:00
# if defined _WIN32 || defined __CYGWIN__
2018-08-19 16:15:14 +00:00
# ifndef __CYGWIN__
InitWinSock ( ) ;
# endif
char hostname [ 512 ] ;
gethostname ( hostname , 512 ) ;
DWORD userSz = UNLEN + 1 ;
char user [ UNLEN + 1 ] ;
GetUserNameA ( user , & userSz ) ;
ptr + = sprintf ( ptr , " User: %s@%s \n " , user , hostname ) ;
# else
2018-12-18 15:10:39 +00:00
char hostname [ _POSIX_HOST_NAME_MAX ] { } ;
char user [ _POSIX_LOGIN_NAME_MAX ] { } ;
2018-08-19 16:15:14 +00:00
2018-12-18 15:10:39 +00:00
gethostname ( hostname , _POSIX_HOST_NAME_MAX ) ;
2018-08-27 11:59:19 +00:00
# if defined __ANDROID__
const auto login = getlogin ( ) ;
if ( login )
{
strcpy ( user , login ) ;
}
else
{
memcpy ( user , " (?) " , 4 ) ;
}
# else
2018-12-18 15:10:39 +00:00
getlogin_r ( user , _POSIX_LOGIN_NAME_MAX ) ;
2018-08-27 11:59:19 +00:00
# endif
2018-08-19 16:15:14 +00:00
ptr + = sprintf ( ptr , " User: %s@%s \n " , user , hostname ) ;
# endif
# if defined __i386 || defined _M_IX86
ptr + = sprintf ( ptr , " Arch: x86 \n " ) ;
# elif defined __x86_64__ || defined _M_X64
ptr + = sprintf ( ptr , " Arch: x64 \n " ) ;
# elif defined __aarch64__
ptr + = sprintf ( ptr , " Arch: ARM64 \n " ) ;
# elif defined __ARM_ARCH
ptr + = sprintf ( ptr , " Arch: ARM \n " ) ;
# else
ptr + = sprintf ( ptr , " Arch: unknown \n " ) ;
# endif
# if defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
uint32_t regs [ 4 ] ;
char cpuModel [ 4 * 4 * 3 ] ;
auto modelPtr = cpuModel ;
2018-08-19 16:53:32 +00:00
for ( uint32_t i = 0x80000002 ; i < 0x80000005 ; + + i )
2018-08-19 16:15:14 +00:00
{
2020-05-06 16:52:36 +00:00
CpuId ( regs , i ) ;
2018-08-19 16:15:14 +00:00
memcpy ( modelPtr , regs , sizeof ( regs ) ) ; modelPtr + = sizeof ( regs ) ;
}
ptr + = sprintf ( ptr , " CPU: %s \n " , cpuModel ) ;
2019-07-03 19:01:34 +00:00
# elif defined __linux__ && defined __ARM_ARCH
bool cpuFound = false ;
FILE * fcpuinfo = fopen ( " /proc/cpuinfo " , " rb " ) ;
if ( fcpuinfo )
{
enum { BufSize = 4 * 1024 } ;
char buf [ BufSize ] ;
const auto sz = fread ( buf , 1 , BufSize , fcpuinfo ) ;
fclose ( fcpuinfo ) ;
const auto end = buf + sz ;
auto cptr = buf ;
uint32_t impl = 0 ;
uint32_t var = 0 ;
uint32_t part = 0 ;
uint32_t rev = 0 ;
while ( end - cptr > 20 )
{
while ( end - cptr > 20 & & memcmp ( cptr , " CPU " , 4 ) ! = 0 )
{
cptr + = 4 ;
while ( end - cptr > 20 & & * cptr ! = ' \n ' ) cptr + + ;
cptr + + ;
}
if ( end - cptr < = 20 ) break ;
cptr + = 4 ;
if ( memcmp ( cptr , " implementer \t : " , 14 ) = = 0 )
{
if ( impl ! = 0 ) break ;
impl = GetHex ( cptr , 14 ) ;
}
else if ( memcmp ( cptr , " variant \t : " , 10 ) = = 0 ) var = GetHex ( cptr , 10 ) ;
else if ( memcmp ( cptr , " part \t : " , 7 ) = = 0 ) part = GetHex ( cptr , 7 ) ;
else if ( memcmp ( cptr , " revision \t : " , 11 ) = = 0 ) rev = GetHex ( cptr , 11 ) ;
while ( * cptr ! = ' \n ' & & * cptr ! = ' \0 ' ) cptr + + ;
cptr + + ;
}
if ( impl ! = 0 | | var ! = 0 | | part ! = 0 | | rev ! = 0 )
{
cpuFound = true ;
ptr + = sprintf ( ptr , " CPU: %s%s r%ip%i \n " , DecodeArmImplementer ( impl ) , DecodeArmPart ( impl , part ) , var , rev ) ;
}
}
if ( ! cpuFound )
{
ptr + = sprintf ( ptr , " CPU: unknown \n " ) ;
}
2019-06-19 07:59:46 +00:00
# elif defined __APPLE__ && TARGET_OS_IPHONE == 1
{
size_t sz ;
sysctlbyname ( " hw.machine " , nullptr , & sz , nullptr , 0 ) ;
auto str = ( char * ) tracy_malloc ( sz ) ;
sysctlbyname ( " hw.machine " , str , & sz , nullptr , 0 ) ;
ptr + = sprintf ( ptr , " Device: %s \n " , DecodeIosDevice ( str ) ) ;
tracy_free ( str ) ;
}
2018-08-19 16:15:14 +00:00
# else
ptr + = sprintf ( ptr , " CPU: unknown \n " ) ;
# endif
2019-08-15 00:28:35 +00:00
ptr + = sprintf ( ptr , " CPU cores: %i \n " , std : : thread : : hardware_concurrency ( ) ) ;
2019-01-19 11:03:30 +00:00
# if defined _WIN32 || defined __CYGWIN__
2018-08-19 16:15:14 +00:00
MEMORYSTATUSEX statex ;
statex . dwLength = sizeof ( statex ) ;
GlobalMemoryStatusEx ( & statex ) ;
2018-12-28 23:49:05 +00:00
# ifdef _MSC_VER
2018-08-22 14:31:09 +00:00
ptr + = sprintf ( ptr , " RAM: %I64u MB \n " , statex . ullTotalPhys / 1024 / 1024 ) ;
2018-12-28 23:49:05 +00:00
# else
ptr + = sprintf ( ptr , " RAM: %llu MB \n " , statex . ullTotalPhys / 1024 / 1024 ) ;
# endif
2018-08-19 16:52:04 +00:00
# elif defined __linux__
struct sysinfo sysInfo ;
sysinfo ( & sysInfo ) ;
2018-08-20 10:53:14 +00:00
ptr + = sprintf ( ptr , " RAM: %lu MB \n " , sysInfo . totalram / 1024 / 1024 ) ;
2019-02-20 12:52:55 +00:00
# elif defined __APPLE__
size_t memSize ;
size_t sz = sizeof ( memSize ) ;
sysctlbyname ( " hw.memsize " , & memSize , & sz , nullptr , 0 ) ;
ptr + = sprintf ( ptr , " RAM: %zu MB \n " , memSize / 1024 / 1024 ) ;
2019-11-21 01:14:08 +00:00
# elif defined BSD
size_t memSize ;
size_t sz = sizeof ( memSize ) ;
sysctlbyname ( " hw.physmem " , & memSize , & sz , nullptr , 0 ) ;
ptr + = sprintf ( ptr , " RAM: %zu MB \n " , memSize / 1024 / 1024 ) ;
2018-08-19 16:15:14 +00:00
# else
ptr + = sprintf ( ptr , " RAM: unknown \n " ) ;
# endif
return buf ;
}
2019-08-17 20:19:04 +00:00
static uint64_t GetPid ( )
{
# if defined _WIN32 || defined __CYGWIN__
return uint64_t ( GetCurrentProcessId ( ) ) ;
# else
return uint64_t ( getpid ( ) ) ;
# endif
}
2021-02-07 19:53:20 +00:00
void Profiler : : AckServerQuery ( )
2021-02-03 21:32:31 +00:00
{
2021-02-07 19:53:20 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : AckServerQueryNoop ) ;
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : AckServerQueryNoop ] ) ;
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : AckServerQueryNoop ] ) ;
2021-02-03 21:32:31 +00:00
}
2021-02-07 19:53:20 +00:00
void Profiler : : AckSourceCodeNotAvailable ( )
2021-02-03 23:03:25 +00:00
{
2021-02-07 19:53:20 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : AckSourceCodeNotAvailable ) ;
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : AckSourceCodeNotAvailable ] ) ;
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : AckSourceCodeNotAvailable ] ) ;
2021-02-03 23:03:25 +00:00
}
2020-03-08 13:37:59 +00:00
static BroadcastMessage & GetBroadcastMessage ( const char * procname , size_t pnsz , int & len , int port )
2019-06-17 16:34:35 +00:00
{
2019-06-18 18:26:40 +00:00
static BroadcastMessage msg ;
2019-06-17 16:34:35 +00:00
2019-06-18 18:26:40 +00:00
msg . broadcastVersion = BroadcastVersion ;
msg . protocolVersion = ProtocolVersion ;
2020-03-08 13:37:59 +00:00
msg . listenPort = port ;
2019-06-17 16:34:35 +00:00
2019-06-18 18:26:40 +00:00
memcpy ( msg . programName , procname , pnsz ) ;
memset ( msg . programName + pnsz , 0 , WelcomeMessageProgramNameSize - pnsz ) ;
2019-06-17 16:34:35 +00:00
2019-06-26 17:33:37 +00:00
len = int ( offsetof ( BroadcastMessage , programName ) + pnsz + 1 ) ;
2019-06-18 18:26:40 +00:00
return msg ;
2019-06-17 16:34:35 +00:00
}
2019-11-07 18:08:43 +00:00
# if defined _WIN32 || defined __CYGWIN__
2018-08-19 23:05:09 +00:00
static DWORD s_profilerThreadId = 0 ;
2018-08-20 00:06:59 +00:00
static char s_crashText [ 1024 ] ;
2018-08-19 23:05:09 +00:00
LONG WINAPI CrashFilter ( PEXCEPTION_POINTERS pExp )
{
2020-08-28 15:21:52 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return EXCEPTION_CONTINUE_SEARCH ;
2019-01-19 11:03:30 +00:00
const unsigned ec = pExp - > ExceptionRecord - > ExceptionCode ;
2018-08-20 00:06:59 +00:00
auto msgPtr = s_crashText ;
switch ( ec )
{
case EXCEPTION_ACCESS_VIOLATION :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_ACCESS_VIOLATION (0x%x). " , ec ) ;
switch ( pExp - > ExceptionRecord - > ExceptionInformation [ 0 ] )
{
case 0 :
2019-02-20 15:28:27 +00:00
msgPtr + = sprintf ( msgPtr , " Read violation at address 0x% " PRIxPTR " . " , pExp - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ;
2018-08-20 00:06:59 +00:00
break ;
case 1 :
2019-02-20 15:28:27 +00:00
msgPtr + = sprintf ( msgPtr , " Write violation at address 0x% " PRIxPTR " . " , pExp - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ;
2018-08-20 00:06:59 +00:00
break ;
case 8 :
2019-02-20 15:28:27 +00:00
msgPtr + = sprintf ( msgPtr , " DEP violation at address 0x% " PRIxPTR " . " , pExp - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ;
2018-08-20 00:06:59 +00:00
break ;
default :
break ;
}
break ;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_ARRAY_BOUNDS_EXCEEDED (0x%x). " , ec ) ;
break ;
case EXCEPTION_DATATYPE_MISALIGNMENT :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_DATATYPE_MISALIGNMENT (0x%x). " , ec ) ;
break ;
case EXCEPTION_FLT_DIVIDE_BY_ZERO :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_FLT_DIVIDE_BY_ZERO (0x%x). " , ec ) ;
break ;
case EXCEPTION_ILLEGAL_INSTRUCTION :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_ILLEGAL_INSTRUCTION (0x%x). " , ec ) ;
break ;
case EXCEPTION_IN_PAGE_ERROR :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_IN_PAGE_ERROR (0x%x). " , ec ) ;
break ;
case EXCEPTION_INT_DIVIDE_BY_ZERO :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_INT_DIVIDE_BY_ZERO (0x%x). " , ec ) ;
break ;
case EXCEPTION_PRIV_INSTRUCTION :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_PRIV_INSTRUCTION (0x%x). " , ec ) ;
break ;
case EXCEPTION_STACK_OVERFLOW :
msgPtr + = sprintf ( msgPtr , " Exception EXCEPTION_STACK_OVERFLOW (0x%x). " , ec ) ;
break ;
default :
return EXCEPTION_CONTINUE_SEARCH ;
}
2018-08-19 23:05:09 +00:00
2018-08-20 00:07:31 +00:00
{
2020-09-29 14:39:56 +00:00
GetProfiler ( ) . SendCallstack ( 60 , " KiUserExceptionDispatcher " ) ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : CrashReport ) ;
2018-08-20 00:07:31 +00:00
item - > crashReport . time = Profiler : : GetTime ( ) ;
item - > crashReport . text = ( uint64_t ) s_crashText ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2018-08-20 00:07:31 +00:00
}
2018-08-19 23:05:09 +00:00
HANDLE h = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD , 0 ) ;
if ( h = = INVALID_HANDLE_VALUE ) return EXCEPTION_CONTINUE_SEARCH ;
THREADENTRY32 te = { sizeof ( te ) } ;
if ( ! Thread32First ( h , & te ) )
{
CloseHandle ( h ) ;
return EXCEPTION_CONTINUE_SEARCH ;
}
const auto pid = GetCurrentProcessId ( ) ;
const auto tid = GetCurrentThreadId ( ) ;
do
{
if ( te . th32OwnerProcessID = = pid & & te . th32ThreadID ! = tid & & te . th32ThreadID ! = s_profilerThreadId )
{
HANDLE th = OpenThread ( THREAD_SUSPEND_RESUME , FALSE , te . th32ThreadID ) ;
if ( th ! = INVALID_HANDLE_VALUE )
{
SuspendThread ( th ) ;
CloseHandle ( th ) ;
}
}
}
while ( Thread32Next ( h , & te ) ) ;
CloseHandle ( h ) ;
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : Crash ) ;
TracyLfqCommit ;
2018-08-19 23:05:09 +00:00
}
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 500 ) ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . RequestShutdown ( ) ;
while ( ! GetProfiler ( ) . HasShutdownFinished ( ) ) { std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ; } ;
2018-08-19 23:05:09 +00:00
TerminateProcess ( GetCurrentProcess ( ) , 1 ) ;
return EXCEPTION_CONTINUE_SEARCH ;
}
# endif
2018-08-20 12:30:56 +00:00
# ifdef __linux__
static long s_profilerTid = 0 ;
static char s_crashText [ 1024 ] ;
2018-08-20 23:45:33 +00:00
static std : : atomic < bool > s_alreadyCrashed ( false ) ;
2018-08-20 12:30:56 +00:00
2019-02-20 15:28:27 +00:00
static void ThreadFreezer ( int /*signal*/ )
2018-08-20 12:30:56 +00:00
{
for ( ; ; ) sleep ( 1000 ) ;
}
static inline void HexPrint ( char * & ptr , uint64_t val )
{
if ( val = = 0 )
{
* ptr + + = ' 0 ' ;
return ;
}
static const char HexTable [ 16 ] = { ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' , ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' } ;
char buf [ 16 ] ;
auto bptr = buf ;
do
{
* bptr + + = HexTable [ val % 16 ] ;
val / = 16 ;
}
while ( val > 0 ) ;
do
{
* ptr + + = * - - bptr ;
}
while ( bptr ! = buf ) ;
}
2019-02-20 15:28:27 +00:00
static void CrashHandler ( int signal , siginfo_t * info , void * /*ucontext*/ )
2018-08-20 12:30:56 +00:00
{
2018-08-20 23:45:33 +00:00
bool expected = false ;
if ( ! s_alreadyCrashed . compare_exchange_strong ( expected , true ) ) ThreadFreezer ( signal ) ;
2021-02-07 18:04:48 +00:00
struct sigaction act = { } ;
act . sa_handler = SIG_DFL ;
sigaction ( SIGABRT , & act , nullptr ) ;
2018-08-20 12:30:56 +00:00
auto msgPtr = s_crashText ;
switch ( signal )
{
case SIGILL :
strcpy ( msgPtr , " Illegal Instruction. \n " ) ;
while ( * msgPtr ) msgPtr + + ;
switch ( info - > si_code )
{
case ILL_ILLOPC :
strcpy ( msgPtr , " Illegal opcode. \n " ) ;
break ;
case ILL_ILLOPN :
strcpy ( msgPtr , " Illegal operand. \n " ) ;
break ;
case ILL_ILLADR :
strcpy ( msgPtr , " Illegal addressing mode. \n " ) ;
break ;
case ILL_ILLTRP :
strcpy ( msgPtr , " Illegal trap. \n " ) ;
break ;
case ILL_PRVOPC :
strcpy ( msgPtr , " Privileged opcode. \n " ) ;
break ;
case ILL_PRVREG :
strcpy ( msgPtr , " Privileged register. \n " ) ;
break ;
case ILL_COPROC :
strcpy ( msgPtr , " Coprocessor error. \n " ) ;
break ;
case ILL_BADSTK :
strcpy ( msgPtr , " Internal stack error. \n " ) ;
break ;
default :
break ;
}
break ;
case SIGFPE :
strcpy ( msgPtr , " Floating-point exception. \n " ) ;
while ( * msgPtr ) msgPtr + + ;
switch ( info - > si_code )
{
case FPE_INTDIV :
strcpy ( msgPtr , " Integer divide by zero. \n " ) ;
break ;
case FPE_INTOVF :
strcpy ( msgPtr , " Integer overflow. \n " ) ;
break ;
case FPE_FLTDIV :
strcpy ( msgPtr , " Floating-point divide by zero. \n " ) ;
break ;
case FPE_FLTOVF :
strcpy ( msgPtr , " Floating-point overflow. \n " ) ;
break ;
case FPE_FLTUND :
strcpy ( msgPtr , " Floating-point underflow. \n " ) ;
break ;
case FPE_FLTRES :
strcpy ( msgPtr , " Floating-point inexact result. \n " ) ;
break ;
case FPE_FLTINV :
strcpy ( msgPtr , " Floating-point invalid operation. \n " ) ;
break ;
case FPE_FLTSUB :
strcpy ( msgPtr , " Subscript out of range. \n " ) ;
break ;
default :
break ;
}
break ;
case SIGSEGV :
strcpy ( msgPtr , " Invalid memory reference. \n " ) ;
while ( * msgPtr ) msgPtr + + ;
switch ( info - > si_code )
{
case SEGV_MAPERR :
strcpy ( msgPtr , " Address not mapped to object. \n " ) ;
break ;
case SEGV_ACCERR :
strcpy ( msgPtr , " Invalid permissions for mapped object. \n " ) ;
break ;
2018-08-27 12:45:07 +00:00
# ifdef SEGV_BNDERR
2018-08-20 12:30:56 +00:00
case SEGV_BNDERR :
strcpy ( msgPtr , " Failed address bound checks. \n " ) ;
break ;
2018-08-27 12:45:07 +00:00
# endif
# ifdef SEGV_PKUERR
2018-08-20 12:30:56 +00:00
case SEGV_PKUERR :
strcpy ( msgPtr , " Access was denied by memory protection keys. \n " ) ;
break ;
2018-08-27 12:45:07 +00:00
# endif
2018-08-20 12:30:56 +00:00
default :
break ;
}
break ;
case SIGPIPE :
strcpy ( msgPtr , " Broken pipe. \n " ) ;
while ( * msgPtr ) msgPtr + + ;
break ;
case SIGBUS :
strcpy ( msgPtr , " Bus error. \n " ) ;
while ( * msgPtr ) msgPtr + + ;
switch ( info - > si_code )
{
case BUS_ADRALN :
strcpy ( msgPtr , " Invalid address alignment. \n " ) ;
break ;
case BUS_ADRERR :
strcpy ( msgPtr , " Nonexistent physical address. \n " ) ;
break ;
case BUS_OBJERR :
strcpy ( msgPtr , " Object-specific hardware error. \n " ) ;
break ;
2020-02-12 00:27:03 +00:00
# ifdef BUS_MCEERR_AR
2018-08-20 12:30:56 +00:00
case BUS_MCEERR_AR :
strcpy ( msgPtr , " Hardware memory error consumed on a machine check; action required. \n " ) ;
break ;
2020-02-12 00:27:03 +00:00
# endif
# ifdef BUS_MCEERR_AO
2018-08-20 12:30:56 +00:00
case BUS_MCEERR_AO :
strcpy ( msgPtr , " Hardware memory error detected in process but not consumed; action optional. \n " ) ;
break ;
2020-02-12 00:27:03 +00:00
# endif
2018-08-20 12:30:56 +00:00
default :
break ;
}
break ;
2021-02-07 18:04:48 +00:00
case SIGABRT :
strcpy ( msgPtr , " Abort signal from abort(). \n " ) ;
break ;
2018-08-20 12:30:56 +00:00
default :
abort ( ) ;
}
while ( * msgPtr ) msgPtr + + ;
if ( signal ! = SIGPIPE )
{
strcpy ( msgPtr , " Fault address: 0x " ) ;
while ( * msgPtr ) msgPtr + + ;
HexPrint ( msgPtr , uint64_t ( info - > si_addr ) ) ;
* msgPtr + + = ' \n ' ;
}
{
2020-09-29 14:39:56 +00:00
GetProfiler ( ) . SendCallstack ( 60 , " __kernel_rt_sigreturn " ) ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : CrashReport ) ;
2018-08-20 12:30:56 +00:00
item - > crashReport . time = Profiler : : GetTime ( ) ;
item - > crashReport . text = ( uint64_t ) s_crashText ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2018-08-20 12:30:56 +00:00
}
DIR * dp = opendir ( " /proc/self/task " ) ;
if ( ! dp ) abort ( ) ;
const auto selfTid = syscall ( SYS_gettid ) ;
struct dirent * ep ;
while ( ( ep = readdir ( dp ) ) ! = nullptr )
{
if ( ep - > d_name [ 0 ] = = ' . ' ) continue ;
int tid = atoi ( ep - > d_name ) ;
if ( tid ! = selfTid & & tid ! = s_profilerTid )
{
syscall ( SYS_tkill , tid , SIGPWR ) ;
}
}
closedir ( dp ) ;
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : Crash ) ;
TracyLfqCommit ;
2018-08-20 12:30:56 +00:00
}
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 500 ) ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . RequestShutdown ( ) ;
while ( ! GetProfiler ( ) . HasShutdownFinished ( ) ) { std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ; } ;
2018-08-20 12:30:56 +00:00
abort ( ) ;
}
# endif
2019-02-19 19:43:14 +00:00
enum { QueuePrealloc = 256 * 1024 } ;
2020-06-23 23:32:57 +00:00
static Profiler * s_instance = nullptr ;
2019-02-19 19:43:14 +00:00
static Thread * s_thread ;
2021-04-29 18:55:16 +00:00
# ifndef TRACY_NO_FRAME_IMAGE
2019-06-26 20:57:24 +00:00
static Thread * s_compressThread ;
2021-04-29 18:55:16 +00:00
# endif
2019-02-19 19:43:14 +00:00
2019-08-12 18:08:15 +00:00
# ifdef TRACY_HAS_SYSTEM_TRACING
static Thread * s_sysTraceThread = nullptr ;
# endif
2020-06-23 23:32:57 +00:00
TRACY_API bool ProfilerAvailable ( ) { return s_instance ! = nullptr ; }
2020-07-07 19:24:44 +00:00
TRACY_API int64_t GetFrequencyQpc ( )
{
# if defined _WIN32 || defined __CYGWIN__
LARGE_INTEGER t ;
QueryPerformanceFrequency ( & t ) ;
return t . QuadPart ;
# else
return 0 ;
# endif
}
2019-02-19 19:43:14 +00:00
# ifdef TRACY_DELAYED_INIT
struct ThreadNameData ;
2019-06-07 13:56:46 +00:00
TRACY_API moodycamel : : ConcurrentQueue < QueueItem > & GetQueue ( ) ;
2019-02-19 19:43:14 +00:00
struct ProfilerData
{
int64_t initTime = SetupHwTimer ( ) ;
moodycamel : : ConcurrentQueue < QueueItem > queue ;
Profiler profiler ;
2019-05-27 12:09:55 +00:00
std : : atomic < uint32_t > lockCounter { 0 } ;
std : : atomic < uint8_t > gpuCtxCounter { 0 } ;
std : : atomic < ThreadNameData * > threadNameData { nullptr } ;
2019-02-19 19:43:14 +00:00
} ;
2019-02-19 17:27:00 +00:00
struct ProducerWrapper
{
2019-02-19 19:43:14 +00:00
ProducerWrapper ( ProfilerData & data ) : detail ( data . queue ) , ptr ( data . queue . get_explicit_producer ( detail ) ) { }
moodycamel : : ProducerToken detail ;
2019-02-19 17:27:00 +00:00
tracy : : moodycamel : : ConcurrentQueue < QueueItem > : : ExplicitProducer * ptr ;
} ;
2019-02-19 19:43:14 +00:00
struct ProfilerThreadData
{
ProfilerThreadData ( ProfilerData & data ) : token ( data ) , gpuCtx ( { nullptr } ) { }
ProducerWrapper token ;
GpuCtxWrapper gpuCtx ;
# ifdef TRACY_ON_DEMAND
LuaZoneState luaZoneState ;
# endif
} ;
2021-05-31 20:55:30 +00:00
std : : atomic < int > RpInitDone { 0 } ;
std : : atomic < int > RpInitLock { 0 } ;
thread_local bool RpThreadInitDone = false ;
2020-07-08 10:48:37 +00:00
# ifdef TRACY_MANUAL_LIFETIME
2020-07-07 07:39:09 +00:00
ProfilerData * s_profilerData = nullptr ;
2021-07-25 09:28:42 +00:00
static ProfilerThreadData & GetProfilerThreadData ( ) ;
2020-07-07 10:12:02 +00:00
TRACY_API void StartupProfiler ( )
2020-07-07 07:39:09 +00:00
{
2021-04-10 11:02:32 +00:00
s_profilerData = ( ProfilerData * ) tracy_malloc ( sizeof ( ProfilerData ) ) ;
new ( s_profilerData ) ProfilerData ( ) ;
2020-07-07 07:39:09 +00:00
s_profilerData - > profiler . SpawnWorkerThreads ( ) ;
2021-07-25 09:28:42 +00:00
GetProfilerThreadData ( ) . token = ProducerWrapper ( * s_profilerData ) ;
2020-07-07 07:39:09 +00:00
}
static ProfilerData & GetProfilerData ( )
{
2021-07-25 09:28:42 +00:00
assert ( s_profilerData ) ;
2020-07-07 07:39:09 +00:00
return * s_profilerData ;
}
2020-07-07 10:12:02 +00:00
TRACY_API void ShutdownProfiler ( )
2020-07-07 07:39:09 +00:00
{
2021-04-10 11:02:32 +00:00
s_profilerData - > ~ ProfilerData ( ) ;
tracy_free ( s_profilerData ) ;
2020-07-07 07:39:09 +00:00
s_profilerData = nullptr ;
2020-07-08 10:50:25 +00:00
rpmalloc_finalize ( ) ;
2021-07-25 09:28:42 +00:00
RpThreadInitDone = false ;
RpInitDone . store ( 0 , std : : memory_order_release ) ;
2020-07-07 07:39:09 +00:00
}
2020-07-08 10:48:37 +00:00
# else
2019-06-19 15:28:18 +00:00
static std : : atomic < int > profilerDataLock { 0 } ;
static std : : atomic < ProfilerData * > profilerData { nullptr } ;
2018-08-19 23:05:09 +00:00
2019-02-19 19:43:14 +00:00
static ProfilerData & GetProfilerData ( )
{
2019-06-19 15:28:18 +00:00
auto ptr = profilerData . load ( std : : memory_order_acquire ) ;
if ( ! ptr )
2019-02-19 19:43:14 +00:00
{
2019-06-19 15:28:18 +00:00
int expected = 0 ;
2021-05-31 00:22:13 +00:00
while ( ! profilerDataLock . compare_exchange_weak ( expected , 1 , std : : memory_order_release , std : : memory_order_relaxed ) ) { expected = 0 ; YieldThread ( ) ; }
2019-06-19 15:28:18 +00:00
ptr = profilerData . load ( std : : memory_order_acquire ) ;
if ( ! ptr )
{
2021-04-10 11:02:32 +00:00
ptr = ( ProfilerData * ) tracy_malloc ( sizeof ( ProfilerData ) ) ;
2019-06-19 15:28:18 +00:00
new ( ptr ) ProfilerData ( ) ;
profilerData . store ( ptr , std : : memory_order_release ) ;
}
profilerDataLock . store ( 0 , std : : memory_order_release ) ;
2019-02-19 19:43:14 +00:00
}
2019-06-19 15:28:18 +00:00
return * ptr ;
2019-02-19 19:43:14 +00:00
}
2020-07-08 10:48:37 +00:00
# endif
2017-09-24 13:59:53 +00:00
2021-04-09 18:51:16 +00:00
// GCC prior to 8.4 had a bug with function-inline thread_local variables. Versions of glibc beginning with
// 2.18 may attempt to work around this issue, which manifests as a crash while running static destructors
// if this function is compiled into a shared object. Unfortunately, centos7 ships with glibc 2.17. If running
// on old GCC, use the old-fashioned way as a workaround
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85400
# if defined(__GNUC__) && ((__GNUC__ < 8) || ((__GNUC__ == 8) && (__GNUC_MINOR__ < 4)))
struct ProfilerThreadDataKey
{
public :
ProfilerThreadDataKey ( )
{
int val = pthread_key_create ( & m_key , sDestructor ) ;
static_cast < void > ( val ) ; // unused
assert ( val = = 0 ) ;
}
~ ProfilerThreadDataKey ( )
{
int val = pthread_key_delete ( m_key ) ;
static_cast < void > ( val ) ; // unused
assert ( val = = 0 ) ;
}
ProfilerThreadData & get ( )
{
void * p = pthread_getspecific ( m_key ) ;
if ( ! p )
{
2021-04-11 23:40:24 +00:00
p = ( ProfilerThreadData * ) tracy_malloc ( sizeof ( ProfilerThreadData ) ) ;
new ( p ) ProfilerThreadData ( GetProfilerData ( ) ) ;
2021-04-09 18:51:16 +00:00
pthread_setspecific ( m_key , p ) ;
}
return * static_cast < ProfilerThreadData * > ( p ) ;
}
private :
pthread_key_t m_key ;
static void sDestructor ( void * p )
{
2021-04-11 23:40:24 +00:00
( ( ProfilerThreadData * ) p ) - > ~ ProfilerThreadData ( ) ;
tracy_free ( p ) ;
2021-04-09 18:51:16 +00:00
}
} ;
static ProfilerThreadData & GetProfilerThreadData ( )
{
static ProfilerThreadDataKey key ;
return key . get ( ) ;
}
# else
2019-02-19 19:43:14 +00:00
static ProfilerThreadData & GetProfilerThreadData ( )
{
thread_local ProfilerThreadData data ( GetProfilerData ( ) ) ;
return data ;
}
2021-04-09 18:51:16 +00:00
# endif
2017-09-18 17:08:54 +00:00
2019-06-07 13:56:46 +00:00
TRACY_API moodycamel : : ConcurrentQueue < QueueItem > : : ExplicitProducer * GetToken ( ) { return GetProfilerThreadData ( ) . token . ptr ; }
TRACY_API Profiler & GetProfiler ( ) { return GetProfilerData ( ) . profiler ; }
TRACY_API moodycamel : : ConcurrentQueue < QueueItem > & GetQueue ( ) { return GetProfilerData ( ) . queue ; }
TRACY_API int64_t GetInitTime ( ) { return GetProfilerData ( ) . initTime ; }
TRACY_API std : : atomic < uint32_t > & GetLockCounter ( ) { return GetProfilerData ( ) . lockCounter ; }
TRACY_API std : : atomic < uint8_t > & GetGpuCtxCounter ( ) { return GetProfilerData ( ) . gpuCtxCounter ; }
TRACY_API GpuCtxWrapper & GetGpuCtx ( ) { return GetProfilerThreadData ( ) . gpuCtx ; }
2019-06-26 17:32:52 +00:00
TRACY_API uint64_t GetThreadHandle ( ) { return detail : : GetThreadHandleImpl ( ) ; }
2020-01-25 15:17:03 +00:00
std : : atomic < ThreadNameData * > & GetThreadNameData ( ) { return GetProfilerData ( ) . threadNameData ; }
2019-02-19 19:43:14 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-07 13:56:46 +00:00
TRACY_API LuaZoneState & GetLuaZoneState ( ) { return GetProfilerThreadData ( ) . luaZoneState ; }
2019-02-19 19:43:14 +00:00
# endif
2020-07-12 17:04:07 +00:00
# ifndef TRACY_MANUAL_LIFETIME
2020-05-19 11:55:54 +00:00
namespace
{
const auto & __profiler_init = GetProfiler ( ) ;
}
2020-07-08 10:48:37 +00:00
# endif
2020-05-19 11:55:54 +00:00
2019-02-19 19:43:14 +00:00
# else
// MSVC static initialization order solution. gcc/clang uses init_order() to avoid all this.
2017-09-10 15:43:56 +00:00
2017-10-16 22:36:15 +00:00
// 1a. But s_queue is needed for initialization of variables in point 2.
extern moodycamel : : ConcurrentQueue < QueueItem > s_queue ;
// 2. If these variables would be in the .CRT$XCB section, they would be initialized only in main thread.
2019-02-19 13:46:24 +00:00
thread_local moodycamel : : ProducerToken init_order ( 107 ) s_token_detail ( s_queue ) ;
2017-10-24 20:02:49 +00:00
thread_local ProducerWrapper init_order ( 108 ) s_token { s_queue . get_explicit_producer ( s_token_detail ) } ;
2019-06-26 17:32:52 +00:00
thread_local ThreadHandleWrapper init_order ( 104 ) s_threadHandle { detail : : GetThreadHandleImpl ( ) } ;
2017-10-16 22:36:15 +00:00
2019-02-19 19:43:14 +00:00
# ifdef _MSC_VER
2017-10-16 22:36:15 +00:00
// 1. Initialize these static variables before all other variables.
2019-02-19 19:43:14 +00:00
# pragma warning( disable : 4075 )
# pragma init_seg( ".CRT$XCB" )
# endif
2017-10-16 22:36:15 +00:00
2018-04-27 14:58:45 +00:00
static InitTimeWrapper init_order ( 101 ) s_initTime { SetupHwTimer ( ) } ;
2021-05-31 00:30:59 +00:00
std : : atomic < int > init_order ( 102 ) RpInitDone ( 0 ) ;
std : : atomic < int > init_order ( 102 ) RpInitLock ( 0 ) ;
2021-05-31 20:38:22 +00:00
thread_local bool RpThreadInitDone = false ;
2017-10-16 23:07:34 +00:00
moodycamel : : ConcurrentQueue < QueueItem > init_order ( 103 ) s_queue ( QueuePrealloc ) ;
2017-10-24 20:02:49 +00:00
std : : atomic < uint32_t > init_order ( 104 ) s_lockCounter ( 0 ) ;
2018-06-22 13:10:23 +00:00
std : : atomic < uint8_t > init_order ( 104 ) s_gpuCtxCounter ( 0 ) ;
2017-10-30 19:45:00 +00:00
2017-11-14 22:29:48 +00:00
thread_local GpuCtxWrapper init_order ( 104 ) s_gpuCtx { nullptr } ;
2017-11-13 23:48:26 +00:00
2017-10-30 19:45:00 +00:00
struct ThreadNameData ;
2018-07-31 11:03:09 +00:00
static std : : atomic < ThreadNameData * > init_order ( 104 ) s_threadNameDataInstance ( nullptr ) ;
2018-07-30 16:12:42 +00:00
std : : atomic < ThreadNameData * > & s_threadNameData = s_threadNameDataInstance ;
2017-10-30 19:45:00 +00:00
2019-02-19 19:43:14 +00:00
# ifdef TRACY_ON_DEMAND
2018-07-13 18:20:37 +00:00
thread_local LuaZoneState init_order ( 104 ) s_luaZoneState { 0 , false } ;
2019-02-19 19:43:14 +00:00
# endif
2018-07-12 10:53:35 +00:00
2019-02-19 17:38:08 +00:00
static Profiler init_order ( 105 ) s_profiler ;
2018-07-30 16:12:42 +00:00
2019-06-07 13:56:46 +00:00
TRACY_API moodycamel : : ConcurrentQueue < QueueItem > : : ExplicitProducer * GetToken ( ) { return s_token . ptr ; }
TRACY_API Profiler & GetProfiler ( ) { return s_profiler ; }
TRACY_API moodycamel : : ConcurrentQueue < QueueItem > & GetQueue ( ) { return s_queue ; }
TRACY_API int64_t GetInitTime ( ) { return s_initTime . val ; }
TRACY_API std : : atomic < uint32_t > & GetLockCounter ( ) { return s_lockCounter ; }
TRACY_API std : : atomic < uint8_t > & GetGpuCtxCounter ( ) { return s_gpuCtxCounter ; }
TRACY_API GpuCtxWrapper & GetGpuCtx ( ) { return s_gpuCtx ; }
2019-07-25 22:02:57 +00:00
# ifdef __CYGWIN__
// Hackfix for cygwin reporting memory frees without matching allocations. WTF?
TRACY_API uint64_t GetThreadHandle ( ) { return detail : : GetThreadHandleImpl ( ) ; }
# else
2019-06-26 17:32:52 +00:00
TRACY_API uint64_t GetThreadHandle ( ) { return s_threadHandle . val ; }
2019-07-25 22:02:57 +00:00
# endif
2019-02-19 17:27:00 +00:00
2020-01-25 15:17:03 +00:00
std : : atomic < ThreadNameData * > & GetThreadNameData ( ) { return s_threadNameData ; }
2018-07-30 16:12:42 +00:00
2019-02-19 19:43:14 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-07 13:56:46 +00:00
TRACY_API LuaZoneState & GetLuaZoneState ( ) { return s_luaZoneState ; }
2019-02-19 19:43:14 +00:00
# endif
2019-02-19 18:33:37 +00:00
# endif
2019-02-19 17:45:41 +00:00
2017-09-10 15:43:56 +00:00
Profiler : : Profiler ( )
2017-10-16 23:07:54 +00:00
: m_timeBegin ( 0 )
2019-06-25 13:44:49 +00:00
, m_mainThread ( detail : : GetThreadHandleImpl ( ) )
2017-10-03 22:34:05 +00:00
, m_epoch ( std : : chrono : : duration_cast < std : : chrono : : seconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) )
2017-09-10 18:14:16 +00:00
, m_shutdown ( false )
2018-08-20 19:49:23 +00:00
, m_shutdownManual ( false )
2018-08-19 23:02:27 +00:00
, m_shutdownFinished ( false )
2017-10-18 17:49:17 +00:00
, m_sock ( nullptr )
2019-06-17 00:25:09 +00:00
, m_broadcast ( nullptr )
2018-07-13 21:55:40 +00:00
, m_noExit ( false )
2020-03-08 15:14:36 +00:00
, m_userPort ( 0 )
2019-01-14 21:23:24 +00:00
, m_zoneId ( 1 )
2020-02-25 22:08:52 +00:00
, m_samplingPeriod ( 0 )
2017-09-17 11:10:42 +00:00
, m_stream ( LZ4_createStream ( ) )
2017-10-14 15:15:18 +00:00
, m_buffer ( ( char * ) tracy_malloc ( TargetFrameSize * 3 ) )
2017-09-17 11:10:42 +00:00
, m_bufferOffset ( 0 )
2017-11-11 13:16:37 +00:00
, m_bufferStart ( 0 )
2017-11-02 16:37:10 +00:00
, m_lz4Buf ( ( char * ) tracy_malloc ( LZ4Size + sizeof ( lz4sz_t ) ) )
2018-04-01 17:53:05 +00:00
, m_serialQueue ( 1024 * 1024 )
2018-04-14 13:46:11 +00:00
, m_serialDequeue ( 1024 * 1024 )
2021-04-29 18:55:16 +00:00
# ifndef TRACY_NO_FRAME_IMAGE
2019-06-26 20:50:56 +00:00
, m_fiQueue ( 16 )
, m_fiDequeue ( 16 )
2021-04-29 18:55:16 +00:00
# endif
2019-06-26 21:18:30 +00:00
, m_frameCount ( 0 )
2018-07-10 19:50:00 +00:00
, m_isConnected ( false )
2020-07-16 09:22:06 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-09 15:15:47 +00:00
, m_connectionId ( 0 )
2018-07-11 10:14:28 +00:00
, m_deferredQueue ( 64 * 1024 )
2018-07-10 19:50:00 +00:00
# endif
2019-11-25 22:59:48 +00:00
, m_paramCallback ( nullptr )
2021-02-03 23:03:25 +00:00
, m_queryData ( nullptr )
2021-07-25 09:46:20 +00:00
, m_crashHandlerInstalled ( false )
2017-09-10 15:43:56 +00:00
{
assert ( ! s_instance ) ;
s_instance = this ;
2019-02-19 19:43:14 +00:00
# ifndef TRACY_DELAYED_INIT
# ifdef _MSC_VER
2017-10-16 22:36:15 +00:00
// 3. But these variables need to be initialized in main thread within the .CRT$XCB section. Do it here.
s_token_detail = moodycamel : : ProducerToken ( s_queue ) ;
s_token = ProducerWrapper { s_queue . get_explicit_producer ( s_token_detail ) } ;
2019-06-26 17:32:52 +00:00
s_threadHandle = ThreadHandleWrapper { m_mainThread } ;
2019-02-19 19:43:14 +00:00
# endif
2017-10-16 22:36:15 +00:00
# endif
2017-09-23 19:33:05 +00:00
CalibrateTimer ( ) ;
2017-09-24 14:02:09 +00:00
CalibrateDelay ( ) ;
2019-11-29 17:29:09 +00:00
ReportTopology ( ) ;
2017-09-23 19:33:05 +00:00
2018-07-13 21:55:40 +00:00
# ifndef TRACY_NO_EXIT
2021-04-09 22:33:01 +00:00
const char * noExitEnv = GetEnvVar ( " TRACY_NO_EXIT " ) ;
2018-07-13 21:55:40 +00:00
if ( noExitEnv & & noExitEnv [ 0 ] = = ' 1 ' )
{
m_noExit = true ;
}
# endif
2021-04-09 22:33:01 +00:00
const char * userPort = GetEnvVar ( " TRACY_PORT " ) ;
2020-03-08 15:14:36 +00:00
if ( userPort )
{
m_userPort = atoi ( userPort ) ;
}
2020-07-12 17:12:50 +00:00
# if !defined(TRACY_DELAYED_INIT) || !defined(TRACY_MANUAL_LIFETIME)
2020-07-07 07:39:09 +00:00
SpawnWorkerThreads ( ) ;
# endif
}
void Profiler : : SpawnWorkerThreads ( )
{
2019-08-12 18:08:15 +00:00
# ifdef TRACY_HAS_SYSTEM_TRACING
2020-02-25 22:08:52 +00:00
if ( SysTraceStart ( m_samplingPeriod ) )
2019-08-12 18:08:15 +00:00
{
s_sysTraceThread = ( Thread * ) tracy_malloc ( sizeof ( Thread ) ) ;
new ( s_sysTraceThread ) Thread ( SysTraceWorker , nullptr ) ;
2020-04-14 20:43:23 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1 ) ) ;
2019-08-12 18:08:15 +00:00
}
# endif
2021-06-04 12:07:46 +00:00
s_thread = ( Thread * ) tracy_malloc ( sizeof ( Thread ) ) ;
new ( s_thread ) Thread ( LaunchWorker , this ) ;
# ifndef TRACY_NO_FRAME_IMAGE
s_compressThread = ( Thread * ) tracy_malloc ( sizeof ( Thread ) ) ;
new ( s_compressThread ) Thread ( LaunchCompressWorker , this ) ;
# endif
2019-11-07 18:08:43 +00:00
# if defined _WIN32 || defined __CYGWIN__
2019-11-07 18:01:42 +00:00
s_profilerThreadId = GetThreadId ( s_thread - > Handle ( ) ) ;
2021-07-25 09:48:27 +00:00
m_exceptionHandler = AddVectoredExceptionHandler ( 1 , CrashFilter ) ;
2018-08-19 23:05:09 +00:00
# endif
2018-08-20 12:30:56 +00:00
# ifdef __linux__
struct sigaction threadFreezer = { } ;
threadFreezer . sa_handler = ThreadFreezer ;
2021-07-25 09:40:22 +00:00
sigaction ( SIGPWR , & threadFreezer , & m_prevSignal . pwr ) ;
2018-08-20 12:30:56 +00:00
struct sigaction crashHandler = { } ;
crashHandler . sa_sigaction = CrashHandler ;
crashHandler . sa_flags = SA_SIGINFO ;
2021-07-25 09:40:22 +00:00
sigaction ( SIGILL , & crashHandler , & m_prevSignal . ill ) ;
sigaction ( SIGFPE , & crashHandler , & m_prevSignal . fpe ) ;
sigaction ( SIGSEGV , & crashHandler , & m_prevSignal . segv ) ;
sigaction ( SIGPIPE , & crashHandler , & m_prevSignal . pipe ) ;
sigaction ( SIGBUS , & crashHandler , & m_prevSignal . bus ) ;
sigaction ( SIGABRT , & crashHandler , & m_prevSignal . abrt ) ;
2018-08-20 12:30:56 +00:00
# endif
2021-07-25 09:46:20 +00:00
m_crashHandlerInstalled = true ;
2018-06-18 23:17:19 +00:00
# ifdef TRACY_HAS_CALLSTACK
InitCallstack ( ) ;
# endif
2017-10-29 15:12:16 +00:00
m_timeBegin . store ( GetTime ( ) , std : : memory_order_relaxed ) ;
2017-09-10 15:43:56 +00:00
}
Profiler : : ~ Profiler ( )
{
2017-09-13 21:36:40 +00:00
m_shutdown . store ( true , std : : memory_order_relaxed ) ;
2019-08-12 18:08:15 +00:00
2021-07-25 09:48:27 +00:00
# if defined _WIN32 || defined __CYGWIN__
if ( m_crashHandlerInstalled ) RemoveVectoredExceptionHandler ( m_exceptionHandler ) ;
# endif
2021-07-25 09:40:22 +00:00
# ifdef __linux__
2021-07-25 09:46:20 +00:00
if ( m_crashHandlerInstalled )
{
sigaction ( SIGPWR , & m_prevSignal . pwr , nullptr ) ;
sigaction ( SIGILL , & m_prevSignal . ill , nullptr ) ;
sigaction ( SIGFPE , & m_prevSignal . fpe , nullptr ) ;
sigaction ( SIGSEGV , & m_prevSignal . segv , nullptr ) ;
sigaction ( SIGPIPE , & m_prevSignal . pipe , nullptr ) ;
sigaction ( SIGBUS , & m_prevSignal . bus , nullptr ) ;
sigaction ( SIGABRT , & m_prevSignal . abrt , nullptr ) ;
}
2021-07-25 09:40:22 +00:00
# endif
2019-08-12 18:08:15 +00:00
# ifdef TRACY_HAS_SYSTEM_TRACING
if ( s_sysTraceThread )
{
SysTraceStop ( ) ;
s_sysTraceThread - > ~ Thread ( ) ;
tracy_free ( s_sysTraceThread ) ;
}
# endif
2021-04-29 18:55:16 +00:00
# ifndef TRACY_NO_FRAME_IMAGE
2019-06-26 20:57:24 +00:00
s_compressThread - > ~ Thread ( ) ;
tracy_free ( s_compressThread ) ;
2021-04-29 18:55:16 +00:00
# endif
2017-10-16 19:13:57 +00:00
s_thread - > ~ Thread ( ) ;
tracy_free ( s_thread ) ;
2017-09-13 21:36:40 +00:00
2017-11-02 16:37:10 +00:00
tracy_free ( m_lz4Buf ) ;
2017-10-14 15:15:18 +00:00
tracy_free ( m_buffer ) ;
2019-05-01 10:57:42 +00:00
LZ4_freeStream ( ( LZ4_stream_t * ) m_stream ) ;
2017-09-17 11:10:42 +00:00
2017-10-18 17:49:17 +00:00
if ( m_sock )
{
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
}
2019-06-17 00:25:09 +00:00
if ( m_broadcast )
{
m_broadcast - > ~ UdpBroadcast ( ) ;
tracy_free ( m_broadcast ) ;
}
2017-09-10 15:43:56 +00:00
assert ( s_instance ) ;
s_instance = nullptr ;
}
2017-09-14 17:23:50 +00:00
bool Profiler : : ShouldExit ( )
{
return s_instance - > m_shutdown . load ( std : : memory_order_relaxed ) ;
}
2017-09-10 15:43:56 +00:00
void Profiler : : Worker ( )
{
2018-08-20 12:30:56 +00:00
# ifdef __linux__
s_profilerTid = syscall ( SYS_gettid ) ;
# endif
2020-07-08 10:50:25 +00:00
ThreadExitHandler threadExitHandler ;
2019-08-14 00:22:45 +00:00
SetThreadName ( " Tracy Profiler " ) ;
2020-03-08 13:34:09 +00:00
# ifdef TRACY_DATA_PORT
2020-04-13 19:40:52 +00:00
const bool dataPortSearch = false ;
auto dataPort = m_userPort ! = 0 ? m_userPort : TRACY_DATA_PORT ;
2020-03-08 13:34:09 +00:00
# else
2020-04-13 19:40:52 +00:00
const bool dataPortSearch = m_userPort = = 0 ;
auto dataPort = m_userPort ! = 0 ? m_userPort : 8086 ;
2020-03-08 13:34:09 +00:00
# endif
# ifdef TRACY_BROADCAST_PORT
const auto broadcastPort = TRACY_BROADCAST_PORT ;
2019-09-21 13:11:15 +00:00
# else
2020-03-08 13:34:09 +00:00
const auto broadcastPort = 8086 ;
2019-09-21 13:11:15 +00:00
# endif
2019-07-19 17:25:27 +00:00
while ( m_timeBegin . load ( std : : memory_order_relaxed ) = = 0 ) std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
2017-10-18 21:30:54 +00:00
rpmalloc_thread_initialize ( ) ;
2021-01-31 16:42:44 +00:00
m_exectime = 0 ;
const auto execname = GetProcessExecutablePath ( ) ;
if ( execname )
{
struct stat st ;
if ( stat ( execname , & st ) = = 0 )
{
m_exectime = ( uint64_t ) st . st_mtime ;
}
}
2017-10-17 19:53:09 +00:00
const auto procname = GetProcessName ( ) ;
const auto pnsz = std : : min < size_t > ( strlen ( procname ) , WelcomeMessageProgramNameSize - 1 ) ;
2018-08-19 16:15:14 +00:00
const auto hostinfo = GetHostInfo ( ) ;
2018-08-19 16:19:12 +00:00
const auto hisz = std : : min < size_t > ( strlen ( hostinfo ) , WelcomeMessageHostInfoSize - 1 ) ;
2018-08-19 16:15:14 +00:00
2019-08-17 20:19:04 +00:00
const uint64_t pid = GetPid ( ) ;
2021-06-14 23:26:50 +00:00
uint8_t flags = 0 ;
2018-07-10 19:44:23 +00:00
# ifdef TRACY_ON_DEMAND
2021-06-14 23:26:50 +00:00
flags | = WelcomeFlag : : OnDemand ;
2018-07-10 19:44:23 +00:00
# endif
2019-06-13 12:05:15 +00:00
# ifdef __APPLE__
2021-06-14 23:26:50 +00:00
flags | = WelcomeFlag : : IsApple ;
# endif
# ifndef TRACY_NO_CODE_TRANSFER
flags | = WelcomeFlag : : CodeTransfer ;
2019-06-13 12:05:15 +00:00
# endif
2021-06-14 23:32:18 +00:00
# ifdef _WIN32
flags | = WelcomeFlag : : CombineSamples ;
# endif
2019-06-13 12:05:15 +00:00
2020-03-25 20:28:02 +00:00
# if defined __i386 || defined _M_IX86
uint8_t cpuArch = CpuArchX86 ;
# elif defined __x86_64__ || defined _M_X64
uint8_t cpuArch = CpuArchX64 ;
# elif defined __aarch64__
uint8_t cpuArch = CpuArchArm64 ;
# elif defined __ARM_ARCH
uint8_t cpuArch = CpuArchArm32 ;
# else
uint8_t cpuArch = CpuArchUnknown ;
# endif
2020-05-06 16:57:05 +00:00
# if defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
uint32_t regs [ 4 ] ;
char manufacturer [ 12 ] ;
CpuId ( regs , 0 ) ;
memcpy ( manufacturer , regs + 1 , 4 ) ;
memcpy ( manufacturer + 4 , regs + 3 , 4 ) ;
memcpy ( manufacturer + 8 , regs + 2 , 4 ) ;
CpuId ( regs , 1 ) ;
uint32_t cpuId = ( regs [ 0 ] & 0xFFF ) | ( ( regs [ 0 ] & 0xFFF0000 ) > > 4 ) ;
# else
const char manufacturer [ 12 ] = { } ;
uint32_t cpuId = 0 ;
# endif
2017-10-17 19:55:40 +00:00
WelcomeMessage welcome ;
2018-03-31 12:03:55 +00:00
MemWrite ( & welcome . timerMul , m_timerMul ) ;
2019-02-19 19:43:14 +00:00
MemWrite ( & welcome . initBegin , GetInitTime ( ) ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & welcome . initEnd , m_timeBegin . load ( std : : memory_order_relaxed ) ) ;
MemWrite ( & welcome . delay , m_delay ) ;
MemWrite ( & welcome . resolution , m_resolution ) ;
MemWrite ( & welcome . epoch , m_epoch ) ;
2021-01-31 16:45:11 +00:00
MemWrite ( & welcome . exectime , m_exectime ) ;
2019-08-17 20:19:04 +00:00
MemWrite ( & welcome . pid , pid ) ;
2020-02-25 22:12:31 +00:00
MemWrite ( & welcome . samplingPeriod , m_samplingPeriod ) ;
2021-06-14 23:26:50 +00:00
MemWrite ( & welcome . flags , flags ) ;
2020-03-25 20:28:02 +00:00
MemWrite ( & welcome . cpuArch , cpuArch ) ;
2020-05-06 16:57:05 +00:00
memcpy ( welcome . cpuManufacturer , manufacturer , 12 ) ;
MemWrite ( & welcome . cpuId , cpuId ) ;
2017-10-17 19:55:40 +00:00
memcpy ( welcome . programName , procname , pnsz ) ;
memset ( welcome . programName + pnsz , 0 , WelcomeMessageProgramNameSize - pnsz ) ;
2018-08-19 16:19:12 +00:00
memcpy ( welcome . hostInfo , hostinfo , hisz ) ;
memset ( welcome . hostInfo + hisz , 0 , WelcomeMessageHostInfoSize - hisz ) ;
2017-10-17 19:55:40 +00:00
2019-02-19 18:33:37 +00:00
moodycamel : : ConsumerToken token ( GetQueue ( ) ) ;
2017-09-10 18:23:06 +00:00
2017-09-11 20:51:47 +00:00
ListenSocket listen ;
2020-04-13 19:40:52 +00:00
bool isListening = false ;
if ( ! dataPortSearch )
{
isListening = listen . Listen ( dataPort , 4 ) ;
}
else
{
for ( uint32_t i = 0 ; i < 20 ; i + + )
{
if ( listen . Listen ( dataPort + i , 4 ) )
{
dataPort + = i ;
isListening = true ;
break ;
}
}
}
if ( ! isListening )
2018-12-21 17:14:30 +00:00
{
for ( ; ; )
{
if ( ShouldExit ( ) )
{
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
}
ClearQueues ( token ) ;
2020-04-04 19:08:13 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
2018-12-21 17:14:30 +00:00
}
}
2017-09-11 20:51:47 +00:00
2019-06-17 16:18:58 +00:00
# ifndef TRACY_NO_BROADCAST
2019-06-17 00:25:09 +00:00
m_broadcast = ( UdpBroadcast * ) tracy_malloc ( sizeof ( UdpBroadcast ) ) ;
new ( m_broadcast ) UdpBroadcast ( ) ;
2020-12-16 14:24:33 +00:00
# ifdef TRACY_ONLY_LOCALHOST
const char * addr = " 127.255.255.255 " ;
# else
const char * addr = " 255.255.255.255 " ;
# endif
if ( ! m_broadcast - > Open ( addr , broadcastPort ) )
2019-06-17 00:25:09 +00:00
{
m_broadcast - > ~ UdpBroadcast ( ) ;
tracy_free ( m_broadcast ) ;
m_broadcast = nullptr ;
}
2019-06-17 16:18:58 +00:00
# endif
2019-06-17 00:25:09 +00:00
2019-06-18 18:26:40 +00:00
int broadcastLen = 0 ;
2020-03-08 13:37:59 +00:00
auto & broadcastMsg = GetBroadcastMessage ( procname , pnsz , broadcastLen , dataPort ) ;
2019-06-18 18:26:40 +00:00
uint64_t lastBroadcast = 0 ;
2019-06-09 13:55:18 +00:00
// Connections loop.
// Each iteration of the loop handles whole connection. Multiple iterations will only
// happen in the on-demand mode or when handshake fails.
2017-09-10 15:43:56 +00:00
for ( ; ; )
{
2019-06-09 13:55:18 +00:00
// Wait for incoming connection
2017-09-11 20:51:47 +00:00
for ( ; ; )
2017-09-10 18:23:06 +00:00
{
2017-10-18 18:01:12 +00:00
# ifndef TRACY_NO_EXIT
2018-08-19 23:02:27 +00:00
if ( ! m_noExit & & ShouldExit ( ) )
{
2020-09-20 20:19:10 +00:00
if ( m_broadcast )
{
broadcastMsg . activeTime = - 1 ;
m_broadcast - > Send ( broadcastPort , & broadcastMsg , broadcastLen ) ;
}
2018-08-19 23:02:27 +00:00
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
}
2017-10-18 18:01:12 +00:00
# endif
2017-09-14 17:07:56 +00:00
m_sock = listen . Accept ( ) ;
if ( m_sock ) break ;
2019-02-24 18:12:17 +00:00
# ifndef TRACY_ON_DEMAND
ProcessSysTime ( ) ;
# endif
2019-06-17 00:25:09 +00:00
if ( m_broadcast )
{
2019-06-18 18:46:12 +00:00
const auto t = std : : chrono : : high_resolution_clock : : now ( ) . time_since_epoch ( ) . count ( ) ;
2019-06-18 18:15:09 +00:00
if ( t - lastBroadcast > 3000000000 ) // 3s
2019-06-17 00:25:09 +00:00
{
2019-06-18 18:15:09 +00:00
lastBroadcast = t ;
2019-06-18 18:46:12 +00:00
const auto ts = std : : chrono : : duration_cast < std : : chrono : : seconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
2020-09-20 20:15:10 +00:00
broadcastMsg . activeTime = int32_t ( ts - m_epoch ) ;
assert ( broadcastMsg . activeTime > = 0 ) ;
2020-03-08 13:34:09 +00:00
m_broadcast - > Send ( broadcastPort , & broadcastMsg , broadcastLen ) ;
2019-06-17 00:25:09 +00:00
}
}
2017-09-10 18:23:06 +00:00
}
2017-09-11 20:51:47 +00:00
2020-09-20 20:19:10 +00:00
if ( m_broadcast )
{
lastBroadcast = 0 ;
broadcastMsg . activeTime = - 1 ;
m_broadcast - > Send ( broadcastPort , & broadcastMsg , broadcastLen ) ;
}
2019-06-09 13:55:18 +00:00
// Handshake
2018-09-09 16:26:53 +00:00
{
char shibboleth [ HandshakeShibbolethSize ] ;
2019-02-10 14:45:23 +00:00
auto res = m_sock - > ReadRaw ( shibboleth , HandshakeShibbolethSize , 2000 ) ;
2018-09-09 16:26:53 +00:00
if ( ! res | | memcmp ( shibboleth , HandshakeShibboleth , HandshakeShibbolethSize ) ! = 0 )
{
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
2019-06-09 14:10:21 +00:00
m_sock = nullptr ;
2018-09-09 16:26:53 +00:00
continue ;
}
2018-09-09 17:28:53 +00:00
uint32_t protocolVersion ;
2019-02-10 14:45:23 +00:00
res = m_sock - > ReadRaw ( & protocolVersion , sizeof ( protocolVersion ) , 2000 ) ;
2018-09-09 17:28:53 +00:00
if ( ! res )
{
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
2019-06-09 14:10:21 +00:00
m_sock = nullptr ;
2018-09-09 17:28:53 +00:00
continue ;
}
if ( protocolVersion ! = ProtocolVersion )
{
HandshakeStatus status = HandshakeProtocolMismatch ;
m_sock - > Send ( & status , sizeof ( status ) ) ;
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
2019-06-09 14:10:21 +00:00
m_sock = nullptr ;
2018-09-09 17:28:53 +00:00
continue ;
}
2018-09-09 16:26:53 +00:00
}
2018-07-10 19:50:00 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-21 17:34:34 +00:00
const auto currentTime = GetTime ( ) ;
2018-07-10 20:01:13 +00:00
ClearQueues ( token ) ;
2019-06-09 15:15:47 +00:00
m_connectionId . fetch_add ( 1 , std : : memory_order_release ) ;
2018-07-10 19:50:00 +00:00
# endif
2020-07-16 09:22:06 +00:00
m_isConnected . store ( true , std : : memory_order_release ) ;
2018-07-10 19:50:00 +00:00
2018-09-09 17:28:53 +00:00
HandshakeStatus handshake = HandshakeWelcome ;
m_sock - > Send ( & handshake , sizeof ( handshake ) ) ;
2019-05-01 10:57:42 +00:00
LZ4_resetStream ( ( LZ4_stream_t * ) m_stream ) ;
2018-07-10 20:37:39 +00:00
m_sock - > Send ( & welcome , sizeof ( welcome ) ) ;
2019-08-02 18:18:08 +00:00
m_threadCtx = 0 ;
2019-10-23 22:04:31 +00:00
m_refTimeSerial = 0 ;
2019-10-25 17:13:11 +00:00
m_refTimeCtx = 0 ;
2019-10-25 17:52:01 +00:00
m_refTimeGpu = 0 ;
2019-08-02 18:18:08 +00:00
2018-07-10 20:37:39 +00:00
# ifdef TRACY_ON_DEMAND
OnDemandPayloadMessage onDemand ;
onDemand . frames = m_frameCount . load ( std : : memory_order_relaxed ) ;
2019-06-21 17:34:34 +00:00
onDemand . currentTime = currentTime ;
2018-07-10 20:37:39 +00:00
m_sock - > Send ( & onDemand , sizeof ( onDemand ) ) ;
2018-07-11 10:28:40 +00:00
m_deferredLock . lock ( ) ;
for ( auto & item : m_deferredQueue )
{
2020-03-08 14:05:35 +00:00
uint64_t ptr ;
2020-07-25 23:15:11 +00:00
uint16_t size ;
2018-07-11 10:28:40 +00:00
const auto idx = MemRead < uint8_t > ( & item . hdr . idx ) ;
2020-03-08 14:05:35 +00:00
switch ( ( QueueType ) idx )
2019-07-12 16:14:42 +00:00
{
2020-03-08 14:05:35 +00:00
case QueueType : : MessageAppInfo :
2020-07-25 23:15:11 +00:00
ptr = MemRead < uint64_t > ( & item . messageFat . text ) ;
size = MemRead < uint16_t > ( & item . messageFat . size ) ;
SendSingleString ( ( const char * ) ptr , size ) ;
2020-03-08 14:05:35 +00:00
break ;
case QueueType : : LockName :
2020-07-25 23:22:09 +00:00
ptr = MemRead < uint64_t > ( & item . lockNameFat . name ) ;
size = MemRead < uint16_t > ( & item . lockNameFat . size ) ;
SendSingleString ( ( const char * ) ptr , size ) ;
2020-03-08 14:05:35 +00:00
break ;
2021-02-27 18:59:32 +00:00
case QueueType : : GpuContextName :
ptr = MemRead < uint64_t > ( & item . gpuContextNameFat . ptr ) ;
size = MemRead < uint16_t > ( & item . gpuContextNameFat . size ) ;
SendSingleString ( ( const char * ) ptr , size ) ;
break ;
2020-03-26 00:07:25 +00:00
default :
break ;
2019-07-12 16:14:42 +00:00
}
2018-07-11 10:28:40 +00:00
AppendData ( & item , QueueDataSize [ idx ] ) ;
}
m_deferredLock . unlock ( ) ;
2018-07-10 20:37:39 +00:00
# endif
2017-09-17 11:10:42 +00:00
2019-06-09 13:55:18 +00:00
// Main communications loop
2018-07-10 19:33:22 +00:00
int keepAlive = 0 ;
2017-09-11 20:51:47 +00:00
for ( ; ; )
2017-09-10 18:23:06 +00:00
{
2019-02-21 20:59:02 +00:00
ProcessSysTime ( ) ;
2017-10-18 16:48:51 +00:00
const auto status = Dequeue ( token ) ;
2018-04-01 18:04:35 +00:00
const auto serialStatus = DequeueSerial ( ) ;
2019-06-09 14:14:30 +00:00
if ( status = = DequeueStatus : : ConnectionLost | | serialStatus = = DequeueStatus : : ConnectionLost )
2017-09-11 20:51:47 +00:00
{
2017-10-18 16:48:51 +00:00
break ;
2017-09-11 20:51:47 +00:00
}
2019-06-09 14:14:30 +00:00
else if ( status = = DequeueStatus : : QueueEmpty & & serialStatus = = DequeueStatus : : QueueEmpty )
2017-09-11 20:51:47 +00:00
{
2017-10-18 16:48:51 +00:00
if ( ShouldExit ( ) ) break ;
2018-07-10 19:33:22 +00:00
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) break ;
}
if ( keepAlive = = 500 )
{
QueueItem ka ;
ka . hdr . type = QueueType : : KeepAlive ;
AppendData ( & ka , QueueDataSize [ ka . hdr . idx ] ) ;
if ( ! CommitData ( ) ) break ;
keepAlive = 0 ;
}
2021-05-21 23:12:42 +00:00
else if ( ! m_sock - > HasData ( ) )
2018-07-10 19:33:22 +00:00
{
keepAlive + + ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
}
}
else
{
keepAlive = 0 ;
2017-09-11 20:51:47 +00:00
}
2017-09-14 17:25:16 +00:00
2021-05-21 23:05:06 +00:00
int quota = 500 ;
2019-06-09 14:51:39 +00:00
bool connActive = true ;
2021-05-21 23:05:06 +00:00
while ( quota - - & & m_sock - > HasData ( ) )
2017-09-14 17:25:16 +00:00
{
2019-06-09 14:51:39 +00:00
connActive = HandleServerQuery ( ) ;
2021-05-21 23:05:06 +00:00
if ( ! connActive ) break ;
2017-09-14 17:25:16 +00:00
}
2019-06-09 14:51:39 +00:00
if ( ! connActive ) break ;
2017-09-10 18:23:06 +00:00
}
2017-10-18 16:48:51 +00:00
if ( ShouldExit ( ) ) break ;
2018-07-10 19:50:00 +00:00
2019-06-09 14:48:00 +00:00
m_isConnected . store ( false , std : : memory_order_release ) ;
2020-07-16 09:22:06 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-10 00:11:29 +00:00
m_bufferOffset = 0 ;
2019-08-04 15:48:19 +00:00
m_bufferStart = 0 ;
2018-07-10 19:50:00 +00:00
# endif
2018-09-09 16:31:06 +00:00
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
2019-06-09 14:10:21 +00:00
m_sock = nullptr ;
2018-09-09 17:42:06 +00:00
2018-09-09 17:44:41 +00:00
# ifndef TRACY_ON_DEMAND
2019-06-09 13:55:18 +00:00
// Client is no longer available here. Accept incoming connections, but reject handshake.
2018-09-09 17:42:06 +00:00
for ( ; ; )
{
if ( ShouldExit ( ) )
{
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
}
2018-12-21 17:12:26 +00:00
ClearQueues ( token ) ;
2018-09-09 17:42:06 +00:00
m_sock = listen . Accept ( ) ;
if ( m_sock )
{
char shibboleth [ HandshakeShibbolethSize ] ;
2019-02-10 14:45:23 +00:00
auto res = m_sock - > ReadRaw ( shibboleth , HandshakeShibbolethSize , 1000 ) ;
2018-09-09 17:42:06 +00:00
if ( ! res | | memcmp ( shibboleth , HandshakeShibboleth , HandshakeShibbolethSize ) ! = 0 )
{
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
2019-06-09 14:10:21 +00:00
m_sock = nullptr ;
2018-09-09 17:42:06 +00:00
continue ;
}
uint32_t protocolVersion ;
2019-02-10 14:45:23 +00:00
res = m_sock - > ReadRaw ( & protocolVersion , sizeof ( protocolVersion ) , 1000 ) ;
2018-09-09 17:42:06 +00:00
if ( ! res )
{
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
2019-06-09 14:10:21 +00:00
m_sock = nullptr ;
2018-09-09 17:42:06 +00:00
continue ;
}
HandshakeStatus status = HandshakeNotAvailable ;
m_sock - > Send ( & status , sizeof ( status ) ) ;
m_sock - > ~ Socket ( ) ;
tracy_free ( m_sock ) ;
}
}
2018-09-09 17:44:41 +00:00
# endif
2017-10-18 16:48:51 +00:00
}
2019-06-09 13:55:18 +00:00
// End of connections loop
2017-10-18 16:48:51 +00:00
2019-06-09 13:55:18 +00:00
// Client is exiting. Send items remaining in queues.
2018-01-11 12:43:54 +00:00
for ( ; ; )
{
const auto status = Dequeue ( token ) ;
2018-04-01 18:04:35 +00:00
const auto serialStatus = DequeueSerial ( ) ;
2019-06-09 14:14:30 +00:00
if ( status = = DequeueStatus : : ConnectionLost | | serialStatus = = DequeueStatus : : ConnectionLost )
2018-01-11 12:43:54 +00:00
{
2019-06-09 14:22:48 +00:00
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
2018-01-11 12:43:54 +00:00
}
2019-06-09 14:14:30 +00:00
else if ( status = = DequeueStatus : : QueueEmpty & & serialStatus = = DequeueStatus : : QueueEmpty )
2018-01-11 12:43:54 +00:00
{
if ( m_bufferOffset ! = m_bufferStart ) CommitData ( ) ;
break ;
}
while ( m_sock - > HasData ( ) )
{
2019-06-09 14:22:48 +00:00
if ( ! HandleServerQuery ( ) )
{
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
}
2018-01-11 12:43:54 +00:00
}
}
2019-06-09 13:55:18 +00:00
// Send client termination notice to the server
2017-10-18 16:48:51 +00:00
QueueItem terminate ;
2018-03-31 12:03:55 +00:00
MemWrite ( & terminate . hdr . type , QueueType : : Terminate ) ;
2018-08-19 23:02:27 +00:00
if ( ! SendData ( ( const char * ) & terminate , 1 ) )
{
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
}
2019-06-09 13:55:18 +00:00
// Handle remaining server queries
2017-10-18 16:48:51 +00:00
for ( ; ; )
{
if ( m_sock - > HasData ( ) )
{
2017-11-11 13:16:37 +00:00
while ( m_sock - > HasData ( ) )
{
if ( ! HandleServerQuery ( ) )
{
2018-08-19 23:02:27 +00:00
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
2017-11-11 13:16:37 +00:00
return ;
}
}
2019-11-14 17:24:29 +00:00
while ( Dequeue ( token ) = = DequeueStatus : : DataDequeued ) { }
while ( DequeueSerial ( ) = = DequeueStatus : : DataDequeued ) { }
2017-11-11 13:16:37 +00:00
if ( m_bufferOffset ! = m_bufferStart )
{
2018-08-19 23:02:27 +00:00
if ( ! CommitData ( ) )
{
m_shutdownFinished . store ( true , std : : memory_order_relaxed ) ;
return ;
}
2017-11-11 13:16:37 +00:00
}
2017-10-18 16:48:51 +00:00
}
else
{
2017-11-11 13:23:55 +00:00
if ( m_bufferOffset ! = m_bufferStart ) CommitData ( ) ;
2017-10-18 16:48:51 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
}
}
}
2021-04-29 18:55:16 +00:00
# ifndef TRACY_NO_FRAME_IMAGE
2019-06-26 20:57:24 +00:00
void Profiler : : CompressWorker ( )
{
2020-07-08 10:50:25 +00:00
ThreadExitHandler threadExitHandler ;
2019-08-20 14:22:54 +00:00
SetThreadName ( " Tracy DXT1 " ) ;
2019-07-19 17:25:27 +00:00
while ( m_timeBegin . load ( std : : memory_order_relaxed ) = = 0 ) std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
2019-06-27 16:11:52 +00:00
rpmalloc_thread_initialize ( ) ;
2019-06-26 21:18:30 +00:00
for ( ; ; )
{
const auto shouldExit = ShouldExit ( ) ;
{
bool lockHeld = true ;
while ( ! m_fiLock . try_lock ( ) )
{
if ( m_shutdownManual . load ( std : : memory_order_relaxed ) )
{
lockHeld = false ;
break ;
}
}
2019-06-27 11:37:09 +00:00
if ( ! m_fiQueue . empty ( ) ) m_fiQueue . swap ( m_fiDequeue ) ;
2019-06-26 21:18:30 +00:00
if ( lockHeld )
{
m_fiLock . unlock ( ) ;
}
}
2019-06-26 20:57:24 +00:00
2019-06-26 21:18:30 +00:00
const auto sz = m_fiDequeue . size ( ) ;
if ( sz > 0 )
{
auto fi = m_fiDequeue . data ( ) ;
auto end = fi + sz ;
while ( fi ! = end )
{
const auto w = fi - > w ;
const auto h = fi - > h ;
const auto csz = size_t ( w * h / 2 ) ;
auto etc1buf = ( char * ) tracy_malloc ( csz ) ;
2019-06-27 15:09:47 +00:00
CompressImageDxt1 ( ( const char * ) fi - > image , etc1buf , w , h ) ;
2019-06-26 21:18:30 +00:00
tracy_free ( fi - > image ) ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : FrameImage ) ;
2020-07-26 12:18:48 +00:00
MemWrite ( & item - > frameImageFat . image , ( uint64_t ) etc1buf ) ;
MemWrite ( & item - > frameImageFat . frame , fi - > frame ) ;
MemWrite ( & item - > frameImageFat . w , w ) ;
MemWrite ( & item - > frameImageFat . h , h ) ;
2019-06-26 21:18:30 +00:00
uint8_t flip = fi - > flip ;
2020-07-26 12:18:48 +00:00
MemWrite ( & item - > frameImageFat . flip , flip ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-06-26 21:18:30 +00:00
fi + + ;
}
m_fiDequeue . clear ( ) ;
}
else
{
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 20 ) ) ;
}
if ( shouldExit )
{
return ;
}
}
2019-06-26 20:57:24 +00:00
}
2021-04-29 18:55:16 +00:00
# endif
2019-06-26 20:57:24 +00:00
2018-07-10 23:34:48 +00:00
static void FreeAssociatedMemory ( const QueueItem & item )
2018-07-10 20:01:13 +00:00
{
2018-07-10 23:34:48 +00:00
if ( item . hdr . idx > = ( int ) QueueType : : Terminate ) return ;
uint64_t ptr ;
switch ( item . hdr . type )
{
case QueueType : : ZoneText :
case QueueType : : ZoneName :
2020-07-25 22:53:55 +00:00
ptr = MemRead < uint64_t > ( & item . zoneTextFat . text ) ;
2018-07-10 23:34:48 +00:00
tracy_free ( ( void * ) ptr ) ;
break ;
2019-05-10 18:17:44 +00:00
case QueueType : : MessageColor :
2019-11-14 22:40:41 +00:00
case QueueType : : MessageColorCallstack :
2020-12-08 03:07:12 +00:00
ptr = MemRead < uint64_t > ( & item . messageColorFat . text ) ;
tracy_free ( ( void * ) ptr ) ;
break ;
case QueueType : : Message :
case QueueType : : MessageCallstack :
2019-07-12 16:14:42 +00:00
# ifndef TRACY_ON_DEMAND
case QueueType : : MessageAppInfo :
# endif
2020-07-25 23:15:11 +00:00
ptr = MemRead < uint64_t > ( & item . messageFat . text ) ;
2018-07-10 23:34:48 +00:00
tracy_free ( ( void * ) ptr ) ;
break ;
case QueueType : : ZoneBeginAllocSrcLoc :
2019-03-03 16:47:26 +00:00
case QueueType : : ZoneBeginAllocSrcLocCallstack :
2018-07-10 23:34:48 +00:00
ptr = MemRead < uint64_t > ( & item . zoneBegin . srcloc ) ;
tracy_free ( ( void * ) ptr ) ;
break ;
2021-01-15 19:13:09 +00:00
case QueueType : : GpuZoneBeginAllocSrcLoc :
case QueueType : : GpuZoneBeginAllocSrcLocCallstack :
case QueueType : : GpuZoneBeginAllocSrcLocSerial :
case QueueType : : GpuZoneBeginAllocSrcLocCallstackSerial :
ptr = MemRead < uint64_t > ( & item . gpuZoneBegin . srcloc ) ;
tracy_free ( ( void * ) ptr ) ;
break ;
2021-01-15 19:49:39 +00:00
case QueueType : : CallstackSerial :
2018-07-10 23:34:48 +00:00
case QueueType : : Callstack :
2020-07-26 12:15:16 +00:00
ptr = MemRead < uint64_t > ( & item . callstackFat . ptr ) ;
2018-07-10 23:34:48 +00:00
tracy_free ( ( void * ) ptr ) ;
break ;
2019-03-05 01:00:31 +00:00
case QueueType : : CallstackAlloc :
2020-07-26 12:25:32 +00:00
ptr = MemRead < uint64_t > ( & item . callstackAllocFat . nativePtr ) ;
2019-03-05 01:00:31 +00:00
tracy_free ( ( void * ) ptr ) ;
2020-07-26 12:25:32 +00:00
ptr = MemRead < uint64_t > ( & item . callstackAllocFat . ptr ) ;
2019-03-05 18:18:43 +00:00
tracy_free ( ( void * ) ptr ) ;
2019-03-05 01:00:31 +00:00
break ;
2020-02-22 15:05:01 +00:00
case QueueType : : CallstackSample :
2020-07-26 12:28:13 +00:00
ptr = MemRead < uint64_t > ( & item . callstackSampleFat . ptr ) ;
2020-02-22 15:05:01 +00:00
tracy_free ( ( void * ) ptr ) ;
break ;
2019-06-06 19:39:54 +00:00
case QueueType : : FrameImage :
2020-07-26 12:18:48 +00:00
ptr = MemRead < uint64_t > ( & item . frameImageFat . image ) ;
2019-06-06 19:39:54 +00:00
tracy_free ( ( void * ) ptr ) ;
break ;
2020-03-08 12:47:38 +00:00
# ifndef TRACY_ON_DEMAND
case QueueType : : LockName :
2020-07-25 23:22:09 +00:00
ptr = MemRead < uint64_t > ( & item . lockNameFat . name ) ;
2020-03-08 12:47:38 +00:00
tracy_free ( ( void * ) ptr ) ;
break ;
2021-01-31 17:46:42 +00:00
case QueueType : : GpuContextName :
ptr = MemRead < uint64_t > ( & item . gpuContextNameFat . ptr ) ;
tracy_free ( ( void * ) ptr ) ;
break ;
2020-03-08 12:47:38 +00:00
# endif
2019-07-12 16:14:42 +00:00
# ifdef TRACY_ON_DEMAND
case QueueType : : MessageAppInfo :
2021-01-31 17:46:42 +00:00
case QueueType : : GpuContextName :
2019-07-12 16:14:42 +00:00
// Don't free memory associated with deferred messages.
break ;
# endif
2018-07-10 23:34:48 +00:00
default :
break ;
}
}
2018-07-10 20:01:13 +00:00
2018-07-10 23:34:48 +00:00
void Profiler : : ClearQueues ( moodycamel : : ConsumerToken & token )
{
for ( ; ; )
{
2020-05-13 16:15:12 +00:00
const auto sz = GetQueue ( ) . try_dequeue_bulk_single ( token , [ ] ( const uint64_t & ) { } , [ ] ( QueueItem * item , size_t sz ) { assert ( sz > 0 ) ; while ( sz - - > 0 ) FreeAssociatedMemory ( * item + + ) ; } ) ;
2018-07-10 23:34:48 +00:00
if ( sz = = 0 ) break ;
}
2018-07-10 20:01:13 +00:00
2019-08-14 20:39:12 +00:00
ClearSerial ( ) ;
}
void Profiler : : ClearSerial ( )
{
bool lockHeld = true ;
while ( ! m_serialLock . try_lock ( ) )
2018-12-21 17:10:29 +00:00
{
2019-08-14 20:39:12 +00:00
if ( m_shutdownManual . load ( std : : memory_order_relaxed ) )
2018-12-21 17:10:29 +00:00
{
2019-08-14 20:39:12 +00:00
lockHeld = false ;
break ;
2018-12-21 17:10:29 +00:00
}
}
2019-08-14 20:39:12 +00:00
for ( auto & v : m_serialQueue ) FreeAssociatedMemory ( v ) ;
m_serialQueue . clear ( ) ;
if ( lockHeld )
{
m_serialLock . unlock ( ) ;
}
2018-07-10 23:34:48 +00:00
for ( auto & v : m_serialDequeue ) FreeAssociatedMemory ( v ) ;
2018-07-10 20:01:13 +00:00
m_serialDequeue . clear ( ) ;
}
2017-10-18 16:48:51 +00:00
Profiler : : DequeueStatus Profiler : : Dequeue ( moodycamel : : ConsumerToken & token )
{
2020-02-23 13:50:50 +00:00
bool connectionLost = false ;
const auto sz = GetQueue ( ) . try_dequeue_bulk_single ( token ,
[ this , & connectionLost ] ( const uint64_t & threadId )
2019-08-02 18:18:08 +00:00
{
2020-02-23 13:50:50 +00:00
if ( threadId ! = m_threadCtx )
{
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : ThreadContext ) ;
MemWrite ( & item . threadCtx . thread , threadId ) ;
if ( ! AppendData ( & item , QueueDataSize [ ( int ) QueueType : : ThreadContext ] ) ) connectionLost = true ;
m_threadCtx = threadId ;
m_refTimeThread = 0 ;
}
} ,
[ this , & connectionLost ] ( QueueItem * item , size_t sz )
2017-10-18 16:48:51 +00:00
{
2020-02-23 13:50:50 +00:00
if ( connectionLost ) return ;
2021-06-09 23:48:11 +00:00
InitRpmalloc ( ) ;
2020-02-23 13:50:50 +00:00
assert ( sz > 0 ) ;
int64_t refThread = m_refTimeThread ;
int64_t refCtx = m_refTimeCtx ;
int64_t refGpu = m_refTimeGpu ;
while ( sz - - > 0 )
2017-11-11 14:22:55 +00:00
{
2020-02-23 13:50:50 +00:00
uint64_t ptr ;
2020-07-21 18:09:25 +00:00
uint16_t size ;
2020-05-10 17:20:59 +00:00
auto idx = MemRead < uint8_t > ( & item - > hdr . idx ) ;
2020-02-23 13:50:50 +00:00
if ( idx < ( int ) QueueType : : Terminate )
2019-08-02 18:18:08 +00:00
{
2020-02-23 13:50:50 +00:00
switch ( ( QueueType ) idx )
{
case QueueType : : ZoneText :
case QueueType : : ZoneName :
2020-07-21 18:09:25 +00:00
ptr = MemRead < uint64_t > ( & item - > zoneTextFat . text ) ;
size = MemRead < uint16_t > ( & item - > zoneTextFat . size ) ;
2020-07-25 22:53:55 +00:00
SendSingleString ( ( const char * ) ptr , size ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
break ;
case QueueType : : Message :
case QueueType : : MessageCallstack :
2020-07-21 18:22:59 +00:00
ptr = MemRead < uint64_t > ( & item - > messageFat . text ) ;
size = MemRead < uint16_t > ( & item - > messageFat . size ) ;
2020-07-25 23:15:11 +00:00
SendSingleString ( ( const char * ) ptr , size ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-07-21 18:22:59 +00:00
break ;
case QueueType : : MessageColor :
2020-02-23 13:50:50 +00:00
case QueueType : : MessageColorCallstack :
2020-07-21 18:22:59 +00:00
ptr = MemRead < uint64_t > ( & item - > messageColorFat . text ) ;
size = MemRead < uint16_t > ( & item - > messageColorFat . size ) ;
2020-07-25 23:15:11 +00:00
SendSingleString ( ( const char * ) ptr , size ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
break ;
case QueueType : : MessageAppInfo :
2020-07-25 23:15:11 +00:00
ptr = MemRead < uint64_t > ( & item - > messageFat . text ) ;
size = MemRead < uint16_t > ( & item - > messageFat . size ) ;
SendSingleString ( ( const char * ) ptr , size ) ;
2019-08-14 21:05:58 +00:00
# ifndef TRACY_ON_DEMAND
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2019-08-14 21:05:58 +00:00
# endif
2020-02-23 13:50:50 +00:00
break ;
case QueueType : : ZoneBeginAllocSrcLoc :
case QueueType : : ZoneBeginAllocSrcLocCallstack :
2019-11-25 21:54:10 +00:00
{
2020-02-23 13:50:50 +00:00
int64_t t = MemRead < int64_t > ( & item - > zoneBegin . time ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > zoneBegin . time , dt ) ;
ptr = MemRead < uint64_t > ( & item - > zoneBegin . srcloc ) ;
SendSourceLocationPayload ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
break ;
}
case QueueType : : Callstack :
2020-07-26 12:15:16 +00:00
ptr = MemRead < uint64_t > ( & item - > callstackFat . ptr ) ;
2019-11-25 21:54:10 +00:00
SendCallstackPayload ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
break ;
case QueueType : : CallstackAlloc :
2020-07-26 12:25:32 +00:00
ptr = MemRead < uint64_t > ( & item - > callstackAllocFat . nativePtr ) ;
2020-02-23 13:50:50 +00:00
if ( ptr ! = 0 )
{
CutCallstack ( ( void * ) ptr , " lua_pcall " ) ;
SendCallstackPayload ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
}
2020-07-26 12:25:32 +00:00
ptr = MemRead < uint64_t > ( & item - > callstackAllocFat . ptr ) ;
2020-02-23 13:50:50 +00:00
SendCallstackAlloc ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
break ;
case QueueType : : CallstackSample :
{
2020-07-26 12:28:13 +00:00
ptr = MemRead < uint64_t > ( & item - > callstackSampleFat . ptr ) ;
2020-02-23 13:50:50 +00:00
SendCallstackPayload64 ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-07-26 12:28:13 +00:00
int64_t t = MemRead < int64_t > ( & item - > callstackSampleFat . time ) ;
2020-02-23 13:50:50 +00:00
int64_t dt = t - refCtx ;
refCtx = t ;
2020-07-26 12:28:13 +00:00
MemWrite ( & item - > callstackSampleFat . time , dt ) ;
2020-02-23 13:50:50 +00:00
break ;
}
case QueueType : : FrameImage :
{
2020-07-26 12:18:48 +00:00
ptr = MemRead < uint64_t > ( & item - > frameImageFat . image ) ;
const auto w = MemRead < uint16_t > ( & item - > frameImageFat . w ) ;
const auto h = MemRead < uint16_t > ( & item - > frameImageFat . h ) ;
2020-02-23 13:50:50 +00:00
const auto csz = size_t ( w * h / 2 ) ;
SendLongString ( ptr , ( const char * ) ptr , csz , QueueType : : FrameImageData ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-02-23 13:50:50 +00:00
break ;
}
case QueueType : : ZoneBegin :
case QueueType : : ZoneBeginCallstack :
{
int64_t t = MemRead < int64_t > ( & item - > zoneBegin . time ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > zoneBegin . time , dt ) ;
break ;
}
case QueueType : : ZoneEnd :
{
int64_t t = MemRead < int64_t > ( & item - > zoneEnd . time ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > zoneEnd . time , dt ) ;
break ;
}
case QueueType : : GpuZoneBegin :
case QueueType : : GpuZoneBeginCallstack :
{
int64_t t = MemRead < int64_t > ( & item - > gpuZoneBegin . cpuTime ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > gpuZoneBegin . cpuTime , dt ) ;
break ;
}
2021-01-15 19:13:09 +00:00
case QueueType : : GpuZoneBeginAllocSrcLoc :
case QueueType : : GpuZoneBeginAllocSrcLocCallstack :
{
int64_t t = MemRead < int64_t > ( & item - > gpuZoneBegin . cpuTime ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > gpuZoneBegin . cpuTime , dt ) ;
ptr = MemRead < uint64_t > ( & item - > gpuZoneBegin . srcloc ) ;
SendSourceLocationPayload ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2021-01-15 19:13:09 +00:00
break ;
}
2020-02-23 13:50:50 +00:00
case QueueType : : GpuZoneEnd :
{
int64_t t = MemRead < int64_t > ( & item - > gpuZoneEnd . cpuTime ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > gpuZoneEnd . cpuTime , dt ) ;
break ;
}
2021-01-31 17:46:42 +00:00
case QueueType : : GpuContextName :
ptr = MemRead < uint64_t > ( & item - > gpuContextNameFat . ptr ) ;
2021-02-10 17:56:07 +00:00
size = MemRead < uint16_t > ( & item - > gpuContextNameFat . size ) ;
2021-01-31 17:46:42 +00:00
SendSingleString ( ( const char * ) ptr , size ) ;
# ifndef TRACY_ON_DEMAND
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2021-01-31 17:46:42 +00:00
# endif
break ;
2020-02-23 13:50:50 +00:00
case QueueType : : PlotData :
{
int64_t t = MemRead < int64_t > ( & item - > plotData . time ) ;
int64_t dt = t - refThread ;
refThread = t ;
MemWrite ( & item - > plotData . time , dt ) ;
break ;
}
case QueueType : : ContextSwitch :
{
int64_t t = MemRead < int64_t > ( & item - > contextSwitch . time ) ;
int64_t dt = t - refCtx ;
refCtx = t ;
MemWrite ( & item - > contextSwitch . time , dt ) ;
break ;
}
case QueueType : : ThreadWakeup :
{
int64_t t = MemRead < int64_t > ( & item - > threadWakeup . time ) ;
int64_t dt = t - refCtx ;
refCtx = t ;
MemWrite ( & item - > threadWakeup . time , dt ) ;
break ;
}
case QueueType : : GpuTime :
{
int64_t t = MemRead < int64_t > ( & item - > gpuTime . gpuTime ) ;
int64_t dt = t - refGpu ;
refGpu = t ;
MemWrite ( & item - > gpuTime . gpuTime , dt ) ;
break ;
}
default :
assert ( false ) ;
break ;
2019-11-25 21:54:10 +00:00
}
2019-10-25 17:13:11 +00:00
}
2020-02-23 13:50:50 +00:00
if ( ! AppendData ( item + + , QueueDataSize [ idx ] ) )
2019-10-25 17:52:01 +00:00
{
2020-02-23 13:50:50 +00:00
connectionLost = true ;
m_refTimeThread = refThread ;
m_refTimeCtx = refCtx ;
m_refTimeGpu = refGpu ;
return ;
2019-08-02 18:18:08 +00:00
}
2017-11-11 14:22:55 +00:00
}
2020-02-23 13:50:50 +00:00
m_refTimeThread = refThread ;
m_refTimeCtx = refCtx ;
m_refTimeGpu = refGpu ;
2017-10-18 16:48:51 +00:00
}
2020-02-23 13:50:50 +00:00
) ;
if ( connectionLost ) return DequeueStatus : : ConnectionLost ;
return sz > 0 ? DequeueStatus : : DataDequeued : DequeueStatus : : QueueEmpty ;
2017-09-10 15:43:56 +00:00
}
2019-08-14 21:06:13 +00:00
Profiler : : DequeueStatus Profiler : : DequeueContextSwitches ( tracy : : moodycamel : : ConsumerToken & token , int64_t & timeStop )
{
2020-02-23 13:50:50 +00:00
const auto sz = GetQueue ( ) . try_dequeue_bulk_single ( token , [ ] ( const uint64_t & ) { } ,
[ this , & timeStop ] ( QueueItem * item , size_t sz )
2019-08-14 21:06:13 +00:00
{
2020-02-23 13:50:50 +00:00
assert ( sz > 0 ) ;
int64_t refCtx = m_refTimeCtx ;
while ( sz - - > 0 )
2019-08-14 21:06:13 +00:00
{
2020-02-23 13:50:50 +00:00
FreeAssociatedMemory ( * item ) ;
if ( timeStop < 0 ) return ;
const auto idx = MemRead < uint8_t > ( & item - > hdr . idx ) ;
if ( idx = = ( uint8_t ) QueueType : : ContextSwitch )
2019-08-14 21:06:13 +00:00
{
2020-02-23 13:50:50 +00:00
const auto csTime = MemRead < int64_t > ( & item - > contextSwitch . time ) ;
if ( csTime > timeStop )
{
timeStop = - 1 ;
m_refTimeCtx = refCtx ;
return ;
}
int64_t dt = csTime - refCtx ;
refCtx = csTime ;
MemWrite ( & item - > contextSwitch . time , dt ) ;
if ( ! AppendData ( item , QueueDataSize [ ( int ) QueueType : : ContextSwitch ] ) )
{
timeStop = - 2 ;
m_refTimeCtx = refCtx ;
return ;
}
2019-08-14 21:06:13 +00:00
}
2020-02-23 13:50:50 +00:00
else if ( idx = = ( uint8_t ) QueueType : : ThreadWakeup )
2019-10-25 16:22:42 +00:00
{
2020-02-23 13:50:50 +00:00
const auto csTime = MemRead < int64_t > ( & item - > threadWakeup . time ) ;
if ( csTime > timeStop )
{
timeStop = - 1 ;
m_refTimeCtx = refCtx ;
return ;
}
int64_t dt = csTime - refCtx ;
refCtx = csTime ;
MemWrite ( & item - > threadWakeup . time , dt ) ;
if ( ! AppendData ( item , QueueDataSize [ ( int ) QueueType : : ThreadWakeup ] ) )
{
timeStop = - 2 ;
m_refTimeCtx = refCtx ;
return ;
}
2019-10-25 16:22:42 +00:00
}
2020-02-23 13:50:50 +00:00
item + + ;
2019-08-14 21:06:13 +00:00
}
2020-02-23 13:50:50 +00:00
m_refTimeCtx = refCtx ;
2019-08-14 21:06:13 +00:00
}
2020-02-23 13:50:50 +00:00
) ;
if ( timeStop = = - 2 ) return DequeueStatus : : ConnectionLost ;
return ( timeStop = = - 1 | | sz > 0 ) ? DequeueStatus : : DataDequeued : DequeueStatus : : QueueEmpty ;
2019-08-14 21:06:13 +00:00
}
2018-04-01 18:04:35 +00:00
Profiler : : DequeueStatus Profiler : : DequeueSerial ( )
{
2018-04-14 13:46:11 +00:00
{
2018-08-20 19:49:23 +00:00
bool lockHeld = true ;
while ( ! m_serialLock . try_lock ( ) )
{
if ( m_shutdownManual . load ( std : : memory_order_relaxed ) )
{
lockHeld = false ;
break ;
}
}
2019-06-27 11:37:09 +00:00
if ( ! m_serialQueue . empty ( ) ) m_serialQueue . swap ( m_serialDequeue ) ;
2018-08-20 19:49:23 +00:00
if ( lockHeld )
{
m_serialLock . unlock ( ) ;
}
2018-04-14 13:46:11 +00:00
}
const auto sz = m_serialDequeue . size ( ) ;
2018-04-01 18:04:35 +00:00
if ( sz > 0 )
{
2021-06-09 23:48:11 +00:00
InitRpmalloc ( ) ;
2020-02-22 15:54:02 +00:00
int64_t refSerial = m_refTimeSerial ;
int64_t refGpu = m_refTimeGpu ;
2018-04-14 13:46:11 +00:00
auto item = m_serialDequeue . data ( ) ;
2018-04-01 18:04:35 +00:00
auto end = item + sz ;
while ( item ! = end )
{
2018-06-19 17:09:57 +00:00
uint64_t ptr ;
2020-05-10 17:28:08 +00:00
auto idx = MemRead < uint8_t > ( & item - > hdr . idx ) ;
2018-06-19 17:09:57 +00:00
if ( idx < ( int ) QueueType : : Terminate )
{
switch ( ( QueueType ) idx )
{
2021-01-15 19:49:39 +00:00
case QueueType : : CallstackSerial :
2020-07-26 12:15:16 +00:00
ptr = MemRead < uint64_t > ( & item - > callstackFat . ptr ) ;
2018-06-19 17:09:57 +00:00
SendCallstackPayload ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2018-06-19 17:09:57 +00:00
break ;
2019-10-23 22:04:31 +00:00
case QueueType : : LockWait :
case QueueType : : LockSharedWait :
{
int64_t t = MemRead < int64_t > ( & item - > lockWait . time ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > lockWait . time , dt ) ;
break ;
}
case QueueType : : LockObtain :
case QueueType : : LockSharedObtain :
{
int64_t t = MemRead < int64_t > ( & item - > lockObtain . time ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > lockObtain . time , dt ) ;
break ;
}
case QueueType : : LockRelease :
case QueueType : : LockSharedRelease :
{
int64_t t = MemRead < int64_t > ( & item - > lockRelease . time ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > lockRelease . time , dt ) ;
break ;
}
2020-07-26 11:45:53 +00:00
case QueueType : : LockName :
{
ptr = MemRead < uint64_t > ( & item - > lockNameFat . name ) ;
uint16_t size = MemRead < uint16_t > ( & item - > lockNameFat . size ) ;
SendSingleString ( ( const char * ) ptr , size ) ;
# ifndef TRACY_ON_DEMAND
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2020-07-26 11:45:53 +00:00
# endif
break ;
}
2019-10-23 22:04:31 +00:00
case QueueType : : MemAlloc :
2020-09-22 16:22:34 +00:00
case QueueType : : MemAllocNamed :
2019-10-23 22:04:31 +00:00
case QueueType : : MemAllocCallstack :
2020-09-22 16:22:34 +00:00
case QueueType : : MemAllocCallstackNamed :
2019-10-23 22:04:31 +00:00
{
int64_t t = MemRead < int64_t > ( & item - > memAlloc . time ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > memAlloc . time , dt ) ;
break ;
}
case QueueType : : MemFree :
2020-09-22 16:22:34 +00:00
case QueueType : : MemFreeNamed :
2019-10-23 22:04:31 +00:00
case QueueType : : MemFreeCallstack :
2020-09-22 16:22:34 +00:00
case QueueType : : MemFreeCallstackNamed :
2019-10-23 22:04:31 +00:00
{
int64_t t = MemRead < int64_t > ( & item - > memFree . time ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > memFree . time , dt ) ;
break ;
}
case QueueType : : GpuZoneBeginSerial :
case QueueType : : GpuZoneBeginCallstackSerial :
{
int64_t t = MemRead < int64_t > ( & item - > gpuZoneBegin . cpuTime ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > gpuZoneBegin . cpuTime , dt ) ;
break ;
}
2021-01-15 19:13:09 +00:00
case QueueType : : GpuZoneBeginAllocSrcLocSerial :
case QueueType : : GpuZoneBeginAllocSrcLocCallstackSerial :
{
int64_t t = MemRead < int64_t > ( & item - > gpuZoneBegin . cpuTime ) ;
int64_t dt = t - refSerial ;
refSerial = t ;
MemWrite ( & item - > gpuZoneBegin . cpuTime , dt ) ;
ptr = MemRead < uint64_t > ( & item - > gpuZoneBegin . srcloc ) ;
SendSourceLocationPayload ( ptr ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2021-01-15 19:13:09 +00:00
break ;
}
2019-10-23 22:04:31 +00:00
case QueueType : : GpuZoneEndSerial :
{
int64_t t = MemRead < int64_t > ( & item - > gpuZoneEnd . cpuTime ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refSerial ;
refSerial = t ;
2019-10-23 22:04:31 +00:00
MemWrite ( & item - > gpuZoneEnd . cpuTime , dt ) ;
break ;
}
2019-10-25 17:52:01 +00:00
case QueueType : : GpuTime :
{
int64_t t = MemRead < int64_t > ( & item - > gpuTime . gpuTime ) ;
2020-02-22 15:54:02 +00:00
int64_t dt = t - refGpu ;
refGpu = t ;
2019-10-25 17:52:01 +00:00
MemWrite ( & item - > gpuTime . gpuTime , dt ) ;
break ;
}
2021-01-31 17:46:42 +00:00
case QueueType : : GpuContextName :
{
ptr = MemRead < uint64_t > ( & item - > gpuContextNameFat . ptr ) ;
uint16_t size = MemRead < uint16_t > ( & item - > gpuContextNameFat . size ) ;
SendSingleString ( ( const char * ) ptr , size ) ;
# ifndef TRACY_ON_DEMAND
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) ptr ) ;
2021-01-31 17:46:42 +00:00
# endif
break ;
}
2018-06-19 17:09:57 +00:00
default :
assert ( false ) ;
break ;
}
}
2019-06-09 14:14:30 +00:00
if ( ! AppendData ( item , QueueDataSize [ idx ] ) ) return DequeueStatus : : ConnectionLost ;
2018-04-01 18:04:35 +00:00
item + + ;
}
2020-02-22 15:54:02 +00:00
m_refTimeSerial = refSerial ;
m_refTimeGpu = refGpu ;
2018-04-14 13:46:11 +00:00
m_serialDequeue . clear ( ) ;
2018-04-01 18:04:35 +00:00
}
else
{
2019-06-09 14:14:30 +00:00
return DequeueStatus : : QueueEmpty ;
2018-04-01 18:04:35 +00:00
}
2019-11-14 17:24:29 +00:00
return DequeueStatus : : DataDequeued ;
2018-04-01 18:04:35 +00:00
}
2017-11-11 13:16:37 +00:00
bool Profiler : : CommitData ( )
{
bool ret = SendData ( m_buffer + m_bufferStart , m_bufferOffset - m_bufferStart ) ;
if ( m_bufferOffset > TargetFrameSize * 2 ) m_bufferOffset = 0 ;
m_bufferStart = m_bufferOffset ;
return ret ;
}
2017-09-14 17:07:56 +00:00
bool Profiler : : SendData ( const char * data , size_t len )
{
2019-05-01 10:57:42 +00:00
const lz4sz_t lz4sz = LZ4_compress_fast_continue ( ( LZ4_stream_t * ) m_stream , data , m_lz4Buf + sizeof ( lz4sz_t ) , ( int ) len , LZ4Size , 1 ) ;
2017-11-02 16:37:10 +00:00
memcpy ( m_lz4Buf , & lz4sz , sizeof ( lz4sz ) ) ;
2017-11-10 16:34:11 +00:00
return m_sock - > Send ( m_lz4Buf , lz4sz + sizeof ( lz4sz_t ) ) ! = - 1 ;
2017-09-14 17:07:56 +00:00
}
2020-07-21 00:19:22 +00:00
void Profiler : : SendString ( uint64_t str , const char * ptr , size_t len , QueueType type )
2017-09-14 17:24:35 +00:00
{
2019-08-16 17:49:16 +00:00
assert ( type = = QueueType : : StringData | |
type = = QueueType : : ThreadName | |
type = = QueueType : : PlotName | |
type = = QueueType : : FrameName | |
type = = QueueType : : ExternalName | |
type = = QueueType : : ExternalThreadName ) ;
2017-09-14 17:24:35 +00:00
2017-10-03 14:41:32 +00:00
QueueItem item ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item . hdr . type , type ) ;
MemWrite ( & item . stringTransfer . ptr , str ) ;
2017-09-14 17:24:35 +00:00
assert ( len < = std : : numeric_limits < uint16_t > : : max ( ) ) ;
2017-10-16 18:42:53 +00:00
auto l16 = uint16_t ( len ) ;
2017-11-11 14:08:03 +00:00
2018-03-31 12:03:55 +00:00
NeedDataSize ( QueueDataSize [ ( int ) type ] + sizeof ( l16 ) + l16 ) ;
2017-11-11 14:08:03 +00:00
2018-06-23 00:19:23 +00:00
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) type ] ) ;
AppendDataUnsafe ( & l16 , sizeof ( l16 ) ) ;
AppendDataUnsafe ( ptr , l16 ) ;
2017-09-14 17:24:35 +00:00
}
2020-07-25 21:13:01 +00:00
void Profiler : : SendSingleString ( const char * ptr , size_t len )
{
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : SingleStringData ) ;
assert ( len < = std : : numeric_limits < uint16_t > : : max ( ) ) ;
auto l16 = uint16_t ( len ) ;
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : SingleStringData ] + sizeof ( l16 ) + l16 ) ;
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : SingleStringData ] ) ;
AppendDataUnsafe ( & l16 , sizeof ( l16 ) ) ;
AppendDataUnsafe ( ptr , l16 ) ;
}
2020-07-25 23:32:49 +00:00
void Profiler : : SendSecondString ( const char * ptr , size_t len )
{
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : SecondStringData ) ;
assert ( len < = std : : numeric_limits < uint16_t > : : max ( ) ) ;
auto l16 = uint16_t ( len ) ;
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : SecondStringData ] + sizeof ( l16 ) + l16 ) ;
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : SecondStringData ] ) ;
AppendDataUnsafe ( & l16 , sizeof ( l16 ) ) ;
AppendDataUnsafe ( ptr , l16 ) ;
}
2019-06-06 22:22:00 +00:00
void Profiler : : SendLongString ( uint64_t str , const char * ptr , size_t len , QueueType type )
2019-06-06 19:39:54 +00:00
{
2020-03-25 19:04:55 +00:00
assert ( type = = QueueType : : FrameImageData | |
2021-02-03 23:03:25 +00:00
type = = QueueType : : SymbolCode | |
type = = QueueType : : SourceCode ) ;
2019-06-06 19:39:54 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , type ) ;
MemWrite ( & item . stringTransfer . ptr , str ) ;
assert ( len < = std : : numeric_limits < uint32_t > : : max ( ) ) ;
assert ( QueueDataSize [ ( int ) type ] + sizeof ( uint32_t ) + len < = TargetFrameSize ) ;
auto l32 = uint32_t ( len ) ;
NeedDataSize ( QueueDataSize [ ( int ) type ] + sizeof ( l32 ) + l32 ) ;
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) type ] ) ;
AppendDataUnsafe ( & l32 , sizeof ( l32 ) ) ;
AppendDataUnsafe ( ptr , l32 ) ;
}
2017-09-26 17:00:25 +00:00
void Profiler : : SendSourceLocation ( uint64_t ptr )
2017-09-26 00:28:14 +00:00
{
2018-07-27 22:34:04 +00:00
auto srcloc = ( const SourceLocationData * ) ptr ;
2017-09-26 00:28:14 +00:00
QueueItem item ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item . hdr . type , QueueType : : SourceLocation ) ;
MemWrite ( & item . srcloc . name , ( uint64_t ) srcloc - > name ) ;
MemWrite ( & item . srcloc . file , ( uint64_t ) srcloc - > file ) ;
MemWrite ( & item . srcloc . function , ( uint64_t ) srcloc - > function ) ;
MemWrite ( & item . srcloc . line , srcloc - > line ) ;
MemWrite ( & item . srcloc . r , uint8_t ( ( srcloc - > color ) & 0xFF ) ) ;
MemWrite ( & item . srcloc . g , uint8_t ( ( srcloc - > color > > 8 ) & 0xFF ) ) ;
MemWrite ( & item . srcloc . b , uint8_t ( ( srcloc - > color > > 16 ) & 0xFF ) ) ;
AppendData ( & item , QueueDataSize [ ( int ) QueueType : : SourceLocation ] ) ;
2017-09-26 00:28:14 +00:00
}
2018-06-19 17:00:57 +00:00
void Profiler : : SendSourceLocationPayload ( uint64_t _ptr )
2017-11-05 15:46:00 +00:00
{
auto ptr = ( const char * ) _ptr ;
QueueItem item ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item . hdr . type , QueueType : : SourceLocationPayload ) ;
MemWrite ( & item . stringTransfer . ptr , _ptr ) ;
2017-11-05 15:46:00 +00:00
2020-07-05 15:11:15 +00:00
uint16_t len ;
memcpy ( & len , ptr , sizeof ( len ) ) ;
assert ( len > 2 ) ;
len - = 2 ;
ptr + = 2 ;
2017-11-11 14:08:03 +00:00
2020-07-05 15:11:15 +00:00
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : SourceLocationPayload ] + sizeof ( len ) + len ) ;
2017-11-11 14:08:03 +00:00
2018-06-23 00:19:23 +00:00
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : SourceLocationPayload ] ) ;
2020-07-05 15:11:15 +00:00
AppendDataUnsafe ( & len , sizeof ( len ) ) ;
AppendDataUnsafe ( ptr , len ) ;
2017-11-05 15:46:00 +00:00
}
2018-06-19 17:09:43 +00:00
void Profiler : : SendCallstackPayload ( uint64_t _ptr )
{
auto ptr = ( uintptr_t * ) _ptr ;
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : CallstackPayload ) ;
MemWrite ( & item . stringTransfer . ptr , _ptr ) ;
const auto sz = * ptr + + ;
const auto len = sz * sizeof ( uint64_t ) ;
const auto l16 = uint16_t ( len ) ;
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : CallstackPayload ] + sizeof ( l16 ) + l16 ) ;
2018-06-23 00:19:23 +00:00
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : CallstackPayload ] ) ;
AppendDataUnsafe ( & l16 , sizeof ( l16 ) ) ;
2018-06-19 17:09:43 +00:00
2018-08-01 12:07:30 +00:00
if ( compile_time_condition < sizeof ( uintptr_t ) = = sizeof ( uint64_t ) > : : value )
2018-06-19 17:09:43 +00:00
{
2018-06-23 00:19:23 +00:00
AppendDataUnsafe ( ptr , sizeof ( uint64_t ) * sz ) ;
2018-06-23 00:13:52 +00:00
}
else
{
for ( uintptr_t i = 0 ; i < sz ; i + + )
{
const auto val = uint64_t ( * ptr + + ) ;
2018-06-23 00:19:23 +00:00
AppendDataUnsafe ( & val , sizeof ( uint64_t ) ) ;
2018-06-23 00:13:52 +00:00
}
2018-06-19 17:09:43 +00:00
}
}
2020-02-22 13:05:01 +00:00
void Profiler : : SendCallstackPayload64 ( uint64_t _ptr )
{
auto ptr = ( uint64_t * ) _ptr ;
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : CallstackPayload ) ;
MemWrite ( & item . stringTransfer . ptr , _ptr ) ;
const auto sz = * ptr + + ;
const auto len = sz * sizeof ( uint64_t ) ;
const auto l16 = uint16_t ( len ) ;
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : CallstackPayload ] + sizeof ( l16 ) + l16 ) ;
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : CallstackPayload ] ) ;
AppendDataUnsafe ( & l16 , sizeof ( l16 ) ) ;
AppendDataUnsafe ( ptr , sizeof ( uint64_t ) * sz ) ;
}
2019-02-28 19:30:07 +00:00
void Profiler : : SendCallstackAlloc ( uint64_t _ptr )
{
auto ptr = ( const char * ) _ptr ;
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : CallstackAllocPayload ) ;
MemWrite ( & item . stringTransfer . ptr , _ptr ) ;
2020-07-05 15:33:29 +00:00
uint16_t len ;
memcpy ( & len , ptr , 2 ) ;
ptr + = 2 ;
2019-02-28 19:30:07 +00:00
2020-07-05 15:33:29 +00:00
NeedDataSize ( QueueDataSize [ ( int ) QueueType : : CallstackAllocPayload ] + sizeof ( len ) + len ) ;
2019-02-28 19:30:07 +00:00
AppendDataUnsafe ( & item , QueueDataSize [ ( int ) QueueType : : CallstackAllocPayload ] ) ;
2020-07-05 15:33:29 +00:00
AppendDataUnsafe ( & len , sizeof ( len ) ) ;
AppendDataUnsafe ( ptr , len ) ;
2019-02-28 19:30:07 +00:00
}
2018-06-19 23:06:31 +00:00
void Profiler : : SendCallstackFrame ( uint64_t ptr )
{
# ifdef TRACY_HAS_CALLSTACK
2019-01-20 18:11:48 +00:00
const auto frameData = DecodeCallstackPtr ( ptr ) ;
2018-06-19 23:06:31 +00:00
2019-01-20 18:11:48 +00:00
{
2020-07-25 22:38:59 +00:00
SendSingleString ( frameData . imageName ) ;
2020-02-25 23:33:09 +00:00
2019-01-20 18:11:48 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : CallstackFrameSize ) ;
MemWrite ( & item . callstackFrameSize . ptr , ptr ) ;
MemWrite ( & item . callstackFrameSize . size , frameData . size ) ;
2018-06-19 23:06:31 +00:00
2019-01-20 18:11:48 +00:00
AppendData ( & item , QueueDataSize [ ( int ) QueueType : : CallstackFrameSize ] ) ;
}
2021-06-09 23:48:11 +00:00
InitRpmalloc ( ) ;
2019-01-20 18:11:48 +00:00
for ( uint8_t i = 0 ; i < frameData . size ; i + + )
{
const auto & frame = frameData . data [ i ] ;
2020-07-25 22:41:49 +00:00
SendSingleString ( frame . name ) ;
2020-07-25 23:32:49 +00:00
SendSecondString ( frame . file ) ;
2019-01-20 18:11:48 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : CallstackFrame ) ;
MemWrite ( & item . callstackFrame . line , frame . line ) ;
2020-02-25 22:03:40 +00:00
MemWrite ( & item . callstackFrame . symAddr , frame . symAddr ) ;
2020-07-25 22:43:24 +00:00
MemWrite ( & item . callstackFrame . symLen , frame . symLen ) ;
2018-06-19 23:06:31 +00:00
2019-01-20 18:11:48 +00:00
AppendData ( & item , QueueDataSize [ ( int ) QueueType : : CallstackFrame ] ) ;
2018-06-19 23:06:31 +00:00
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ( void * ) frame . name ) ;
tracy_free_fast ( ( void * ) frame . file ) ;
2019-01-20 18:11:48 +00:00
}
2018-06-19 23:06:31 +00:00
# endif
}
2018-06-19 17:09:43 +00:00
2017-09-21 23:54:04 +00:00
bool Profiler : : HandleServerQuery ( )
{
2020-04-13 12:26:59 +00:00
ServerQueryPacket payload ;
if ( ! m_sock - > Read ( & payload , sizeof ( payload ) , 10 ) ) return false ;
2017-09-21 23:54:04 +00:00
uint8_t type ;
uint64_t ptr ;
2020-03-25 19:04:01 +00:00
uint32_t extra ;
2020-04-13 12:26:59 +00:00
memcpy ( & type , & payload . type , sizeof ( payload . type ) ) ;
memcpy ( & ptr , & payload . ptr , sizeof ( payload . ptr ) ) ;
memcpy ( & extra , & payload . extra , sizeof ( payload . extra ) ) ;
2017-09-21 23:54:04 +00:00
switch ( type )
{
case ServerQueryString :
SendString ( ptr , ( const char * ) ptr , QueueType : : StringData ) ;
break ;
2017-09-21 23:55:02 +00:00
case ServerQueryThreadString :
2017-09-22 23:38:26 +00:00
if ( ptr = = m_mainThread )
{
2020-07-21 15:21:09 +00:00
SendString ( ptr , " Main thread " , 11 , QueueType : : ThreadName ) ;
2017-09-22 23:38:26 +00:00
}
else
{
SendString ( ptr , GetThreadName ( ptr ) , QueueType : : ThreadName ) ;
}
2017-09-21 23:55:02 +00:00
break ;
2017-09-26 00:28:14 +00:00
case ServerQuerySourceLocation :
SendSourceLocation ( ptr ) ;
break ;
2017-10-13 01:36:59 +00:00
case ServerQueryPlotName :
SendString ( ptr , ( const char * ) ptr , QueueType : : PlotName ) ;
break ;
2017-10-18 16:48:51 +00:00
case ServerQueryTerminate :
return false ;
2018-06-19 23:06:31 +00:00
case ServerQueryCallstackFrame :
SendCallstackFrame ( ptr ) ;
break ;
2018-08-04 18:48:21 +00:00
case ServerQueryFrameName :
SendString ( ptr , ( const char * ) ptr , QueueType : : FrameName ) ;
break ;
2019-08-01 21:14:09 +00:00
case ServerQueryDisconnect :
HandleDisconnect ( ) ;
return false ;
2019-08-26 16:02:10 +00:00
# ifdef TRACY_HAS_SYSTEM_TRACING
2019-08-16 17:22:23 +00:00
case ServerQueryExternalName :
SysTraceSendExternalName ( ptr ) ;
break ;
2019-08-26 16:02:10 +00:00
# endif
2019-11-25 22:59:48 +00:00
case ServerQueryParameter :
HandleParameter ( ptr ) ;
break ;
2020-02-26 21:35:15 +00:00
case ServerQuerySymbol :
HandleSymbolQuery ( ptr ) ;
break ;
2020-08-15 23:31:54 +00:00
# ifndef TRACY_NO_CODE_TRANSFER
2020-03-25 19:04:55 +00:00
case ServerQuerySymbolCode :
HandleSymbolCodeQuery ( ptr , extra ) ;
break ;
2020-08-15 23:31:54 +00:00
# endif
2020-04-01 19:43:03 +00:00
case ServerQueryCodeLocation :
SendCodeLocation ( ptr ) ;
break ;
2021-02-03 23:03:25 +00:00
case ServerQuerySourceCode :
HandleSourceCodeQuery ( ) ;
break ;
case ServerQueryDataTransfer :
assert ( ! m_queryData ) ;
m_queryDataPtr = m_queryData = ( char * ) tracy_malloc ( ptr + 11 ) ;
AckServerQuery ( ) ;
break ;
case ServerQueryDataTransferPart :
memcpy ( m_queryDataPtr , & ptr , 8 ) ;
memcpy ( m_queryDataPtr + 8 , & extra , 4 ) ;
m_queryDataPtr + = 12 ;
AckServerQuery ( ) ;
break ;
2017-09-21 23:54:04 +00:00
default :
assert ( false ) ;
break ;
}
return true ;
}
2019-08-01 21:14:09 +00:00
void Profiler : : HandleDisconnect ( )
{
2019-08-14 21:06:13 +00:00
moodycamel : : ConsumerToken token ( GetQueue ( ) ) ;
2019-08-26 16:02:10 +00:00
# ifdef TRACY_HAS_SYSTEM_TRACING
2019-08-14 21:06:13 +00:00
if ( s_sysTraceThread )
{
auto timestamp = GetTime ( ) ;
for ( ; ; )
{
const auto status = DequeueContextSwitches ( token , timestamp ) ;
if ( status = = DequeueStatus : : ConnectionLost )
{
return ;
}
else if ( status = = DequeueStatus : : QueueEmpty )
{
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) return ;
}
}
if ( timestamp < 0 )
{
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) return ;
}
break ;
}
ClearSerial ( ) ;
if ( m_sock - > HasData ( ) )
{
while ( m_sock - > HasData ( ) )
{
if ( ! HandleServerQuery ( ) ) return ;
}
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) return ;
}
}
else
{
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) return ;
}
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
}
}
}
2019-08-26 16:02:10 +00:00
# endif
2019-08-14 21:06:13 +00:00
2019-08-01 21:14:09 +00:00
QueueItem terminate ;
MemWrite ( & terminate . hdr . type , QueueType : : Terminate ) ;
if ( ! SendData ( ( const char * ) & terminate , 1 ) ) return ;
for ( ; ; )
{
2019-08-14 21:06:13 +00:00
ClearQueues ( token ) ;
2019-08-01 21:14:09 +00:00
if ( m_sock - > HasData ( ) )
{
while ( m_sock - > HasData ( ) )
{
if ( ! HandleServerQuery ( ) ) return ;
}
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) return ;
}
}
else
{
if ( m_bufferOffset ! = m_bufferStart )
{
if ( ! CommitData ( ) ) return ;
}
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
}
}
}
2017-09-23 19:33:05 +00:00
void Profiler : : CalibrateTimer ( )
{
2018-04-26 13:25:54 +00:00
# ifdef TRACY_HW_TIMER
2017-09-23 19:33:05 +00:00
std : : atomic_signal_fence ( std : : memory_order_acq_rel ) ;
const auto t0 = std : : chrono : : high_resolution_clock : : now ( ) ;
2018-04-26 13:29:09 +00:00
const auto r0 = GetTime ( ) ;
2017-09-23 19:33:05 +00:00
std : : atomic_signal_fence ( std : : memory_order_acq_rel ) ;
2017-11-25 12:34:26 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 200 ) ) ;
2017-09-23 19:33:05 +00:00
std : : atomic_signal_fence ( std : : memory_order_acq_rel ) ;
const auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
2018-04-26 13:29:09 +00:00
const auto r1 = GetTime ( ) ;
2017-09-23 19:33:05 +00:00
std : : atomic_signal_fence ( std : : memory_order_acq_rel ) ;
const auto dt = std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( t1 - t0 ) . count ( ) ;
const auto dr = r1 - r0 ;
m_timerMul = double ( dt ) / double ( dr ) ;
2017-09-25 22:13:24 +00:00
# else
m_timerMul = 1. ;
2017-09-23 19:33:05 +00:00
# endif
}
2017-09-24 14:02:09 +00:00
void Profiler : : CalibrateDelay ( )
{
2020-07-30 22:58:59 +00:00
constexpr int Iterations = 50000 ;
2019-06-19 15:29:04 +00:00
auto mindiff = std : : numeric_limits < int64_t > : : max ( ) ;
for ( int i = 0 ; i < Iterations * 10 ; i + + )
{
const auto t0i = GetTime ( ) ;
const auto t1i = GetTime ( ) ;
const auto dti = t1i - t0i ;
if ( dti > 0 & & dti < mindiff ) mindiff = dti ;
}
m_resolution = mindiff ;
# ifdef TRACY_DELAYED_INIT
m_delay = m_resolution ;
# else
2020-07-30 22:58:59 +00:00
constexpr int Events = Iterations * 2 ; // start + end
2019-10-20 20:13:29 +00:00
static_assert ( Events < QueuePrealloc , " Delay calibration loop will allocate memory in queue " ) ;
2017-09-26 23:03:29 +00:00
2019-10-20 20:18:05 +00:00
static const tracy : : SourceLocationData __tracy_source_location { nullptr , __FUNCTION__ , __FILE__ , ( uint32_t ) __LINE__ , 0 } ;
2017-10-29 15:12:16 +00:00
const auto t0 = GetTime ( ) ;
2017-09-24 14:02:09 +00:00
for ( int i = 0 ; i < Iterations ; i + + )
{
2017-10-01 15:49:45 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : ZoneBegin ) ;
2019-08-12 17:18:17 +00:00
MemWrite ( & item - > zoneBegin . time , Profiler : : GetTime ( ) ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > zoneBegin . srcloc , ( uint64_t ) & __tracy_source_location ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2017-10-01 15:49:45 +00:00
}
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : ZoneEnd ) ;
2019-08-12 17:18:17 +00:00
MemWrite ( & item - > zoneEnd . time , GetTime ( ) ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2017-10-01 15:49:45 +00:00
}
2017-09-24 14:02:09 +00:00
}
2017-10-29 15:12:16 +00:00
const auto t1 = GetTime ( ) ;
2017-09-24 14:02:09 +00:00
const auto dt = t1 - t0 ;
2019-10-20 20:13:29 +00:00
m_delay = dt / Events ;
2017-09-24 14:02:09 +00:00
2019-02-19 18:33:37 +00:00
moodycamel : : ConsumerToken token ( GetQueue ( ) ) ;
2019-10-20 20:13:29 +00:00
int left = Events ;
2017-09-24 14:02:09 +00:00
while ( left ! = 0 )
{
2020-05-13 16:15:12 +00:00
const auto sz = GetQueue ( ) . try_dequeue_bulk_single ( token , [ ] ( const uint64_t & ) { } , [ ] ( QueueItem * item , size_t sz ) { } ) ;
2017-09-24 14:02:09 +00:00
assert ( sz > 0 ) ;
2017-10-16 18:42:53 +00:00
left - = ( int ) sz ;
2017-09-24 14:02:09 +00:00
}
2019-10-20 20:13:29 +00:00
assert ( GetQueue ( ) . size_approx ( ) = = 0 ) ;
2019-06-19 15:29:04 +00:00
# endif
2017-09-24 14:02:09 +00:00
}
2019-11-29 17:29:09 +00:00
void Profiler : : ReportTopology ( )
{
2020-01-02 21:39:05 +00:00
# ifndef TRACY_DELAYED_INIT
2019-11-29 21:41:41 +00:00
struct CpuData
{
uint32_t package ;
uint32_t core ;
uint32_t thread ;
} ;
2019-11-29 17:29:09 +00:00
# if defined _WIN32 || defined __CYGWIN__
2020-04-23 22:55:57 +00:00
t_GetLogicalProcessorInformationEx _GetLogicalProcessorInformationEx = ( t_GetLogicalProcessorInformationEx ) GetProcAddress ( GetModuleHandleA ( " kernel32.dll " ) , " GetLogicalProcessorInformationEx " ) ;
2019-11-29 17:29:09 +00:00
if ( ! _GetLogicalProcessorInformationEx ) return ;
DWORD psz = 0 ;
_GetLogicalProcessorInformationEx ( RelationProcessorPackage , nullptr , & psz ) ;
auto packageInfo = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * ) tracy_malloc ( psz ) ;
auto res = _GetLogicalProcessorInformationEx ( RelationProcessorPackage , packageInfo , & psz ) ;
assert ( res ) ;
DWORD csz = 0 ;
_GetLogicalProcessorInformationEx ( RelationProcessorCore , nullptr , & csz ) ;
auto coreInfo = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * ) tracy_malloc ( csz ) ;
res = _GetLogicalProcessorInformationEx ( RelationProcessorCore , coreInfo , & csz ) ;
assert ( res ) ;
SYSTEM_INFO sysinfo ;
GetSystemInfo ( & sysinfo ) ;
const uint32_t numcpus = sysinfo . dwNumberOfProcessors ;
auto cpuData = ( CpuData * ) tracy_malloc ( sizeof ( CpuData ) * numcpus ) ;
for ( uint32_t i = 0 ; i < numcpus ; i + + ) cpuData [ i ] . thread = i ;
int idx = 0 ;
auto ptr = packageInfo ;
while ( ( char * ) ptr < ( ( char * ) packageInfo ) + psz )
{
assert ( ptr - > Relationship = = RelationProcessorPackage ) ;
// FIXME account for GroupCount
auto mask = ptr - > Processor . GroupMask [ 0 ] . Mask ;
int core = 0 ;
while ( mask ! = 0 )
{
if ( mask & 1 ) cpuData [ core ] . package = idx ;
core + + ;
mask > > = 1 ;
}
ptr = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * ) ( ( ( char * ) ptr ) + ptr - > Size ) ;
idx + + ;
}
idx = 0 ;
ptr = coreInfo ;
while ( ( char * ) ptr < ( ( char * ) coreInfo ) + csz )
{
assert ( ptr - > Relationship = = RelationProcessorCore ) ;
// FIXME account for GroupCount
auto mask = ptr - > Processor . GroupMask [ 0 ] . Mask ;
int core = 0 ;
while ( mask ! = 0 )
{
if ( mask & 1 ) cpuData [ core ] . core = idx ;
core + + ;
mask > > = 1 ;
}
ptr = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * ) ( ( ( char * ) ptr ) + ptr - > Size ) ;
idx + + ;
}
2019-11-29 21:41:41 +00:00
for ( uint32_t i = 0 ; i < numcpus ; i + + )
{
auto & data = cpuData [ i ] ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : CpuTopology ) ;
2019-11-29 21:41:41 +00:00
MemWrite ( & item - > cpuTopology . package , data . package ) ;
MemWrite ( & item - > cpuTopology . core , data . core ) ;
MemWrite ( & item - > cpuTopology . thread , data . thread ) ;
# ifdef TRACY_ON_DEMAND
DeferItem ( * item ) ;
# endif
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-29 21:41:41 +00:00
}
2019-11-29 17:29:09 +00:00
tracy_free ( cpuData ) ;
tracy_free ( coreInfo ) ;
tracy_free ( packageInfo ) ;
2019-11-30 00:51:29 +00:00
# elif defined __linux__
const int numcpus = std : : thread : : hardware_concurrency ( ) ;
auto cpuData = ( CpuData * ) tracy_malloc ( sizeof ( CpuData ) * numcpus ) ;
memset ( cpuData , 0 , sizeof ( CpuData ) * numcpus ) ;
const char * basePath = " /sys/devices/system/cpu/cpu " ;
for ( int i = 0 ; i < numcpus ; i + + )
{
char path [ 1024 ] ;
sprintf ( path , " %s%i/topology/physical_package_id " , basePath , i ) ;
char buf [ 1024 ] ;
FILE * f = fopen ( path , " rb " ) ;
2020-06-23 23:14:55 +00:00
if ( ! f )
{
tracy_free ( cpuData ) ;
2020-06-21 15:46:53 +00:00
return ;
}
2019-11-30 00:51:29 +00:00
auto read = fread ( buf , 1 , 1024 , f ) ;
buf [ read ] = ' \0 ' ;
fclose ( f ) ;
cpuData [ i ] . package = uint32_t ( atoi ( buf ) ) ;
cpuData [ i ] . thread = i ;
sprintf ( path , " %s%i/topology/core_id " , basePath , i ) ;
f = fopen ( path , " rb " ) ;
read = fread ( buf , 1 , 1024 , f ) ;
buf [ read ] = ' \0 ' ;
fclose ( f ) ;
cpuData [ i ] . core = uint32_t ( atoi ( buf ) ) ;
}
2020-03-01 00:48:20 +00:00
for ( int i = 0 ; i < numcpus ; i + + )
2019-11-30 00:51:29 +00:00
{
auto & data = cpuData [ i ] ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : CpuTopology ) ;
2019-11-30 00:51:29 +00:00
MemWrite ( & item - > cpuTopology . package , data . package ) ;
MemWrite ( & item - > cpuTopology . core , data . core ) ;
MemWrite ( & item - > cpuTopology . thread , data . thread ) ;
# ifdef TRACY_ON_DEMAND
DeferItem ( * item ) ;
# endif
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-30 00:51:29 +00:00
}
tracy_free ( cpuData ) ;
2019-11-29 17:29:09 +00:00
# endif
2020-01-02 21:39:05 +00:00
# endif
2019-11-29 17:29:09 +00:00
}
2019-07-29 22:42:31 +00:00
void Profiler : : SendCallstack ( int depth , const char * skipBefore )
2018-08-20 20:20:44 +00:00
{
# ifdef TRACY_HAS_CALLSTACK
2020-09-29 13:10:55 +00:00
TracyLfqPrepare ( QueueType : : Callstack ) ;
2018-08-20 20:20:44 +00:00
auto ptr = Callstack ( depth ) ;
2019-03-05 01:15:13 +00:00
CutCallstack ( ptr , skipBefore ) ;
2020-07-26 12:15:16 +00:00
MemWrite ( & item - > callstackFat . ptr , ( uint64_t ) ptr ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-03-05 01:15:13 +00:00
# endif
}
void Profiler : : CutCallstack ( void * callstack , const char * skipBefore )
{
# ifdef TRACY_HAS_CALLSTACK
auto data = ( uintptr_t * ) callstack ;
2018-08-20 20:20:44 +00:00
const auto sz = * data + + ;
2018-08-20 23:24:00 +00:00
uintptr_t i ;
2018-08-20 20:20:44 +00:00
for ( i = 0 ; i < sz ; i + + )
{
2019-03-05 01:39:23 +00:00
auto name = DecodeCallstackPtrFast ( uint64_t ( data [ i ] ) ) ;
const bool found = strcmp ( name , skipBefore ) = = 0 ;
2018-08-20 20:20:44 +00:00
if ( found )
{
i + + ;
break ;
}
}
if ( i ! = sz )
{
memmove ( data , data + i , ( sz - i ) * sizeof ( uintptr_t * ) ) ;
* - - data = sz - i ;
}
# endif
}
2019-02-21 20:59:02 +00:00
# ifdef TRACY_HAS_SYSTIME
void Profiler : : ProcessSysTime ( )
{
2019-10-29 22:05:14 +00:00
if ( m_shutdown . load ( std : : memory_order_relaxed ) ) return ;
2019-02-21 20:59:02 +00:00
auto t = std : : chrono : : high_resolution_clock : : now ( ) . time_since_epoch ( ) . count ( ) ;
if ( t - m_sysTimeLast > 100000000 ) // 100 ms
{
2019-02-25 14:11:35 +00:00
auto sysTime = m_sysTime . Get ( ) ;
if ( sysTime > = 0 )
{
m_sysTimeLast = t ;
2019-02-21 20:59:02 +00:00
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : SysTimeReport ) ;
2019-02-25 14:11:35 +00:00
MemWrite ( & item - > sysTime . time , GetTime ( ) ) ;
MemWrite ( & item - > sysTime . sysTime , sysTime ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-02-25 14:11:35 +00:00
}
2019-02-21 20:59:02 +00:00
}
}
# endif
2019-11-25 22:59:48 +00:00
void Profiler : : HandleParameter ( uint64_t payload )
{
assert ( m_paramCallback ) ;
const auto idx = uint32_t ( payload > > 32 ) ;
const auto val = int32_t ( payload & 0xFFFFFFFF ) ;
m_paramCallback ( idx , val ) ;
2021-02-03 21:32:31 +00:00
AckServerQuery ( ) ;
2019-11-25 22:59:48 +00:00
}
2020-11-21 20:05:39 +00:00
# ifdef __ANDROID__
// Implementation helpers of EnsureReadable(address).
// This is so far only needed on Android, where it is common for libraries to be mapped
// with only executable, not readable, permissions. Typical example (line from /proc/self/maps):
/*
746 b63b000 - 746 b6dc000 - - xp 00042000 07 : 48 35 / apex / com . android . runtime / lib64 / bionic / libc . so
*/
// See https://github.com/wolfpld/tracy/issues/125 .
// To work around this, we parse /proc/self/maps and we use mprotect to set read permissions
// on any mappings that contain symbols addresses hit by HandleSymbolCodeQuery.
2020-11-23 16:56:08 +00:00
namespace {
2020-11-21 20:05:39 +00:00
// Holds some information about a single memory mapping.
struct MappingInfo {
// Start of address range. Inclusive.
uintptr_t start_address ;
// End of address range. Exclusive, so the mapping is the half-open interval
// [start, end) and its length in bytes is `end - start`. As in /proc/self/maps.
uintptr_t end_address ;
// Read/Write/Executable permissions.
bool perm_r , perm_w , perm_x ;
} ;
2020-11-23 16:56:08 +00:00
} // anonymous namespace
2020-11-21 20:05:39 +00:00
// Internal implementation helper for LookUpMapping(address).
//
// Parses /proc/self/maps returning a vector<MappingInfo>.
// /proc/self/maps is assumed to be sorted by ascending address, so the resulting
// vector is sorted by ascending address too.
2020-11-23 16:56:08 +00:00
static std : : vector < MappingInfo > ParseMappings ( )
2020-11-21 20:05:39 +00:00
{
std : : vector < MappingInfo > result ;
FILE * file = fopen ( " /proc/self/maps " , " r " ) ;
if ( ! file ) return result ;
char line [ 1024 ] ;
while ( fgets ( line , sizeof ( line ) , file ) )
{
uintptr_t start_addr ;
uintptr_t end_addr ;
if ( sscanf ( line , " %lx-%lx " , & start_addr , & end_addr ) ! = 2 ) continue ;
char * first_space = strchr ( line , ' ' ) ;
if ( ! first_space ) continue ;
char * perm = first_space + 1 ;
char * second_space = strchr ( perm , ' ' ) ;
if ( ! second_space | | second_space - perm ! = 4 ) continue ;
result . emplace_back ( ) ;
auto & mapping = result . back ( ) ;
mapping . start_address = start_addr ;
mapping . end_address = end_addr ;
mapping . perm_r = perm [ 0 ] = = ' r ' ;
mapping . perm_w = perm [ 1 ] = = ' w ' ;
mapping . perm_x = perm [ 2 ] = = ' x ' ;
}
fclose ( file ) ;
return result ;
}
// Internal implementation helper for LookUpMapping(address).
//
// Takes as input an `address` and a known vector `mappings`, assumed to be
// sorted by increasing addresses, as /proc/self/maps seems to be.
// Returns a pointer to the MappingInfo describing the mapping that this
// address belongs to, or nullptr if the address isn't in `mappings`.
2020-11-23 16:56:08 +00:00
static MappingInfo * LookUpMapping ( std : : vector < MappingInfo > & mappings , uintptr_t address )
2020-11-21 20:05:39 +00:00
{
// Comparison function for std::lower_bound. Returns true if all addresses in `m1`
// are lower than `addr`.
auto Compare = [ ] ( const MappingInfo & m1 , uintptr_t addr ) {
// '<=' because the address ranges are half-open intervals, [start, end).
return m1 . end_address < = addr ;
} ;
auto iter = std : : lower_bound ( mappings . begin ( ) , mappings . end ( ) , address , Compare ) ;
2020-11-23 16:56:08 +00:00
if ( iter = = mappings . end ( ) | | iter - > start_address > address ) {
2020-11-21 20:05:39 +00:00
return nullptr ;
}
return & * iter ;
}
// Internal implementation helper for EnsureReadable(address).
//
// Takes as input an `address` and returns a pointer to a MappingInfo
// describing the mapping that this address belongs to, or nullptr if
// the address isn't in any known mapping.
//
2020-11-22 14:49:09 +00:00
// This function is stateful and not reentrant (assumes to be called from
// only one thread). It holds a vector of mappings parsed from /proc/self/maps.
2020-11-21 20:05:39 +00:00
//
// Attempts to react to mappings changes by re-parsing /proc/self/maps.
2020-11-23 16:56:08 +00:00
static MappingInfo * LookUpMapping ( uintptr_t address )
2020-11-21 20:05:39 +00:00
{
// Static state managed by this function. Not constant, we mutate that state as
// we turn some mappings readable. Initially parsed once here, updated as needed below.
static std : : vector < MappingInfo > s_mappings = ParseMappings ( ) ;
MappingInfo * mapping = LookUpMapping ( s_mappings , address ) ;
if ( mapping ) return mapping ;
// This address isn't in any known mapping. Try parsing again, maybe
// mappings changed.
s_mappings = ParseMappings ( ) ;
return LookUpMapping ( s_mappings , address ) ;
}
// Internal implementation helper for EnsureReadable(address).
//
// Attempts to make the specified `mapping` readable if it isn't already.
// Returns true if and only if the mapping is readable.
2020-11-23 16:56:08 +00:00
static bool EnsureReadable ( MappingInfo & mapping )
2020-11-21 20:05:39 +00:00
{
if ( mapping . perm_r )
{
// The mapping is already readable.
return true ;
}
int prot = PROT_READ ;
if ( mapping . perm_w ) prot | = PROT_WRITE ;
if ( mapping . perm_x ) prot | = PROT_EXEC ;
if ( mprotect ( reinterpret_cast < void * > ( mapping . start_address ) ,
mapping . end_address - mapping . start_address , prot ) = = - 1 )
{
// Failed to make the mapping readable. Shouldn't happen, hasn't
// been observed yet. If it happened in practice, we should consider
// adding a bool to MappingInfo to track this to avoid retrying mprotect
// everytime on such mappings.
return false ;
}
// The mapping is now readable. Update `mapping` so the next call will be fast.
mapping . perm_r = true ;
return true ;
}
// Attempts to set the read permission on the entire mapping containing the
2020-11-23 16:56:08 +00:00
// specified address. Returns true if and only if the mapping is now readable.
static bool EnsureReadable ( uintptr_t address )
2020-11-21 20:05:39 +00:00
{
MappingInfo * mapping = LookUpMapping ( address ) ;
return mapping & & EnsureReadable ( * mapping ) ;
}
# endif // defined __ANDROID__
2020-02-26 21:35:15 +00:00
void Profiler : : HandleSymbolQuery ( uint64_t symbol )
{
# ifdef TRACY_HAS_CALLSTACK
2021-06-12 14:08:50 +00:00
// Special handling for kernel frames
if ( symbol > > 63 ! = 0 )
{
SendSingleString ( " <kernel> " ) ;
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : SymbolInformation ) ;
MemWrite ( & item . symbolInformation . line , 0 ) ;
MemWrite ( & item . symbolInformation . symAddr , symbol ) ;
AppendData ( & item , QueueDataSize [ ( int ) QueueType : : SymbolInformation ] ) ;
return ;
}
2021-06-12 12:41:53 +00:00
# ifdef __ANDROID__
2020-11-21 20:05:39 +00:00
// On Android it's common for code to be in mappings that are only executable
// but not readable.
if ( ! EnsureReadable ( symbol ) )
{
2021-06-12 12:41:53 +00:00
AckServerQuery ( ) ;
2020-11-21 20:05:39 +00:00
return ;
}
2021-06-12 12:41:53 +00:00
# endif
2020-02-26 21:35:15 +00:00
const auto sym = DecodeSymbolAddress ( symbol ) ;
2020-07-25 22:31:54 +00:00
SendSingleString ( sym . file ) ;
2020-02-26 21:35:15 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : SymbolInformation ) ;
2020-02-27 11:49:48 +00:00
MemWrite ( & item . symbolInformation . line , sym . line ) ;
MemWrite ( & item . symbolInformation . symAddr , symbol ) ;
2020-02-26 21:35:15 +00:00
AppendData ( & item , QueueDataSize [ ( int ) QueueType : : SymbolInformation ] ) ;
2020-02-27 12:17:26 +00:00
if ( sym . needFree ) tracy_free ( ( void * ) sym . file ) ;
2020-02-26 21:35:15 +00:00
# endif
}
2020-03-25 19:04:55 +00:00
void Profiler : : HandleSymbolCodeQuery ( uint64_t symbol , uint32_t size )
{
2020-11-21 20:05:39 +00:00
# ifdef __ANDROID__
// On Android it's common for code to be in mappings that are only executable
// but not readable.
if ( ! EnsureReadable ( symbol ) )
{
2021-06-12 23:08:04 +00:00
AckServerQuery ( ) ;
2020-11-21 20:05:39 +00:00
return ;
}
# endif
2020-03-25 19:04:55 +00:00
SendLongString ( symbol , ( const char * ) symbol , size , QueueType : : SymbolCode ) ;
}
2021-02-03 23:03:25 +00:00
void Profiler : : HandleSourceCodeQuery ( )
{
assert ( m_exectime ! = 0 ) ;
assert ( m_queryData ) ;
2021-06-09 23:48:11 +00:00
InitRpmalloc ( ) ;
2021-02-03 23:03:25 +00:00
struct stat st ;
if ( stat ( m_queryData , & st ) = = 0 & & ( uint64_t ) st . st_mtime < m_exectime & & st . st_size < ( TargetFrameSize - 16 ) )
{
FILE * f = fopen ( m_queryData , " rb " ) ;
2021-06-09 23:48:11 +00:00
tracy_free_fast ( m_queryData ) ;
2021-02-03 23:03:25 +00:00
if ( f )
{
2021-06-09 23:48:11 +00:00
auto ptr = ( char * ) tracy_malloc_fast ( st . st_size ) ;
2021-02-03 23:03:25 +00:00
auto rd = fread ( ptr , 1 , st . st_size , f ) ;
fclose ( f ) ;
2021-02-07 20:08:24 +00:00
if ( rd = = ( size_t ) st . st_size )
2021-02-03 23:03:25 +00:00
{
SendLongString ( ( uint64_t ) ptr , ptr , rd , QueueType : : SourceCode ) ;
}
else
{
AckSourceCodeNotAvailable ( ) ;
}
2021-06-09 23:48:11 +00:00
tracy_free_fast ( ptr ) ;
2021-02-03 23:03:25 +00:00
}
else
{
AckSourceCodeNotAvailable ( ) ;
}
}
else
{
2021-06-09 23:48:11 +00:00
tracy_free_fast ( m_queryData ) ;
2021-02-03 23:03:25 +00:00
AckSourceCodeNotAvailable ( ) ;
}
m_queryData = nullptr ;
}
2020-04-01 19:43:03 +00:00
void Profiler : : SendCodeLocation ( uint64_t ptr )
{
# ifdef TRACY_HAS_CALLSTACK
const auto sym = DecodeCodeAddress ( ptr ) ;
2020-07-25 22:28:52 +00:00
SendSingleString ( sym . file ) ;
2020-04-01 19:43:03 +00:00
QueueItem item ;
MemWrite ( & item . hdr . type , QueueType : : CodeInformation ) ;
MemWrite ( & item . codeInformation . ptr , ptr ) ;
MemWrite ( & item . codeInformation . line , sym . line ) ;
2021-06-19 17:03:00 +00:00
MemWrite ( & item . codeInformation . symAddr , sym . symAddr ) ;
2020-04-01 19:43:03 +00:00
AppendData ( & item , QueueDataSize [ ( int ) QueueType : : CodeInformation ] ) ;
if ( sym . needFree ) tracy_free ( ( void * ) sym . file ) ;
# endif
}
2020-04-07 20:01:31 +00:00
# if ( defined _WIN32 || defined __CYGWIN__ ) && defined TRACY_TIMER_QPC
int64_t Profiler : : GetTimeQpc ( )
{
LARGE_INTEGER t ;
QueryPerformanceCounter ( & t ) ;
return t . QuadPart ;
}
# endif
2017-09-10 15:43:56 +00:00
}
2017-10-16 19:34:39 +00:00
2019-01-14 19:55:37 +00:00
# ifdef __cplusplus
extern " C " {
# endif
2019-10-03 20:39:26 +00:00
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin ( const struct ___tracy_source_location_data * srcloc , int active )
2019-01-14 19:55:37 +00:00
{
___tracy_c_zone_context ctx ;
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
ctx . active = active & & tracy : : GetProfiler ( ) . IsConnected ( ) ;
2019-01-14 19:55:37 +00:00
# else
ctx . active = active ;
# endif
if ( ! ctx . active ) return ctx ;
2019-02-19 17:38:08 +00:00
const auto id = tracy : : GetProfiler ( ) . GetNextZoneId ( ) ;
2019-01-14 21:28:58 +00:00
ctx . id = id ;
2019-01-15 17:59:05 +00:00
# ifndef TRACY_NO_VERIFY
2019-01-14 21:28:58 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-01-14 21:28:58 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-14 21:28:58 +00:00
}
2019-01-15 17:59:05 +00:00
# endif
2019-01-14 21:28:58 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneBegin ) ;
2019-08-12 17:18:17 +00:00
tracy : : MemWrite ( & item - > zoneBegin . time , tracy : : Profiler : : GetTime ( ) ) ;
2019-01-14 21:28:58 +00:00
tracy : : MemWrite ( & item - > zoneBegin . srcloc , ( uint64_t ) srcloc ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-14 21:28:58 +00:00
}
2019-01-14 19:55:37 +00:00
return ctx ;
}
2019-10-03 20:39:26 +00:00
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_callstack ( const struct ___tracy_source_location_data * srcloc , int depth , int active )
2019-01-14 19:55:37 +00:00
{
___tracy_c_zone_context ctx ;
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
ctx . active = active & & tracy : : GetProfiler ( ) . IsConnected ( ) ;
2019-01-14 19:55:37 +00:00
# else
ctx . active = active ;
# endif
if ( ! ctx . active ) return ctx ;
2019-02-19 17:38:08 +00:00
const auto id = tracy : : GetProfiler ( ) . GetNextZoneId ( ) ;
2019-01-14 21:28:58 +00:00
ctx . id = id ;
2019-01-15 17:59:05 +00:00
# ifndef TRACY_NO_VERIFY
2019-01-14 21:28:58 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-01-14 21:28:58 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-14 21:28:58 +00:00
}
2019-01-15 17:59:05 +00:00
# endif
2020-09-29 14:39:56 +00:00
tracy : : GetProfiler ( ) . SendCallstack ( depth ) ;
2019-01-14 21:28:58 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneBeginCallstack ) ;
2019-08-12 17:18:17 +00:00
tracy : : MemWrite ( & item - > zoneBegin . time , tracy : : Profiler : : GetTime ( ) ) ;
2019-01-14 21:28:58 +00:00
tracy : : MemWrite ( & item - > zoneBegin . srcloc , ( uint64_t ) srcloc ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-14 21:28:58 +00:00
}
2019-01-14 19:55:37 +00:00
return ctx ;
}
2019-12-05 23:22:49 +00:00
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc ( uint64_t srcloc , int active )
{
___tracy_c_zone_context ctx ;
# ifdef TRACY_ON_DEMAND
ctx . active = active & & tracy : : GetProfiler ( ) . IsConnected ( ) ;
# else
ctx . active = active ;
# endif
2019-12-05 23:42:42 +00:00
if ( ! ctx . active )
{
tracy : : tracy_free ( ( void * ) srcloc ) ;
return ctx ;
}
2019-12-05 23:22:49 +00:00
const auto id = tracy : : GetProfiler ( ) . GetNextZoneId ( ) ;
ctx . id = id ;
# ifndef TRACY_NO_VERIFY
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-12-05 23:22:49 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-12-05 23:22:49 +00:00
}
# endif
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneBeginAllocSrcLoc ) ;
2019-12-05 23:22:49 +00:00
tracy : : MemWrite ( & item - > zoneBegin . time , tracy : : Profiler : : GetTime ( ) ) ;
tracy : : MemWrite ( & item - > zoneBegin . srcloc , srcloc ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-12-05 23:22:49 +00:00
}
return ctx ;
}
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc_callstack ( uint64_t srcloc , int depth , int active )
{
___tracy_c_zone_context ctx ;
# ifdef TRACY_ON_DEMAND
ctx . active = active & & tracy : : GetProfiler ( ) . IsConnected ( ) ;
# else
ctx . active = active ;
# endif
2019-12-05 23:42:42 +00:00
if ( ! ctx . active )
{
tracy : : tracy_free ( ( void * ) srcloc ) ;
return ctx ;
}
2019-12-05 23:22:49 +00:00
const auto id = tracy : : GetProfiler ( ) . GetNextZoneId ( ) ;
ctx . id = id ;
# ifndef TRACY_NO_VERIFY
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-12-05 23:22:49 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-12-05 23:22:49 +00:00
}
# endif
2020-09-29 14:39:56 +00:00
tracy : : GetProfiler ( ) . SendCallstack ( depth ) ;
2019-12-05 23:22:49 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneBeginAllocSrcLocCallstack ) ;
2019-12-05 23:22:49 +00:00
tracy : : MemWrite ( & item - > zoneBegin . time , tracy : : Profiler : : GetTime ( ) ) ;
tracy : : MemWrite ( & item - > zoneBegin . srcloc , srcloc ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-12-05 23:22:49 +00:00
}
return ctx ;
}
2019-10-03 20:39:26 +00:00
TRACY_API void ___tracy_emit_zone_end ( TracyCZoneCtx ctx )
2019-01-14 19:55:37 +00:00
{
if ( ! ctx . active ) return ;
2019-01-15 17:59:05 +00:00
# ifndef TRACY_NO_VERIFY
2019-01-14 21:28:58 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-01-14 21:28:58 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , ctx . id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-14 21:28:58 +00:00
}
2019-01-15 17:59:05 +00:00
# endif
2019-01-14 21:28:58 +00:00
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneEnd ) ;
2019-08-12 17:18:17 +00:00
tracy : : MemWrite ( & item - > zoneEnd . time , tracy : : Profiler : : GetTime ( ) ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-14 21:28:58 +00:00
}
2019-01-14 19:55:37 +00:00
}
2019-10-03 20:39:26 +00:00
TRACY_API void ___tracy_emit_zone_text ( TracyCZoneCtx ctx , const char * txt , size_t size )
2019-01-16 00:17:01 +00:00
{
2020-07-21 18:09:25 +00:00
assert ( size < std : : numeric_limits < uint16_t > : : max ( ) ) ;
2019-01-16 00:17:01 +00:00
if ( ! ctx . active ) return ;
2020-07-21 18:09:25 +00:00
auto ptr = ( char * ) tracy : : tracy_malloc ( size ) ;
2019-01-16 00:17:01 +00:00
memcpy ( ptr , txt , size ) ;
# ifndef TRACY_NO_VERIFY
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-01-16 00:17:01 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , ctx . id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-16 00:17:01 +00:00
}
# endif
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneText ) ;
2020-07-21 18:09:25 +00:00
tracy : : MemWrite ( & item - > zoneTextFat . text , ( uint64_t ) ptr ) ;
tracy : : MemWrite ( & item - > zoneTextFat . size , ( uint16_t ) size ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-16 00:17:01 +00:00
}
}
2019-10-03 20:39:26 +00:00
TRACY_API void ___tracy_emit_zone_name ( TracyCZoneCtx ctx , const char * txt , size_t size )
2019-01-16 00:17:01 +00:00
{
2020-07-21 18:09:25 +00:00
assert ( size < std : : numeric_limits < uint16_t > : : max ( ) ) ;
2019-01-16 00:17:01 +00:00
if ( ! ctx . active ) return ;
2020-07-21 18:09:25 +00:00
auto ptr = ( char * ) tracy : : tracy_malloc ( size ) ;
2019-01-16 00:17:01 +00:00
memcpy ( ptr , txt , size ) ;
# ifndef TRACY_NO_VERIFY
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
2019-01-16 00:17:01 +00:00
tracy : : MemWrite ( & item - > zoneValidation . id , ctx . id ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-16 00:17:01 +00:00
}
# endif
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepareC ( tracy : : QueueType : : ZoneName ) ;
2020-07-21 18:09:25 +00:00
tracy : : MemWrite ( & item - > zoneTextFat . text , ( uint64_t ) ptr ) ;
tracy : : MemWrite ( & item - > zoneTextFat . size , ( uint16_t ) size ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommitC ;
2019-01-16 00:17:01 +00:00
}
}
2020-11-27 11:37:35 +00:00
TRACY_API void ___tracy_emit_zone_color ( TracyCZoneCtx ctx , uint32_t color ) {
if ( ! ctx . active ) return ;
# ifndef TRACY_NO_VERIFY
{
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
tracy : : MemWrite ( & item - > zoneValidation . id , ctx . id ) ;
TracyLfqCommitC ;
}
# endif
{
TracyLfqPrepareC ( tracy : : QueueType : : ZoneColor ) ;
tracy : : MemWrite ( & item - > zoneColor . r , uint8_t ( ( color ) & 0xFF ) ) ;
tracy : : MemWrite ( & item - > zoneColor . g , uint8_t ( ( color > > 8 ) & 0xFF ) ) ;
tracy : : MemWrite ( & item - > zoneColor . b , uint8_t ( ( color > > 16 ) & 0xFF ) ) ;
TracyLfqCommitC ;
}
}
2020-05-24 14:13:09 +00:00
TRACY_API void ___tracy_emit_zone_value ( TracyCZoneCtx ctx , uint64_t value )
{
if ( ! ctx . active ) return ;
# ifndef TRACY_NO_VERIFY
{
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValidation ) ;
tracy : : MemWrite ( & item - > zoneValidation . id , ctx . id ) ;
TracyLfqCommitC ;
}
# endif
{
TracyLfqPrepareC ( tracy : : QueueType : : ZoneValue ) ;
tracy : : MemWrite ( & item - > zoneValue . value , value ) ;
TracyLfqCommitC ;
}
}
2020-06-23 23:33:26 +00:00
TRACY_API void ___tracy_emit_memory_alloc ( const void * ptr , size_t size , int secure ) { tracy : : Profiler : : MemAlloc ( ptr , size , secure ! = 0 ) ; }
TRACY_API void ___tracy_emit_memory_alloc_callstack ( const void * ptr , size_t size , int depth , int secure ) { tracy : : Profiler : : MemAllocCallstack ( ptr , size , depth , secure ! = 0 ) ; }
TRACY_API void ___tracy_emit_memory_free ( const void * ptr , int secure ) { tracy : : Profiler : : MemFree ( ptr , secure ! = 0 ) ; }
TRACY_API void ___tracy_emit_memory_free_callstack ( const void * ptr , int depth , int secure ) { tracy : : Profiler : : MemFreeCallstack ( ptr , depth , secure ! = 0 ) ; }
2020-11-15 14:23:22 +00:00
TRACY_API void ___tracy_emit_memory_alloc_named ( const void * ptr , size_t size , int secure , const char * name ) { tracy : : Profiler : : MemAllocNamed ( ptr , size , secure ! = 0 , name ) ; }
TRACY_API void ___tracy_emit_memory_alloc_callstack_named ( const void * ptr , size_t size , int depth , int secure , const char * name ) { tracy : : Profiler : : MemAllocCallstackNamed ( ptr , size , depth , secure ! = 0 , name ) ; }
TRACY_API void ___tracy_emit_memory_free_named ( const void * ptr , int secure , const char * name ) { tracy : : Profiler : : MemFreeNamed ( ptr , secure ! = 0 , name ) ; }
TRACY_API void ___tracy_emit_memory_free_callstack_named ( const void * ptr , int depth , int secure , const char * name ) { tracy : : Profiler : : MemFreeCallstackNamed ( ptr , depth , secure ! = 0 , name ) ; }
2019-10-03 20:39:26 +00:00
TRACY_API void ___tracy_emit_frame_mark ( const char * name ) { tracy : : Profiler : : SendFrameMark ( name ) ; }
TRACY_API void ___tracy_emit_frame_mark_start ( const char * name ) { tracy : : Profiler : : SendFrameMark ( name , tracy : : QueueType : : FrameMarkMsgStart ) ; }
TRACY_API void ___tracy_emit_frame_mark_end ( const char * name ) { tracy : : Profiler : : SendFrameMark ( name , tracy : : QueueType : : FrameMarkMsgEnd ) ; }
TRACY_API void ___tracy_emit_frame_image ( const void * image , uint16_t w , uint16_t h , uint8_t offset , int flip ) { tracy : : Profiler : : SendFrameImage ( image , w , h , offset , flip ) ; }
TRACY_API void ___tracy_emit_plot ( const char * name , double val ) { tracy : : Profiler : : PlotData ( name , val ) ; }
2019-11-14 22:40:41 +00:00
TRACY_API void ___tracy_emit_message ( const char * txt , size_t size , int callstack ) { tracy : : Profiler : : Message ( txt , size , callstack ) ; }
TRACY_API void ___tracy_emit_messageL ( const char * txt , int callstack ) { tracy : : Profiler : : Message ( txt , callstack ) ; }
TRACY_API void ___tracy_emit_messageC ( const char * txt , size_t size , uint32_t color , int callstack ) { tracy : : Profiler : : MessageColor ( txt , size , color , callstack ) ; }
TRACY_API void ___tracy_emit_messageLC ( const char * txt , uint32_t color , int callstack ) { tracy : : Profiler : : MessageColor ( txt , color , callstack ) ; }
2019-10-03 20:39:26 +00:00
TRACY_API void ___tracy_emit_message_appinfo ( const char * txt , size_t size ) { tracy : : Profiler : : MessageAppInfo ( txt , size ) ; }
2020-06-20 14:31:12 +00:00
TRACY_API uint64_t ___tracy_alloc_srcloc ( uint32_t line , const char * source , size_t sourceSz , const char * function , size_t functionSz ) {
return tracy : : Profiler : : AllocSourceLocation ( line , source , sourceSz , function , functionSz ) ;
}
TRACY_API uint64_t ___tracy_alloc_srcloc_name ( uint32_t line , const char * source , size_t sourceSz , const char * function , size_t functionSz , const char * name , size_t nameSz ) {
return tracy : : Profiler : : AllocSourceLocation ( line , source , sourceSz , function , functionSz , name , nameSz ) ;
}
2019-06-24 18:54:43 +00:00
2019-01-14 19:55:37 +00:00
# ifdef __cplusplus
}
# endif
2017-10-16 19:34:39 +00:00
# endif