Decouple source code retrieval from the profiler thread.

This will prevent apparent freezes of the profiler when debuginfod queries are
made.
This commit is contained in:
Bartosz Taudul 2022-10-13 00:27:28 +02:00
parent 6ca1c98655
commit a85c0e18d2
No known key found for this signature in database
GPG Key ID: B7FE2008B7575DF3
4 changed files with 69 additions and 37 deletions

View File

@ -709,14 +709,6 @@ void Profiler::AckServerQuery()
AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::AckServerQueryNoop] ); AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::AckServerQueryNoop] );
} }
void Profiler::AckSourceCodeNotAvailable()
{
QueueItem item;
MemWrite( &item.hdr.type, QueueType::AckSourceCodeNotAvailable );
NeedDataSize( QueueDataSize[(int)QueueType::AckSourceCodeNotAvailable] );
AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::AckSourceCodeNotAvailable] );
}
void Profiler::AckSymbolCodeNotAvailable() void Profiler::AckSymbolCodeNotAvailable()
{ {
QueueItem item; QueueItem item;
@ -2202,6 +2194,10 @@ static void FreeAssociatedMemory( const QueueItem& item )
tracy_free_fast( (void*)ptr ); tracy_free_fast( (void*)ptr );
break; break;
#endif #endif
case QueueType::SourceCodeMetadata:
ptr = MemRead<uint64_t>( &item.sourceCodeMetadata.ptr );
tracy_free( (void*)ptr );
break;
default: default:
break; break;
} }
@ -2496,6 +2492,15 @@ Profiler::DequeueStatus Profiler::Dequeue( moodycamel::ConsumerToken& token )
continue; continue;
} }
#endif #endif
case QueueType::SourceCodeMetadata:
{
auto ptr = (const char*)MemRead<uint64_t>( &item->sourceCodeMetadata.ptr );
auto size = MemRead<uint32_t>( &item->sourceCodeMetadata.size );
SendLongString( (uint64_t)ptr, ptr, size, QueueType::SourceCode );
tracy_free_fast( (void*)ptr );
++item;
continue;
}
default: default:
assert( false ); assert( false );
break; break;
@ -3162,6 +3167,15 @@ void Profiler::QueueKernelCode( uint64_t symbol, uint32_t size )
#endif #endif
} }
void Profiler::QueueSourceCodeQuery()
{
assert( m_exectime != 0 );
assert( m_queryData );
m_symbolQueue.emplace( SymbolQueueItem { SymbolQueueItemType::SourceCode, uint64_t( m_queryData ), uint64_t( m_queryImage ) } );
m_queryData = nullptr;
m_queryImage = nullptr;
}
#ifdef TRACY_HAS_CALLSTACK #ifdef TRACY_HAS_CALLSTACK
void Profiler::HandleSymbolQueueItem( const SymbolQueueItem& si ) void Profiler::HandleSymbolQueueItem( const SymbolQueueItem& si )
{ {
@ -3249,6 +3263,9 @@ void Profiler::HandleSymbolQueueItem( const SymbolQueueItem& si )
TracyLfqCommit; TracyLfqCommit;
break; break;
} }
case SymbolQueueItemType::SourceCode:
HandleSourceCodeQuery( (char*)si.ptr, (char*)si.extra );
break;
default: default:
assert( false ); assert( false );
break; break;
@ -3365,7 +3382,7 @@ bool Profiler::HandleServerQuery()
break; break;
#endif #endif
case ServerQuerySourceCode: case ServerQuerySourceCode:
HandleSourceCodeQuery(); QueueSourceCodeQuery();
break; break;
case ServerQueryDataTransfer: case ServerQueryDataTransfer:
if( m_queryData ) if( m_queryData )
@ -3791,19 +3808,15 @@ void Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size )
} }
} }
void Profiler::HandleSourceCodeQuery() void Profiler::HandleSourceCodeQuery( char* data, char* image )
{ {
assert( m_exectime != 0 );
assert( m_queryData );
InitRpmalloc();
bool ok = false; bool ok = false;
struct stat st; struct stat st;
if( stat( m_queryData, &st ) == 0 && (uint64_t)st.st_mtime < m_exectime ) if( stat( data, &st ) == 0 && (uint64_t)st.st_mtime < m_exectime )
{ {
if( st.st_size < ( TargetFrameSize - 16 ) ) if( st.st_size < ( TargetFrameSize - 16 ) )
{ {
FILE* f = fopen( m_queryData, "rb" ); FILE* f = fopen( data, "rb" );
if( f ) if( f )
{ {
auto ptr = (char*)tracy_malloc_fast( st.st_size ); auto ptr = (char*)tracy_malloc_fast( st.st_size );
@ -3811,22 +3824,25 @@ void Profiler::HandleSourceCodeQuery()
fclose( f ); fclose( f );
if( rd == (size_t)st.st_size ) if( rd == (size_t)st.st_size )
{ {
SendLongString( (uint64_t)ptr, ptr, rd, QueueType::SourceCode ); TracyLfqPrepare( QueueType::SourceCodeMetadata );
MemWrite( &item->sourceCodeMetadata.ptr, (uint64_t)ptr );
MemWrite( &item->sourceCodeMetadata.size, (uint32_t)rd );
TracyLfqCommit;
ok = true; ok = true;
} }
tracy_free_fast( ptr );
} }
} }
} }
#ifdef TRACY_DEBUGINFOD #ifdef TRACY_DEBUGINFOD
else if( m_queryImage && m_queryData[0] == '/' ) else if( image && data[0] == '/' )
{ {
size_t size; size_t size;
auto buildid = GetBuildIdForImage( m_queryImage, size ); auto buildid = GetBuildIdForImage( image, size );
if( buildid ) if( buildid )
{ {
auto d = debuginfod_find_source( GetDebuginfodClient(), buildid, size, m_queryData, nullptr ); auto d = debuginfod_find_source( GetDebuginfodClient(), buildid, size, data, nullptr );
TracyDebug( "DebugInfo source query: %s, fn: %s, image: %s\n", d >= 0 ? " ok " : "fail", m_queryData, m_queryImage ); TracyDebug( "DebugInfo source query: %s, fn: %s, image: %s\n", d >= 0 ? " ok " : "fail", data, image );
if( d >= 0 ) if( d >= 0 )
{ {
struct stat st; struct stat st;
@ -3838,10 +3854,12 @@ void Profiler::HandleSourceCodeQuery()
auto rd = read( d, ptr, st.st_size ); auto rd = read( d, ptr, st.st_size );
if( rd == (size_t)st.st_size ) if( rd == (size_t)st.st_size )
{ {
SendLongString( (uint64_t)ptr, ptr, rd, QueueType::SourceCode ); TracyLfqPrepare( QueueType::SourceCodeMetadata );
MemWrite( &item->sourceCodeMetadata.ptr, (uint64_t)ptr );
MemWrite( &item->sourceCodeMetadata.size, (uint32_t)rd );
TracyLfqCommit;
ok = true; ok = true;
} }
tracy_free_fast( ptr );
} }
close( d ); close( d );
} }
@ -3849,31 +3867,35 @@ void Profiler::HandleSourceCodeQuery()
} }
else else
{ {
TracyDebug( "DebugInfo invalid query fn: %s, image: %s\n", m_queryData, m_queryImage ); TracyDebug( "DebugInfo invalid query fn: %s, image: %s\n", data, image );
} }
#endif #endif
if( !ok && m_sourceCallback ) if( !ok && m_sourceCallback )
{ {
size_t sz; size_t sz;
char* ptr = m_sourceCallback( m_sourceCallbackData, m_queryData, sz ); char* ptr = m_sourceCallback( m_sourceCallbackData, data, sz );
if( ptr ) if( ptr )
{ {
if( sz < ( TargetFrameSize - 16 ) ) if( sz < ( TargetFrameSize - 16 ) )
{ {
SendLongString( (uint64_t)ptr, ptr, sz, QueueType::SourceCode ); TracyLfqPrepare( QueueType::SourceCodeMetadata );
MemWrite( &item->sourceCodeMetadata.ptr, (uint64_t)ptr );
MemWrite( &item->sourceCodeMetadata.size, (uint32_t)sz );
TracyLfqCommit;
ok = true; ok = true;
} }
tracy_free_fast( ptr );
} }
} }
if( !ok ) AckSourceCodeNotAvailable(); if( !ok )
{
TracyLfqPrepare( QueueType::AckSourceCodeNotAvailable );
TracyLfqCommit;
}
tracy_free_fast( m_queryData ); tracy_free_fast( data );
tracy_free_fast( m_queryImage ); tracy_free_fast( image );
m_queryData = nullptr;
m_queryImage = nullptr;
} }
#if defined _WIN32 && defined TRACY_TIMER_QPC #if defined _WIN32 && defined TRACY_TIMER_QPC

