mirror of
https://github.com/wolfpld/tracy.git
synced 2026-06-14 03:09:04 +00:00
Compare commits
13 Commits
slomp/webg
...
syscalls
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ee42a723a | ||
|
|
154a3ead5f | ||
|
|
bbdbf2bc78 | ||
|
|
1fdb45979c | ||
|
|
359bcee690 | ||
|
|
8a6f4258e9 | ||
|
|
102c835b4c | ||
|
|
68cffc8525 | ||
|
|
14af14999e | ||
|
|
0610c73be3 | ||
|
|
17165102fc | ||
|
|
975207a2ad | ||
|
|
394ad35eb2 |
@@ -9,6 +9,7 @@
|
|||||||
# define NOMINMAX
|
# define NOMINMAX
|
||||||
# endif
|
# endif
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
# include <winternl.h>
|
||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
# pragma warning( push )
|
# pragma warning( push )
|
||||||
# pragma warning( disable : 4091 )
|
# pragma warning( disable : 4091 )
|
||||||
@@ -37,6 +38,29 @@ int cb_num;
|
|||||||
CallstackEntry cb_data[MaxCbTrace];
|
CallstackEntry cb_data[MaxCbTrace];
|
||||||
|
|
||||||
extern "C" { t_RtlWalkFrameChain RtlWalkFrameChain = 0; }
|
extern "C" { t_RtlWalkFrameChain RtlWalkFrameChain = 0; }
|
||||||
|
extern "C" typedef NTSTATUS (WINAPI *t_ZwQuerySystemInformation)( int, PVOID, ULONG, PULONG );
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
typedef struct _SYSTEM_MODULE_ENTRY
|
||||||
|
{
|
||||||
|
HANDLE Section;
|
||||||
|
PVOID MappedBase;
|
||||||
|
PVOID ImageBase;
|
||||||
|
ULONG ImageSize;
|
||||||
|
ULONG Flags;
|
||||||
|
USHORT LoadOrderIndex;
|
||||||
|
USHORT InitOrderIndex;
|
||||||
|
USHORT LoadCount;
|
||||||
|
USHORT OffsetToFileName;
|
||||||
|
UCHAR FullPathName[256];
|
||||||
|
} SYSTEM_MODULE_ENTRY;
|
||||||
|
|
||||||
|
typedef struct _SYSTEM_MODULE_INFORMATION
|
||||||
|
{
|
||||||
|
ULONG Count;
|
||||||
|
SYSTEM_MODULE_ENTRY Module[1];
|
||||||
|
} SYSTEM_MODULE_INFORMATION;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined __MINGW32__ && API_VERSION_NUMBER < 12
|
#if defined __MINGW32__ && API_VERSION_NUMBER < 12
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -51,28 +75,55 @@ BOOL IMAGEAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 qwAddr, ULONG
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static HANDLE currentProcess;
|
||||||
|
|
||||||
void InitCallstack()
|
void InitCallstack()
|
||||||
{
|
{
|
||||||
|
currentProcess = GetCurrentProcess();
|
||||||
#ifdef UNICODE
|
#ifdef UNICODE
|
||||||
RtlWalkFrameChain = (t_RtlWalkFrameChain)GetProcAddress( GetModuleHandle( L"ntdll.dll" ), "RtlWalkFrameChain" );
|
RtlWalkFrameChain = (t_RtlWalkFrameChain)GetProcAddress( GetModuleHandle( L"ntdll.dll" ), "RtlWalkFrameChain" );
|
||||||
|
t_ZwQuerySystemInformation ZwQuerySystemInformation = (t_ZwQuerySystemInformation)GetProcAddress( GetModuleHandle( L"ntdll.dll" ), "ZwQuerySystemInformation" );
|
||||||
#else
|
#else
|
||||||
RtlWalkFrameChain = (t_RtlWalkFrameChain)GetProcAddress( GetModuleHandle( "ntdll.dll" ), "RtlWalkFrameChain" );
|
RtlWalkFrameChain = (t_RtlWalkFrameChain)GetProcAddress( GetModuleHandle( "ntdll.dll" ), "RtlWalkFrameChain" );
|
||||||
|
t_ZwQuerySystemInformation ZwQuerySystemInformation = (t_ZwQuerySystemInformation)GetProcAddress( GetModuleHandle( "ntdll.dll" ), "ZwQuerySystemInformation" );
|
||||||
#endif
|
#endif
|
||||||
SymInitialize( GetCurrentProcess(), nullptr, true );
|
SymInitialize( currentProcess, nullptr, true );
|
||||||
SymSetOptions( SYMOPT_LOAD_LINES );
|
SymSetOptions( SYMOPT_LOAD_LINES );
|
||||||
|
|
||||||
|
if( ZwQuerySystemInformation )
|
||||||
|
{
|
||||||
|
char sysroot[1024];
|
||||||
|
const auto rootlen = ExpandEnvironmentStringsA( "%SystemRoot%", sysroot, 1024 ) - 1;
|
||||||
|
ULONG size = 0;
|
||||||
|
ZwQuerySystemInformation( 11 /*SystemModuleInformation*/, 0, size, &size );
|
||||||
|
auto modules = (SYSTEM_MODULE_INFORMATION*)tracy_malloc( size );
|
||||||
|
ZwQuerySystemInformation( 11 /*SystemModuleInformation*/, modules, size, &size );
|
||||||
|
for( ULONG i=0; i<modules->Count; i++ )
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
const char* name = (char*)modules->Module[i].FullPathName;
|
||||||
|
if( strncmp( "\\SystemRoot", name, 11 ) == 0 )
|
||||||
|
{
|
||||||
|
memcpy( buf, sysroot, rootlen );
|
||||||
|
strcpy( buf + rootlen, name+11 );
|
||||||
|
name = buf;
|
||||||
|
}
|
||||||
|
auto res = SymLoadModuleEx( currentProcess, nullptr, name, nullptr, (DWORD64)modules->Module[i].ImageBase, modules->Module[i].ImageSize, nullptr, 0 );
|
||||||
|
}
|
||||||
|
tracy_free( modules );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DecodeCallstackPtrFast( uint64_t ptr )
|
const char* DecodeCallstackPtrFast( uint64_t ptr )
|
||||||
{
|
{
|
||||||
static char ret[1024];
|
static char ret[1024];
|
||||||
const auto proc = GetCurrentProcess();
|
|
||||||
|
|
||||||
char buf[sizeof( SYMBOL_INFO ) + 1024];
|
char buf[sizeof( SYMBOL_INFO ) + 1024];
|
||||||
auto si = (SYMBOL_INFO*)buf;
|
auto si = (SYMBOL_INFO*)buf;
|
||||||
si->SizeOfStruct = sizeof( SYMBOL_INFO );
|
si->SizeOfStruct = sizeof( SYMBOL_INFO );
|
||||||
si->MaxNameLen = 1024;
|
si->MaxNameLen = 1024;
|
||||||
|
|
||||||
if( SymFromAddr( proc, ptr, nullptr, si ) == 0 )
|
if( SymFromAddr( currentProcess, ptr, nullptr, si ) == 0 )
|
||||||
{
|
{
|
||||||
*ret = '\0';
|
*ret = '\0';
|
||||||
}
|
}
|
||||||
@@ -87,13 +138,12 @@ const char* DecodeCallstackPtrFast( uint64_t ptr )
|
|||||||
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
||||||
{
|
{
|
||||||
int write;
|
int write;
|
||||||
const auto proc = GetCurrentProcess();
|
|
||||||
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
||||||
const auto inlineNum = std::min<DWORD>( MaxCbTrace - 1, SymAddrIncludeInlineTrace( proc, ptr ) );
|
const auto inlineNum = std::min<DWORD>( MaxCbTrace - 1, SymAddrIncludeInlineTrace( currentProcess, ptr ) );
|
||||||
DWORD ctx = 0;
|
DWORD ctx = 0;
|
||||||
DWORD idx;
|
DWORD idx;
|
||||||
BOOL doInline = FALSE;
|
BOOL doInline = FALSE;
|
||||||
if( inlineNum != 0 ) doInline = SymQueryInlineTrace( proc, ptr, 0, ptr, ptr, &ctx, &idx );
|
if( inlineNum != 0 ) doInline = SymQueryInlineTrace( currentProcess, ptr, 0, ptr, ptr, &ctx, &idx );
|
||||||
if( doInline )
|
if( doInline )
|
||||||
{
|
{
|
||||||
write = inlineNum;
|
write = inlineNum;
|
||||||
@@ -111,7 +161,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
|||||||
si->SizeOfStruct = sizeof( SYMBOL_INFO );
|
si->SizeOfStruct = sizeof( SYMBOL_INFO );
|
||||||
si->MaxNameLen = 1024;
|
si->MaxNameLen = 1024;
|
||||||
|
|
||||||
if( SymFromAddr( proc, ptr, nullptr, si ) == 0 )
|
if( SymFromAddr( currentProcess, ptr, nullptr, si ) == 0 )
|
||||||
{
|
{
|
||||||
memcpy( si->Name, "[unknown]", 10 );
|
memcpy( si->Name, "[unknown]", 10 );
|
||||||
si->NameLen = 9;
|
si->NameLen = 9;
|
||||||
@@ -129,7 +179,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
|||||||
cb_data[write].name = name;
|
cb_data[write].name = name;
|
||||||
|
|
||||||
const char* filename;
|
const char* filename;
|
||||||
if (SymGetLineFromAddr64(proc, ptr, &displacement, &line) == 0)
|
if( SymGetLineFromAddr64( currentProcess, ptr, &displacement, &line ) == 0 )
|
||||||
{
|
{
|
||||||
filename = "[unknown]";
|
filename = "[unknown]";
|
||||||
cb_data[write].line = 0;
|
cb_data[write].line = 0;
|
||||||
@@ -155,7 +205,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
|||||||
{
|
{
|
||||||
auto& cb = cb_data[i];
|
auto& cb = cb_data[i];
|
||||||
|
|
||||||
if( SymFromInlineContext( proc, ptr, ctx, nullptr, si ) == 0 )
|
if( SymFromInlineContext( currentProcess, ptr, ctx, nullptr, si ) == 0 )
|
||||||
{
|
{
|
||||||
memcpy( si->Name, "[unknown]", 10 );
|
memcpy( si->Name, "[unknown]", 10 );
|
||||||
si->NameLen = 9;
|
si->NameLen = 9;
|
||||||
@@ -167,7 +217,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
|
|||||||
cb.name = name;
|
cb.name = name;
|
||||||
|
|
||||||
const char* filename;
|
const char* filename;
|
||||||
if( SymGetLineFromInlineContext( proc, ptr, ctx, 0, &displacement, &line ) == 0 )
|
if( SymGetLineFromInlineContext( currentProcess, ptr, ctx, 0, &displacement, &line ) == 0 )
|
||||||
{
|
{
|
||||||
filename = "[unknown]";
|
filename = "[unknown]";
|
||||||
cb.line = 0;
|
cb.line = 0;
|
||||||
|
|||||||
@@ -1017,6 +1017,7 @@ Profiler::Profiler()
|
|||||||
, m_broadcast( nullptr )
|
, m_broadcast( nullptr )
|
||||||
, m_noExit( false )
|
, m_noExit( false )
|
||||||
, m_zoneId( 1 )
|
, m_zoneId( 1 )
|
||||||
|
, m_pid( GetPid() )
|
||||||
, m_stream( LZ4_createStream() )
|
, m_stream( LZ4_createStream() )
|
||||||
, m_buffer( (char*)tracy_malloc( TargetFrameSize*3 ) )
|
, m_buffer( (char*)tracy_malloc( TargetFrameSize*3 ) )
|
||||||
, m_bufferOffset( 0 )
|
, m_bufferOffset( 0 )
|
||||||
@@ -1172,8 +1173,6 @@ void Profiler::Worker()
|
|||||||
const auto hostinfo = GetHostInfo();
|
const auto hostinfo = GetHostInfo();
|
||||||
const auto hisz = std::min<size_t>( strlen( hostinfo ), WelcomeMessageHostInfoSize - 1 );
|
const auto hisz = std::min<size_t>( strlen( hostinfo ), WelcomeMessageHostInfoSize - 1 );
|
||||||
|
|
||||||
const uint64_t pid = GetPid();
|
|
||||||
|
|
||||||
#ifdef TRACY_ON_DEMAND
|
#ifdef TRACY_ON_DEMAND
|
||||||
uint8_t onDemand = 1;
|
uint8_t onDemand = 1;
|
||||||
#else
|
#else
|
||||||
@@ -1193,7 +1192,7 @@ void Profiler::Worker()
|
|||||||
MemWrite( &welcome.delay, m_delay );
|
MemWrite( &welcome.delay, m_delay );
|
||||||
MemWrite( &welcome.resolution, m_resolution );
|
MemWrite( &welcome.resolution, m_resolution );
|
||||||
MemWrite( &welcome.epoch, m_epoch );
|
MemWrite( &welcome.epoch, m_epoch );
|
||||||
MemWrite( &welcome.pid, pid );
|
MemWrite( &welcome.pid, m_pid );
|
||||||
MemWrite( &welcome.onDemand, onDemand );
|
MemWrite( &welcome.onDemand, onDemand );
|
||||||
MemWrite( &welcome.isApple, isApple );
|
MemWrite( &welcome.isApple, isApple );
|
||||||
memcpy( welcome.programName, procname, pnsz );
|
memcpy( welcome.programName, procname, pnsz );
|
||||||
@@ -1811,6 +1810,22 @@ Profiler::DequeueStatus Profiler::Dequeue( moodycamel::ConsumerToken& token )
|
|||||||
MemWrite( &item->gpuTime.gpuTime, dt );
|
MemWrite( &item->gpuTime.gpuTime, dt );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case QueueType::SysCallEnter:
|
||||||
|
{
|
||||||
|
int64_t t = MemRead<int64_t>( &item->sysCallEnter.time );
|
||||||
|
int64_t dt = t - m_refTimeCtx;
|
||||||
|
m_refTimeCtx = t;
|
||||||
|
MemWrite( &item->sysCallEnter.time, dt );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QueueType::SysCallExit:
|
||||||
|
{
|
||||||
|
int64_t t = MemRead<int64_t>( &item->sysCallExit.time );
|
||||||
|
int64_t dt = t - m_refTimeCtx;
|
||||||
|
m_refTimeCtx = t;
|
||||||
|
MemWrite( &item->sysCallExit.time, dt );
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assert( false );
|
assert( false );
|
||||||
break;
|
break;
|
||||||
@@ -2039,7 +2054,9 @@ void Profiler::SendString( uint64_t str, const char* ptr, QueueType type )
|
|||||||
type == QueueType::PlotName ||
|
type == QueueType::PlotName ||
|
||||||
type == QueueType::FrameName ||
|
type == QueueType::FrameName ||
|
||||||
type == QueueType::ExternalName ||
|
type == QueueType::ExternalName ||
|
||||||
type == QueueType::ExternalThreadName );
|
type == QueueType::ExternalThreadName ||
|
||||||
|
type == QueueType::CodeLocationString
|
||||||
|
);
|
||||||
|
|
||||||
QueueItem item;
|
QueueItem item;
|
||||||
MemWrite( &item.hdr.type, type );
|
MemWrite( &item.hdr.type, type );
|
||||||
@@ -2243,6 +2260,16 @@ bool Profiler::HandleServerQuery()
|
|||||||
SysTraceSendExternalName( ptr );
|
SysTraceSendExternalName( ptr );
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case ServerQueryCodeLocationString:
|
||||||
|
{
|
||||||
|
#ifdef TRACY_HAS_CALLSTACK
|
||||||
|
const auto name = DecodeCallstackPtrFast( ptr );
|
||||||
|
#else
|
||||||
|
const auto name = "???";
|
||||||
|
#endif
|
||||||
|
SendString( ptr, name, QueueType::CodeLocationString );
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assert( false );
|
assert( false );
|
||||||
break;
|
break;
|
||||||
@@ -2482,6 +2509,11 @@ void Profiler::ProcessSysTime()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uint64_t Profiler::GetProfilerTid() const
|
||||||
|
{
|
||||||
|
return s_profilerThreadId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -446,6 +446,9 @@ public:
|
|||||||
|
|
||||||
void SendString( uint64_t ptr, const char* str, QueueType type );
|
void SendString( uint64_t ptr, const char* str, QueueType type );
|
||||||
|
|
||||||
|
uint64_t Pid() const { return m_pid; }
|
||||||
|
uint64_t GetProfilerTid() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class DequeueStatus { Success, ConnectionLost, QueueEmpty };
|
enum class DequeueStatus { Success, ConnectionLost, QueueEmpty };
|
||||||
|
|
||||||
@@ -541,6 +544,7 @@ private:
|
|||||||
UdpBroadcast* m_broadcast;
|
UdpBroadcast* m_broadcast;
|
||||||
bool m_noExit;
|
bool m_noExit;
|
||||||
std::atomic<uint32_t> m_zoneId;
|
std::atomic<uint32_t> m_zoneId;
|
||||||
|
uint64_t m_pid;
|
||||||
|
|
||||||
uint64_t m_threadCtx;
|
uint64_t m_threadCtx;
|
||||||
int64_t m_refTimeThread;
|
int64_t m_refTimeThread;
|
||||||
|
|||||||
@@ -54,6 +54,47 @@ struct ReadyThread
|
|||||||
int8_t reserverd;
|
int8_t reserverd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef TRACY_SYSCALLS
|
||||||
|
struct SysCallEnter
|
||||||
|
{
|
||||||
|
// Official MSDN documentation is bullshitting here
|
||||||
|
// This is corroborated by tracerpt displaying address as 64-bit
|
||||||
|
#if defined __x86_64__ || defined _M_X64
|
||||||
|
uint64_t sysCallAddress;
|
||||||
|
#else
|
||||||
|
uint32_t sysCallAddress;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TraceThread
|
||||||
|
{
|
||||||
|
uint32_t ProcessId;
|
||||||
|
uint32_t TThreadId;
|
||||||
|
uint32_t StackBase;
|
||||||
|
uint32_t StackLimit;
|
||||||
|
uint32_t UserStackBase;
|
||||||
|
uint32_t UserStackLimit;
|
||||||
|
uint32_t Affinity;
|
||||||
|
uint32_t Win32StartAddr;
|
||||||
|
uint32_t TebBase;
|
||||||
|
uint32_t SubProcessTag;
|
||||||
|
uint8_t BasePriority;
|
||||||
|
uint8_t PagePriority;
|
||||||
|
uint8_t IoPriority;
|
||||||
|
uint8_t ThreadFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t coreThread[256] = {};
|
||||||
|
|
||||||
|
// We need to know which thread ids are in our process. A hash map would be the best solution here,
|
||||||
|
// but there is no solution ready to use right now. Instead, let's store a thread bit map. Note that
|
||||||
|
// this is only an approximation, there are no guarantees about thread ids returned by the kernel, as
|
||||||
|
// Raymond Chen said on multiple occasions. In the false positive case, we will be reporting system
|
||||||
|
// calls belonging to some other process, and that's no big deal.
|
||||||
|
enum { TidCapacity = 8192 };
|
||||||
|
uint64_t processThreads[TidCapacity] = {};
|
||||||
|
#endif
|
||||||
|
|
||||||
void WINAPI EventRecordCallback( PEVENT_RECORD record )
|
void WINAPI EventRecordCallback( PEVENT_RECORD record )
|
||||||
{
|
{
|
||||||
#ifdef TRACY_ON_DEMAND
|
#ifdef TRACY_ON_DEMAND
|
||||||
@@ -64,6 +105,7 @@ void WINAPI EventRecordCallback( PEVENT_RECORD record )
|
|||||||
if( hdr.EventDescriptor.Opcode == 36 )
|
if( hdr.EventDescriptor.Opcode == 36 )
|
||||||
{
|
{
|
||||||
const auto cswitch = (const CSwitch*)record->UserData;
|
const auto cswitch = (const CSwitch*)record->UserData;
|
||||||
|
const auto cpu = record->BufferContext.ProcessorNumber;
|
||||||
|
|
||||||
Magic magic;
|
Magic magic;
|
||||||
auto token = GetToken();
|
auto token = GetToken();
|
||||||
@@ -75,10 +117,14 @@ void WINAPI EventRecordCallback( PEVENT_RECORD record )
|
|||||||
memcpy( &item->contextSwitch.newThread, &cswitch->newThreadId, sizeof( cswitch->newThreadId ) );
|
memcpy( &item->contextSwitch.newThread, &cswitch->newThreadId, sizeof( cswitch->newThreadId ) );
|
||||||
memset( ((char*)&item->contextSwitch.oldThread)+4, 0, 4 );
|
memset( ((char*)&item->contextSwitch.oldThread)+4, 0, 4 );
|
||||||
memset( ((char*)&item->contextSwitch.newThread)+4, 0, 4 );
|
memset( ((char*)&item->contextSwitch.newThread)+4, 0, 4 );
|
||||||
MemWrite( &item->contextSwitch.cpu, record->BufferContext.ProcessorNumber );
|
MemWrite( &item->contextSwitch.cpu, cpu );
|
||||||
MemWrite( &item->contextSwitch.reason, cswitch->oldThreadWaitReason );
|
MemWrite( &item->contextSwitch.reason, cswitch->oldThreadWaitReason );
|
||||||
MemWrite( &item->contextSwitch.state, cswitch->oldThreadState );
|
MemWrite( &item->contextSwitch.state, cswitch->oldThreadState );
|
||||||
tail.store( magic + 1, std::memory_order_release );
|
tail.store( magic + 1, std::memory_order_release );
|
||||||
|
|
||||||
|
#ifdef TRACY_SYSCALLS
|
||||||
|
coreThread[cpu] = cswitch->newThreadId;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if( hdr.EventDescriptor.Opcode == 50 )
|
else if( hdr.EventDescriptor.Opcode == 50 )
|
||||||
{
|
{
|
||||||
@@ -94,6 +140,70 @@ void WINAPI EventRecordCallback( PEVENT_RECORD record )
|
|||||||
memset( ((char*)&item->threadWakeup.thread)+4, 0, 4 );
|
memset( ((char*)&item->threadWakeup.thread)+4, 0, 4 );
|
||||||
tail.store( magic + 1, std::memory_order_release );
|
tail.store( magic + 1, std::memory_order_release );
|
||||||
}
|
}
|
||||||
|
#ifdef TRACY_SYSCALLS
|
||||||
|
else if( hdr.EventDescriptor.Opcode == 51 )
|
||||||
|
{
|
||||||
|
const auto cpu = record->BufferContext.ProcessorNumber;
|
||||||
|
const auto thread = coreThread[cpu];
|
||||||
|
|
||||||
|
if( thread != 0 )
|
||||||
|
{
|
||||||
|
const auto tid = thread / 4;
|
||||||
|
const auto entry = ( tid / 64 ) % TidCapacity;
|
||||||
|
const auto bit = tid % 64;
|
||||||
|
if( processThreads[entry] & ( 1ull << bit ) )
|
||||||
|
{
|
||||||
|
const auto syscall = (const SysCallEnter*)record->UserData;
|
||||||
|
uint64_t addr = syscall->sysCallAddress;
|
||||||
|
|
||||||
|
Magic magic;
|
||||||
|
auto token = GetToken();
|
||||||
|
auto& tail = token->get_tail_index();
|
||||||
|
auto item = token->enqueue_begin( magic );
|
||||||
|
MemWrite( &item->hdr.type, QueueType::SysCallEnter );
|
||||||
|
MemWrite( &item->sysCallEnter.time, hdr.TimeStamp.QuadPart );
|
||||||
|
MemWrite( &item->sysCallEnter.thread, thread );
|
||||||
|
MemWrite( &item->sysCallEnter.address, addr );
|
||||||
|
tail.store( magic + 1, std::memory_order_release );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( hdr.EventDescriptor.Opcode == 52 )
|
||||||
|
{
|
||||||
|
const auto cpu = record->BufferContext.ProcessorNumber;
|
||||||
|
const auto thread = coreThread[cpu];
|
||||||
|
|
||||||
|
if( thread != 0 )
|
||||||
|
{
|
||||||
|
const auto tid = thread / 4;
|
||||||
|
const auto entry = ( tid / 64 ) % TidCapacity;
|
||||||
|
const auto bit = tid % 64;
|
||||||
|
if( processThreads[entry] & ( 1ull << bit ) )
|
||||||
|
{
|
||||||
|
Magic magic;
|
||||||
|
auto token = GetToken();
|
||||||
|
auto& tail = token->get_tail_index();
|
||||||
|
auto item = token->enqueue_begin( magic );
|
||||||
|
MemWrite( &item->hdr.type, QueueType::SysCallExit );
|
||||||
|
MemWrite( &item->sysCallExit.time, hdr.TimeStamp.QuadPart );
|
||||||
|
MemWrite( &item->sysCallExit.thread, thread );
|
||||||
|
tail.store( magic + 1, std::memory_order_release );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( hdr.EventDescriptor.Opcode == 1 || hdr.EventDescriptor.Opcode == 3 )
|
||||||
|
{
|
||||||
|
const auto tt = (const TraceThread*)record->UserData;
|
||||||
|
if( tt->ProcessId == GetProfiler().Pid() && tt->TThreadId != GetProfiler().GetProfilerTid() && tt->TThreadId != GetCurrentThreadId() )
|
||||||
|
{
|
||||||
|
// Thread ids are (currently) multiples of 4, but its not a part of the contract.
|
||||||
|
const uint32_t tid = tt->TThreadId / 4;
|
||||||
|
const auto entry = ( tid / 64 ) % TidCapacity;
|
||||||
|
const auto bit = tid % 64;
|
||||||
|
processThreads[entry] |= ( 1ull << bit );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SysTraceStart()
|
bool SysTraceStart()
|
||||||
@@ -114,7 +224,11 @@ bool SysTraceStart()
|
|||||||
const auto psz = sizeof( EVENT_TRACE_PROPERTIES ) + sizeof( KERNEL_LOGGER_NAME );
|
const auto psz = sizeof( EVENT_TRACE_PROPERTIES ) + sizeof( KERNEL_LOGGER_NAME );
|
||||||
s_prop = (EVENT_TRACE_PROPERTIES*)tracy_malloc( psz );
|
s_prop = (EVENT_TRACE_PROPERTIES*)tracy_malloc( psz );
|
||||||
memset( s_prop, 0, sizeof( EVENT_TRACE_PROPERTIES ) );
|
memset( s_prop, 0, sizeof( EVENT_TRACE_PROPERTIES ) );
|
||||||
|
#ifdef TRACY_SYSCALLS
|
||||||
|
s_prop->EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_DISPATCHER | EVENT_TRACE_FLAG_SYSTEMCALL | EVENT_TRACE_FLAG_THREAD;
|
||||||
|
#else
|
||||||
s_prop->EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_DISPATCHER;
|
s_prop->EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_DISPATCHER;
|
||||||
|
#endif
|
||||||
s_prop->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
s_prop->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
||||||
s_prop->Wnode.BufferSize = psz;
|
s_prop->Wnode.BufferSize = psz;
|
||||||
s_prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
s_prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
namespace tracy
|
namespace tracy
|
||||||
{
|
{
|
||||||
|
|
||||||
enum : uint32_t { ProtocolVersion = 21 };
|
enum : uint32_t { ProtocolVersion = 22 };
|
||||||
enum : uint32_t { BroadcastVersion = 0 };
|
enum : uint32_t { BroadcastVersion = 0 };
|
||||||
|
|
||||||
using lz4sz_t = uint32_t;
|
using lz4sz_t = uint32_t;
|
||||||
@@ -46,7 +46,8 @@ enum ServerQuery : uint8_t
|
|||||||
ServerQueryCallstackFrame,
|
ServerQueryCallstackFrame,
|
||||||
ServerQueryFrameName,
|
ServerQueryFrameName,
|
||||||
ServerQueryDisconnect,
|
ServerQueryDisconnect,
|
||||||
ServerQueryExternalName
|
ServerQueryExternalName,
|
||||||
|
ServerQueryCodeLocationString
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerQueryPacket
|
struct ServerQueryPacket
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ enum class QueueType : uint8_t
|
|||||||
ContextSwitch,
|
ContextSwitch,
|
||||||
ThreadWakeup,
|
ThreadWakeup,
|
||||||
GpuTime,
|
GpuTime,
|
||||||
|
SysCallEnter,
|
||||||
|
SysCallExit,
|
||||||
Terminate,
|
Terminate,
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
ThreadContext,
|
ThreadContext,
|
||||||
@@ -73,6 +75,7 @@ enum class QueueType : uint8_t
|
|||||||
FrameImageData,
|
FrameImageData,
|
||||||
ExternalName,
|
ExternalName,
|
||||||
ExternalThreadName,
|
ExternalThreadName,
|
||||||
|
CodeLocationString,
|
||||||
NUM_TYPES
|
NUM_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -330,6 +333,19 @@ struct QueueTidToPid
|
|||||||
uint64_t pid;
|
uint64_t pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QueueSysCallEnter
|
||||||
|
{
|
||||||
|
int64_t time;
|
||||||
|
uint64_t thread;
|
||||||
|
uint64_t address;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueueSysCallExit
|
||||||
|
{
|
||||||
|
int64_t time;
|
||||||
|
uint64_t thread;
|
||||||
|
};
|
||||||
|
|
||||||
struct QueueHeader
|
struct QueueHeader
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@@ -378,6 +394,8 @@ struct QueueItem
|
|||||||
QueueContextSwitch contextSwitch;
|
QueueContextSwitch contextSwitch;
|
||||||
QueueThreadWakeup threadWakeup;
|
QueueThreadWakeup threadWakeup;
|
||||||
QueueTidToPid tidToPid;
|
QueueTidToPid tidToPid;
|
||||||
|
QueueSysCallEnter sysCallEnter;
|
||||||
|
QueueSysCallExit sysCallExit;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
@@ -420,6 +438,8 @@ static const size_t QueueDataSize[] = {
|
|||||||
sizeof( QueueHeader ) + sizeof( QueueContextSwitch ),
|
sizeof( QueueHeader ) + sizeof( QueueContextSwitch ),
|
||||||
sizeof( QueueHeader ) + sizeof( QueueThreadWakeup ),
|
sizeof( QueueHeader ) + sizeof( QueueThreadWakeup ),
|
||||||
sizeof( QueueHeader ) + sizeof( QueueGpuTime ),
|
sizeof( QueueHeader ) + sizeof( QueueGpuTime ),
|
||||||
|
sizeof( QueueHeader ) + sizeof( QueueSysCallEnter ),
|
||||||
|
sizeof( QueueHeader ) + sizeof( QueueSysCallExit ),
|
||||||
// above items must be first
|
// above items must be first
|
||||||
sizeof( QueueHeader ), // terminate
|
sizeof( QueueHeader ), // terminate
|
||||||
sizeof( QueueHeader ), // keep alive
|
sizeof( QueueHeader ), // keep alive
|
||||||
@@ -453,6 +473,7 @@ static const size_t QueueDataSize[] = {
|
|||||||
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // frame image data
|
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // frame image data
|
||||||
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // external name
|
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // external name
|
||||||
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // external thread name
|
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // external thread name
|
||||||
|
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // code location string
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert( QueueItemSize == 32, "Queue item size not 32 bytes" );
|
static_assert( QueueItemSize == 32, "Queue item size not 32 bytes" );
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.26730.15
|
VisualStudioVersion = 16.0.29411.108
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tracy", "Tracy.vcxproj", "{1C736F84-08DF-4A7A-A7FB-7BA3412B8C97}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tracy", "Tracy.vcxproj", "{1C736F84-08DF-4A7A-A7FB-7BA3412B8C97}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -339,6 +339,16 @@ struct MessageData
|
|||||||
|
|
||||||
enum { MessageDataSize = sizeof( MessageData ) };
|
enum { MessageDataSize = sizeof( MessageData ) };
|
||||||
|
|
||||||
|
|
||||||
|
struct SysCall
|
||||||
|
{
|
||||||
|
int64_t start;
|
||||||
|
int64_t end;
|
||||||
|
uint64_t ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { SysCallSize = sizeof( SysCall ) };
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
|
||||||
@@ -354,6 +364,7 @@ struct ThreadData
|
|||||||
#ifndef TRACY_NO_STATISTICS
|
#ifndef TRACY_NO_STATISTICS
|
||||||
Vector<int64_t> childTimeStack;
|
Vector<int64_t> childTimeStack;
|
||||||
#endif
|
#endif
|
||||||
|
Vector<SysCall> sysCalls;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GpuCtxThreadData
|
struct GpuCtxThreadData
|
||||||
|
|||||||
@@ -2337,6 +2337,13 @@ void View::DrawZones()
|
|||||||
offset += ostep * lockDepth;
|
offset += ostep * lockDepth;
|
||||||
depth += lockDepth;
|
depth += lockDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !v->sysCalls.empty() )
|
||||||
|
{
|
||||||
|
const auto sysCallDepth = DrawSysCalls( v->sysCalls, hover, pxns, nspx, wpos, offset, yMin, yMax );
|
||||||
|
offset += ostep * sysCallDepth;
|
||||||
|
depth += sysCallDepth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offset += ostep * 0.2f;
|
offset += ostep * 0.2f;
|
||||||
|
|
||||||
@@ -4371,6 +4378,119 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int View::DrawSysCalls( const Vector<SysCall>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, float yMin, float yMax )
|
||||||
|
{
|
||||||
|
auto it = std::lower_bound( vec.begin(), vec.end(), std::max<int64_t>( 0, m_vd.zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.end < (uint64_t)r; } );
|
||||||
|
if( it == vec.end() ) return 0;
|
||||||
|
|
||||||
|
const auto zitend = std::lower_bound( it, vec.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.start < r; } );
|
||||||
|
if( it == zitend ) return 0;
|
||||||
|
if( it->end < 0 ) return 0;
|
||||||
|
|
||||||
|
const auto w = ImGui::GetWindowContentRegionWidth() - 1;
|
||||||
|
const auto ty = ImGui::GetFontSize();
|
||||||
|
const auto ostep = ty + 1;
|
||||||
|
auto draw = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
while( it < zitend )
|
||||||
|
{
|
||||||
|
const auto color = 0xFFDD7777;
|
||||||
|
const auto zsz = std::max( ( it->end - it->start ) * pxns, pxns * 0.5 );
|
||||||
|
if( zsz < MinVisSize )
|
||||||
|
{
|
||||||
|
const auto origStart = it->start;
|
||||||
|
int num = 0;
|
||||||
|
const auto px0 = ( it->start - m_vd.zvStart ) * pxns;
|
||||||
|
auto px1 = ( it->end - m_vd.zvStart ) * pxns;
|
||||||
|
auto rend = it->end;
|
||||||
|
auto nextTime = it->end + MinVisSize;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
const auto prevIt = it;
|
||||||
|
it = std::lower_bound( it, zitend, nextTime, [] ( const auto& l, const auto& r ) { return (uint64_t)l.end < (uint64_t)r; } );
|
||||||
|
if( it == prevIt ) ++it;
|
||||||
|
num += std::distance( prevIt, it );
|
||||||
|
if( it == zitend ) break;
|
||||||
|
const auto nend = it->end < 0 ? m_worker.GetLastTime() : it->end;
|
||||||
|
const auto pxnext = ( nend - m_vd.zvStart ) * pxns;
|
||||||
|
if( pxnext - px1 >= MinVisSize * 2 ) break;
|
||||||
|
px1 = pxnext;
|
||||||
|
rend = nend;
|
||||||
|
nextTime = nend + nspx;
|
||||||
|
}
|
||||||
|
draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ), color );
|
||||||
|
DrawZigZag( draw, wpos + ImVec2( 0, offset + ty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), ty/4, DarkenColor( color ) );
|
||||||
|
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ) ) )
|
||||||
|
{
|
||||||
|
if( num > 1 )
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
TextFocused( "Sys calls too small to display:", RealToString( num, true ) );
|
||||||
|
ImGui::Separator();
|
||||||
|
TextFocused( "Execution time:", TimeToString( rend - origStart ) );
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
|
||||||
|
if( ImGui::IsMouseClicked( 2 ) && rend - origStart > 0 )
|
||||||
|
{
|
||||||
|
ZoomToRange( origStart, rend );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( ImGui::IsMouseClicked( 2 ) && rend - origStart > 0 )
|
||||||
|
{
|
||||||
|
ZoomToRange( origStart, it->end );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto name = m_worker.GetCodeLocationName( it->ptr );
|
||||||
|
const auto tsz = ImGui::CalcTextSize( name );
|
||||||
|
|
||||||
|
const auto pr0 = ( it->start - m_vd.zvStart ) * pxns;
|
||||||
|
const auto pr1 = ( it->end - m_vd.zvStart ) * pxns;
|
||||||
|
const auto px0 = std::max( pr0, -10.0 );
|
||||||
|
const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } );
|
||||||
|
draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), color );
|
||||||
|
draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), HighlightColor( color ) );
|
||||||
|
if( tsz.x < zsz )
|
||||||
|
{
|
||||||
|
const auto x = ( it->start - m_vd.zvStart ) * pxns + ( ( it->end - it->start ) * pxns - tsz.x ) / 2;
|
||||||
|
if( x < 0 || x > w - tsz.x )
|
||||||
|
{
|
||||||
|
ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
|
||||||
|
DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset ), 0xFFFFFFFF, name );
|
||||||
|
ImGui::PopClipRect();
|
||||||
|
}
|
||||||
|
else if( it->start == it->end )
|
||||||
|
{
|
||||||
|
DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset ), 0xFFFFFFFF, name );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFFFFFFFF, name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
|
||||||
|
DrawTextContrast( draw, wpos + ImVec2( ( it->start - m_vd.zvStart ) * pxns, offset ), 0xFFFFFFFF, name );
|
||||||
|
ImGui::PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ) ) )
|
||||||
|
{
|
||||||
|
if( !m_zoomAnim.active && ImGui::IsMouseClicked( 2 ) )
|
||||||
|
{
|
||||||
|
ZoomToRange( it->start, it->end );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int View::DrawCpuData( int offset, double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax )
|
int View::DrawCpuData( int offset, double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax )
|
||||||
{
|
{
|
||||||
const auto w = ImGui::GetWindowContentRegionWidth() - 1;
|
const auto w = ImGui::GetWindowContentRegionWidth() - 1;
|
||||||
@@ -10508,6 +10628,7 @@ void View::DrawInfo()
|
|||||||
TextFocused( "Context switch regions:", RealToString( m_worker.GetContextSwitchCount(), true ) );
|
TextFocused( "Context switch regions:", RealToString( m_worker.GetContextSwitchCount(), true ) );
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
TextFocused( "+", RealToString( m_worker.GetContextSwitchPerCpuCount(), true ) );
|
TextFocused( "+", RealToString( m_worker.GetContextSwitchPerCpuCount(), true ) );
|
||||||
|
TextFocused( "System calls:", RealToString( m_worker.GetSysCallCount(), true ) );
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ private:
|
|||||||
int SkipGpuZoneLevel( const Vector<GpuEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift );
|
int SkipGpuZoneLevel( const Vector<GpuEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift );
|
||||||
void DrawLockHeader( uint32_t id, const LockMap& lockmap, const SourceLocation& srcloc, bool hover, ImDrawList* draw, const ImVec2& wpos, float w, float ty, float offset, uint8_t tid );
|
void DrawLockHeader( uint32_t id, const LockMap& lockmap, const SourceLocation& srcloc, bool hover, ImDrawList* draw, const ImVec2& wpos, float w, float ty, float offset, uint8_t tid );
|
||||||
int DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int offset, LockHighlight& highlight, float yMin, float yMax );
|
int DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int offset, LockHighlight& highlight, float yMin, float yMax );
|
||||||
|
int DrawSysCalls( const Vector<SysCall>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, float yMin, float yMax );
|
||||||
int DrawPlots( int offset, double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax );
|
int DrawPlots( int offset, double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax );
|
||||||
void DrawPlotPoint( const ImVec2& wpos, float x, float y, int offset, uint32_t color, bool hover, bool hasPrev, const PlotItem* item, double prev, bool merged, PlotType type, float PlotHeight );
|
void DrawPlotPoint( const ImVec2& wpos, float x, float y, int offset, uint32_t color, bool hover, bool hasPrev, const PlotItem* item, double prev, bool merged, PlotType type, float PlotHeight );
|
||||||
void DrawPlotPoint( const ImVec2& wpos, float x, float y, int offset, uint32_t color, bool hover, bool hasPrev, double val, double prev, bool merged, PlotType type, float PlotHeight );
|
void DrawPlotPoint( const ImVec2& wpos, float x, float y, int offset, uint32_t color, bool hover, bool hasPrev, double val, double prev, bool merged, PlotType type, float PlotHeight );
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ Worker::Worker( const char* addr, int port )
|
|||||||
, m_pendingSourceLocation( 0 )
|
, m_pendingSourceLocation( 0 )
|
||||||
, m_pendingCallstackFrames( 0 )
|
, m_pendingCallstackFrames( 0 )
|
||||||
, m_pendingCallstackSubframes( 0 )
|
, m_pendingCallstackSubframes( 0 )
|
||||||
|
, m_pendingCodeLocationStrings( 0 )
|
||||||
, m_callstackFrameStaging( nullptr )
|
, m_callstackFrameStaging( nullptr )
|
||||||
, m_traceVersion( CurrentVersion )
|
, m_traceVersion( CurrentVersion )
|
||||||
, m_loadTime( 0 )
|
, m_loadTime( 0 )
|
||||||
@@ -1840,6 +1841,16 @@ uint64_t Worker::GetContextSwitchPerCpuCount() const
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Worker::GetSysCallCount() const
|
||||||
|
{
|
||||||
|
uint64_t cnt = 0;
|
||||||
|
for( auto& td : m_data.threads )
|
||||||
|
{
|
||||||
|
cnt += td->sysCalls.size();
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t Worker::GetPidFromTid( uint64_t tid ) const
|
uint64_t Worker::GetPidFromTid( uint64_t tid ) const
|
||||||
{
|
{
|
||||||
auto it = m_data.tidToPid.find( tid );
|
auto it = m_data.tidToPid.find( tid );
|
||||||
@@ -2148,6 +2159,19 @@ std::pair<const char*, const char*> Worker::GetExternalName( uint64_t id ) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* Worker::GetCodeLocationName( uint64_t ptr ) const
|
||||||
|
{
|
||||||
|
const auto it = m_data.codeLocationNames.find( ptr );
|
||||||
|
if( it == m_data.codeLocationNames.end() )
|
||||||
|
{
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* Worker::GetZoneName( const SourceLocation& srcloc ) const
|
const char* Worker::GetZoneName( const SourceLocation& srcloc ) const
|
||||||
{
|
{
|
||||||
if( srcloc.name.active )
|
if( srcloc.name.active )
|
||||||
@@ -2448,7 +2472,8 @@ void Worker::Exec()
|
|||||||
{
|
{
|
||||||
if( m_pendingStrings != 0 || m_pendingThreads != 0 || m_pendingSourceLocation != 0 || m_pendingCallstackFrames != 0 ||
|
if( m_pendingStrings != 0 || m_pendingThreads != 0 || m_pendingSourceLocation != 0 || m_pendingCallstackFrames != 0 ||
|
||||||
!m_pendingCustomStrings.empty() || m_data.plots.IsPending() || m_pendingCallstackPtr != 0 ||
|
!m_pendingCustomStrings.empty() || m_data.plots.IsPending() || m_pendingCallstackPtr != 0 ||
|
||||||
m_pendingExternalNames != 0 || m_pendingCallstackSubframes != 0 || !m_pendingFrameImageData.empty() )
|
m_pendingExternalNames != 0 || m_pendingCallstackSubframes != 0 || !m_pendingFrameImageData.empty() ||
|
||||||
|
m_pendingCodeLocationStrings != 0 )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2549,6 +2574,9 @@ bool Worker::DispatchProcess( const QueueItem& ev, char*& ptr )
|
|||||||
case QueueType::ExternalThreadName:
|
case QueueType::ExternalThreadName:
|
||||||
AddExternalThreadName( ev.stringTransfer.ptr, ptr, sz );
|
AddExternalThreadName( ev.stringTransfer.ptr, ptr, sz );
|
||||||
break;
|
break;
|
||||||
|
case QueueType::CodeLocationString:
|
||||||
|
AddCodeLocationString( ev.stringTransfer.ptr, ptr, sz );
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert( false );
|
assert( false );
|
||||||
break;
|
break;
|
||||||
@@ -2846,6 +2874,16 @@ void Worker::CheckExternalName( uint64_t id )
|
|||||||
Query( ServerQueryExternalName, id );
|
Query( ServerQueryExternalName, id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Worker::CheckCodeLocationString( uint64_t id )
|
||||||
|
{
|
||||||
|
if( m_data.codeLocationNames.find( id ) != m_data.codeLocationNames.end() ) return;
|
||||||
|
|
||||||
|
m_data.codeLocationNames.emplace( id, "???" );
|
||||||
|
m_pendingCodeLocationStrings++;
|
||||||
|
|
||||||
|
Query( ServerQueryCodeLocationString, id );
|
||||||
|
}
|
||||||
|
|
||||||
void Worker::AddSourceLocation( const QueueSourceLocation& srcloc )
|
void Worker::AddSourceLocation( const QueueSourceLocation& srcloc )
|
||||||
{
|
{
|
||||||
assert( m_pendingSourceLocation > 0 );
|
assert( m_pendingSourceLocation > 0 );
|
||||||
@@ -2964,6 +3002,16 @@ void Worker::AddExternalThreadName( uint64_t ptr, char* str, size_t sz )
|
|||||||
it->second.second = sl.ptr;
|
it->second.second = sl.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Worker::AddCodeLocationString( uint64_t ptr, char* str, size_t sz )
|
||||||
|
{
|
||||||
|
assert( m_pendingCodeLocationStrings > 0 );
|
||||||
|
m_pendingCodeLocationStrings--;
|
||||||
|
auto it = m_data.codeLocationNames.find( ptr );
|
||||||
|
assert( it != m_data.codeLocationNames.end() && strcmp( it->second, "???" ) == 0 );
|
||||||
|
const auto sl = StoreString( str, sz );
|
||||||
|
it->second = sl.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
static const uint8_t DxtcIndexTable[256] = {
|
static const uint8_t DxtcIndexTable[256] = {
|
||||||
85, 87, 86, 84, 93, 95, 94, 92, 89, 91, 90, 88, 81, 83, 82, 80,
|
85, 87, 86, 84, 93, 95, 94, 92, 89, 91, 90, 88, 81, 83, 82, 80,
|
||||||
117, 119, 118, 116, 125, 127, 126, 124, 121, 123, 122, 120, 113, 115, 114, 112,
|
117, 119, 118, 116, 125, 127, 126, 124, 121, 123, 122, 120, 113, 115, 114, 112,
|
||||||
@@ -3399,6 +3447,12 @@ bool Worker::Process( const QueueItem& ev )
|
|||||||
case QueueType::TidToPid:
|
case QueueType::TidToPid:
|
||||||
ProcessTidToPid( ev.tidToPid );
|
ProcessTidToPid( ev.tidToPid );
|
||||||
break;
|
break;
|
||||||
|
case QueueType::SysCallEnter:
|
||||||
|
ProcessSysCallEnter( ev.sysCallEnter );
|
||||||
|
break;
|
||||||
|
case QueueType::SysCallExit:
|
||||||
|
ProcessSysCallExit( ev.sysCallExit );
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert( false );
|
assert( false );
|
||||||
break;
|
break;
|
||||||
@@ -4641,6 +4695,40 @@ void Worker::ProcessTidToPid( const QueueTidToPid& ev )
|
|||||||
m_data.tidToPid.emplace( ev.tid, ev.pid );
|
m_data.tidToPid.emplace( ev.tid, ev.pid );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Worker::ProcessSysCallEnter( const QueueSysCallEnter& ev )
|
||||||
|
{
|
||||||
|
auto td = RetrieveThread( ev.thread );
|
||||||
|
if( !td ) return;
|
||||||
|
if( td->sysCalls.empty() )
|
||||||
|
{
|
||||||
|
CheckCodeLocationString( ev.address );
|
||||||
|
const auto refTime = m_refTimeCtx + ev.time;
|
||||||
|
m_refTimeCtx = refTime;
|
||||||
|
const auto time = TscTime( refTime - m_data.baseTime );
|
||||||
|
td->sysCalls.push_back( SysCall { time, -1, ev.address } );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( td->sysCalls.back().end < 0 ) return;
|
||||||
|
CheckCodeLocationString( ev.address );
|
||||||
|
const auto refTime = m_refTimeCtx + ev.time;
|
||||||
|
m_refTimeCtx = refTime;
|
||||||
|
const auto time = TscTime( refTime - m_data.baseTime );
|
||||||
|
td->sysCalls.push_back_non_empty( SysCall { time, -1, ev.address } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::ProcessSysCallExit( const QueueSysCallExit& ev )
|
||||||
|
{
|
||||||
|
auto td = RetrieveThread( ev.thread );
|
||||||
|
if( !td || td->sysCalls.empty() ) return;
|
||||||
|
if( td->sysCalls.back().end >= 0 ) return;
|
||||||
|
const auto refTime = m_refTimeCtx + ev.time;
|
||||||
|
m_refTimeCtx = refTime;
|
||||||
|
const auto time = TscTime( refTime - m_data.baseTime );
|
||||||
|
td->sysCalls.back().end = time;
|
||||||
|
}
|
||||||
|
|
||||||
void Worker::MemAllocChanged( int64_t time )
|
void Worker::MemAllocChanged( int64_t time )
|
||||||
{
|
{
|
||||||
const auto val = (double)m_data.memory.usage;
|
const auto val = (double)m_data.memory.usage;
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ private:
|
|||||||
flat_hash_map<charutil::StringKey, uint32_t, charutil::StringKey::HasherPOT, charutil::StringKey::Comparator> stringMap;
|
flat_hash_map<charutil::StringKey, uint32_t, charutil::StringKey::HasherPOT, charutil::StringKey::Comparator> stringMap;
|
||||||
flat_hash_map<uint64_t, const char*, nohash<uint64_t>> threadNames;
|
flat_hash_map<uint64_t, const char*, nohash<uint64_t>> threadNames;
|
||||||
flat_hash_map<uint64_t, std::pair<const char*, const char*>, nohash<uint64_t>> externalNames;
|
flat_hash_map<uint64_t, std::pair<const char*, const char*>, nohash<uint64_t>> externalNames;
|
||||||
|
flat_hash_map<uint64_t, const char*, nohash<uint64_t>> codeLocationNames;
|
||||||
|
|
||||||
flat_hash_map<uint64_t, SourceLocation, nohash<uint64_t>> sourceLocation;
|
flat_hash_map<uint64_t, SourceLocation, nohash<uint64_t>> sourceLocation;
|
||||||
Vector<SourceLocation*> sourceLocationPayload;
|
Vector<SourceLocation*> sourceLocationPayload;
|
||||||
@@ -298,6 +299,7 @@ public:
|
|||||||
uint64_t GetContextSwitchPerCpuCount() const;
|
uint64_t GetContextSwitchPerCpuCount() const;
|
||||||
bool HasContextSwitches() const { return !m_data.ctxSwitch.empty(); }
|
bool HasContextSwitches() const { return !m_data.ctxSwitch.empty(); }
|
||||||
uint64_t GetSrcLocCount() const { return m_data.sourceLocationPayload.size() + m_data.sourceLocation.size(); }
|
uint64_t GetSrcLocCount() const { return m_data.sourceLocationPayload.size() + m_data.sourceLocation.size(); }
|
||||||
|
uint64_t GetSysCallCount() const;
|
||||||
uint64_t GetCallstackPayloadCount() const { return m_data.callstackPayload.size() - 1; }
|
uint64_t GetCallstackPayloadCount() const { return m_data.callstackPayload.size() - 1; }
|
||||||
uint64_t GetCallstackFrameCount() const { return m_data.callstackFrameMap.size(); }
|
uint64_t GetCallstackFrameCount() const { return m_data.callstackFrameMap.size(); }
|
||||||
uint32_t GetFrameImageCount() const { return (uint32_t)m_data.frameImage.size(); }
|
uint32_t GetFrameImageCount() const { return (uint32_t)m_data.frameImage.size(); }
|
||||||
@@ -354,6 +356,7 @@ public:
|
|||||||
bool IsThreadLocal( uint64_t id ) const;
|
bool IsThreadLocal( uint64_t id ) const;
|
||||||
const SourceLocation& GetSourceLocation( int16_t srcloc ) const;
|
const SourceLocation& GetSourceLocation( int16_t srcloc ) const;
|
||||||
std::pair<const char*, const char*> GetExternalName( uint64_t id ) const;
|
std::pair<const char*, const char*> GetExternalName( uint64_t id ) const;
|
||||||
|
const char* GetCodeLocationName( uint64_t ptr ) const;
|
||||||
|
|
||||||
const char* GetZoneName( const SourceLocation& srcloc ) const;
|
const char* GetZoneName( const SourceLocation& srcloc ) const;
|
||||||
const char* GetZoneName( const ZoneEvent& ev ) const;
|
const char* GetZoneName( const ZoneEvent& ev ) const;
|
||||||
@@ -459,6 +462,8 @@ private:
|
|||||||
tracy_force_inline void ProcessContextSwitch( const QueueContextSwitch& ev );
|
tracy_force_inline void ProcessContextSwitch( const QueueContextSwitch& ev );
|
||||||
tracy_force_inline void ProcessThreadWakeup( const QueueThreadWakeup& ev );
|
tracy_force_inline void ProcessThreadWakeup( const QueueThreadWakeup& ev );
|
||||||
tracy_force_inline void ProcessTidToPid( const QueueTidToPid& ev );
|
tracy_force_inline void ProcessTidToPid( const QueueTidToPid& ev );
|
||||||
|
tracy_force_inline void ProcessSysCallEnter( const QueueSysCallEnter& ev );
|
||||||
|
tracy_force_inline void ProcessSysCallExit( const QueueSysCallExit& ev );
|
||||||
|
|
||||||
tracy_force_inline void ProcessZoneBeginImpl( ZoneEvent* zone, const QueueZoneBegin& ev );
|
tracy_force_inline void ProcessZoneBeginImpl( ZoneEvent* zone, const QueueZoneBegin& ev );
|
||||||
tracy_force_inline void ProcessZoneBeginAllocSrcLocImpl( ZoneEvent* zone, const QueueZoneBegin& ev );
|
tracy_force_inline void ProcessZoneBeginAllocSrcLocImpl( ZoneEvent* zone, const QueueZoneBegin& ev );
|
||||||
@@ -526,6 +531,7 @@ private:
|
|||||||
void CheckString( uint64_t ptr );
|
void CheckString( uint64_t ptr );
|
||||||
void CheckThreadString( uint64_t id );
|
void CheckThreadString( uint64_t id );
|
||||||
void CheckExternalName( uint64_t id );
|
void CheckExternalName( uint64_t id );
|
||||||
|
void CheckCodeLocationString( uint64_t id );
|
||||||
|
|
||||||
void AddSourceLocation( const QueueSourceLocation& srcloc );
|
void AddSourceLocation( const QueueSourceLocation& srcloc );
|
||||||
void AddSourceLocationPayload( uint64_t ptr, char* data, size_t sz );
|
void AddSourceLocationPayload( uint64_t ptr, char* data, size_t sz );
|
||||||
@@ -535,6 +541,7 @@ private:
|
|||||||
void AddCustomString( uint64_t ptr, char* str, size_t sz );
|
void AddCustomString( uint64_t ptr, char* str, size_t sz );
|
||||||
void AddExternalName( uint64_t ptr, char* str, size_t sz );
|
void AddExternalName( uint64_t ptr, char* str, size_t sz );
|
||||||
void AddExternalThreadName( uint64_t ptr, char* str, size_t sz );
|
void AddExternalThreadName( uint64_t ptr, char* str, size_t sz );
|
||||||
|
void AddCodeLocationString( uint64_t ptr, char* str, size_t sz );
|
||||||
void AddFrameImageData( uint64_t ptr, char* data, size_t sz );
|
void AddFrameImageData( uint64_t ptr, char* data, size_t sz );
|
||||||
|
|
||||||
tracy_force_inline void AddCallstackPayload( uint64_t ptr, char* data, size_t sz );
|
tracy_force_inline void AddCallstackPayload( uint64_t ptr, char* data, size_t sz );
|
||||||
@@ -615,6 +622,7 @@ private:
|
|||||||
uint32_t m_pendingSourceLocation;
|
uint32_t m_pendingSourceLocation;
|
||||||
uint32_t m_pendingCallstackFrames;
|
uint32_t m_pendingCallstackFrames;
|
||||||
uint8_t m_pendingCallstackSubframes;
|
uint8_t m_pendingCallstackSubframes;
|
||||||
|
uint32_t m_pendingCodeLocationStrings;
|
||||||
|
|
||||||
CallstackFrameData* m_callstackFrameStaging;
|
CallstackFrameData* m_callstackFrameStaging;
|
||||||
uint64_t m_callstackFrameStagingPtr;
|
uint64_t m_callstackFrameStagingPtr;
|
||||||
|
|||||||
Reference in New Issue
Block a user