View File

@ -168,7 +168,8 @@ class Profiler
CallstackFrame, CallstackFrame,
SymbolQuery, SymbolQuery,
ExternalName, ExternalName,
KernelCode KernelCode,
SourceCode
}; };
struct SymbolQueueItem struct SymbolQueueItem
@ -807,15 +808,15 @@ private:
void QueueSymbolQuery( uint64_t symbol ); void QueueSymbolQuery( uint64_t symbol );
void QueueExternalName( uint64_t ptr ); void QueueExternalName( uint64_t ptr );
void QueueKernelCode( uint64_t symbol, uint32_t size ); void QueueKernelCode( uint64_t symbol, uint32_t size );
void QueueSourceCodeQuery();
bool HandleServerQuery(); bool HandleServerQuery();
void HandleDisconnect(); void HandleDisconnect();
void HandleParameter( uint64_t payload ); void HandleParameter( uint64_t payload );
void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size ); void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size );
void HandleSourceCodeQuery(); void HandleSourceCodeQuery( char* data, char* image );
void AckServerQuery(); void AckServerQuery();
void AckSourceCodeNotAvailable();
void AckSymbolCodeNotAvailable(); void AckSymbolCodeNotAvailable();
void CalibrateTimer(); void CalibrateTimer();

View File

@ -9,7 +9,7 @@ namespace tracy
constexpr unsigned Lz4CompressBound( unsigned isize ) { return isize + ( isize / 255 ) + 16; } constexpr unsigned Lz4CompressBound( unsigned isize ) { return isize + ( isize / 255 ) + 16; }
enum : uint32_t { ProtocolVersion = 61 }; enum : uint32_t { ProtocolVersion = 62 };
enum : uint16_t { BroadcastVersion = 3 }; enum : uint16_t { BroadcastVersion = 3 };
using lz4sz_t = uint32_t; using lz4sz_t = uint32_t;

View File

@ -63,6 +63,7 @@ enum class QueueType : uint8_t
SymbolInformation, SymbolInformation,
ExternalNameMetadata, ExternalNameMetadata,
SymbolCodeMetadata, SymbolCodeMetadata,
SourceCodeMetadata,
FiberEnter, FiberEnter,
FiberLeave, FiberLeave,
Terminate, Terminate,
@ -635,6 +636,12 @@ struct QueueSymbolCodeMetadata
uint32_t size; uint32_t size;
}; };
struct QueueSourceCodeMetadata
{
uint64_t ptr;
uint32_t size;
};
struct QueueHeader struct QueueHeader
{ {
union union
@ -725,6 +732,7 @@ struct QueueItem
QueueCpuTopology cpuTopology; QueueCpuTopology cpuTopology;
QueueExternalNameMetadata externalNameMetadata; QueueExternalNameMetadata externalNameMetadata;
QueueSymbolCodeMetadata symbolCodeMetadata; QueueSymbolCodeMetadata symbolCodeMetadata;
QueueSourceCodeMetadata sourceCodeMetadata;
QueueFiberEnter fiberEnter; QueueFiberEnter fiberEnter;
QueueFiberLeave fiberLeave; QueueFiberLeave fiberLeave;
}; };
@ -789,6 +797,7 @@ static constexpr size_t QueueDataSize[] = {
sizeof( QueueHeader ) + sizeof( QueueSymbolInformation ), sizeof( QueueHeader ) + sizeof( QueueSymbolInformation ),
sizeof( QueueHeader ), // ExternalNameMetadata - not for wire transfer sizeof( QueueHeader ), // ExternalNameMetadata - not for wire transfer
sizeof( QueueHeader ), // SymbolCodeMetadata - not for wire transfer sizeof( QueueHeader ), // SymbolCodeMetadata - not for wire transfer
sizeof( QueueHeader ), // SourceCodeMetadata - not for wire transfer
sizeof( QueueHeader ) + sizeof( QueueFiberEnter ), sizeof( QueueHeader ) + sizeof( QueueFiberEnter ),
sizeof( QueueHeader ) + sizeof( QueueFiberLeave ), sizeof( QueueHeader ) + sizeof( QueueFiberLeave ),
// above items must be first // above items must be first