Last-resort source code transfer from client to server.

This commit is contained in:
Bartosz Taudul 2021-02-04 00:03:25 +01:00
parent 3376620919
commit ad2062fb40
6 changed files with 154 additions and 7 deletions

View File

@ -575,6 +575,12 @@ static void AckServerQuery()
TracyLfqCommit; TracyLfqCommit;
} }
static void AckSourceCodeNotAvailable()
{
TracyLfqPrepare( QueueType::AckSourceCodeNotAvailable );
TracyLfqCommit;
}
static BroadcastMessage& GetBroadcastMessage( const char* procname, size_t pnsz, int& len, int port ) static BroadcastMessage& GetBroadcastMessage( const char* procname, size_t pnsz, int& len, int port )
{ {
static BroadcastMessage msg; static BroadcastMessage msg;
@ -1143,6 +1149,7 @@ Profiler::Profiler()
, m_deferredQueue( 64*1024 ) , m_deferredQueue( 64*1024 )
#endif #endif
, m_paramCallback( nullptr ) , m_paramCallback( nullptr )
, m_queryData( nullptr )
{ {
assert( !s_instance ); assert( !s_instance );
s_instance = this; s_instance = this;
@ -2426,7 +2433,8 @@ void Profiler::SendSecondString( const char* ptr, size_t len )
void Profiler::SendLongString( uint64_t str, const char* ptr, size_t len, QueueType type ) void Profiler::SendLongString( uint64_t str, const char* ptr, size_t len, QueueType type )
{ {
assert( type == QueueType::FrameImageData || assert( type == QueueType::FrameImageData ||
type == QueueType::SymbolCode ); type == QueueType::SymbolCode ||
type == QueueType::SourceCode );
QueueItem item; QueueItem item;
MemWrite( &item.hdr.type, type ); MemWrite( &item.hdr.type, type );
@ -2649,6 +2657,20 @@ bool Profiler::HandleServerQuery()
case ServerQueryCodeLocation: case ServerQueryCodeLocation:
SendCodeLocation( ptr ); SendCodeLocation( ptr );
break; break;
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;
default: default:
assert( false ); assert( false );
break; break;
@ -3197,6 +3219,44 @@ void Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size )
SendLongString( symbol, (const char*)symbol, size, QueueType::SymbolCode ); SendLongString( symbol, (const char*)symbol, size, QueueType::SymbolCode );
} }
void Profiler::HandleSourceCodeQuery()
{
assert( m_exectime != 0 );
assert( m_queryData );
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" );
tracy_free( m_queryData );
if( f )
{
auto ptr = (char*)tracy_malloc( st.st_size );
auto rd = fread( ptr, 1, st.st_size, f );
fclose( f );
if( rd == st.st_size )
{
SendLongString( (uint64_t)ptr, ptr, rd, QueueType::SourceCode );
}
else
{
AckSourceCodeNotAvailable();
}
tracy_free( ptr );
}
else
{
AckSourceCodeNotAvailable();
}
}
else
{
tracy_free( m_queryData );
AckSourceCodeNotAvailable();
}
m_queryData = nullptr;
}
void Profiler::SendCodeLocation( uint64_t ptr ) void Profiler::SendCodeLocation( uint64_t ptr )
{ {
#ifdef TRACY_HAS_CALLSTACK #ifdef TRACY_HAS_CALLSTACK

View File

@ -691,6 +691,7 @@ private:
void HandleParameter( uint64_t payload ); void HandleParameter( uint64_t payload );
void HandleSymbolQuery( uint64_t symbol ); void HandleSymbolQuery( uint64_t symbol );
void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size ); void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size );
void HandleSourceCodeQuery();
void CalibrateTimer(); void CalibrateTimer();
void CalibrateDelay(); void CalibrateDelay();
@ -808,6 +809,9 @@ private:
#endif #endif
ParameterCallback m_paramCallback; ParameterCallback m_paramCallback;
char* m_queryData;
char* m_queryDataPtr;
}; };
} }

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 = 45 }; enum : uint32_t { ProtocolVersion = 46 };
enum : uint16_t { BroadcastVersion = 2 }; enum : uint16_t { BroadcastVersion = 2 };
using lz4sz_t = uint32_t; using lz4sz_t = uint32_t;
@ -51,7 +51,10 @@ enum ServerQuery : uint8_t
ServerQueryParameter, ServerQueryParameter,
ServerQuerySymbol, ServerQuerySymbol,
ServerQuerySymbolCode, ServerQuerySymbolCode,
ServerQueryCodeLocation ServerQueryCodeLocation,
ServerQuerySourceCode,
ServerQueryDataTransfer,
ServerQueryDataTransferPart
}; };
struct ServerQueryPacket struct ServerQueryPacket

View File

@ -85,6 +85,7 @@ enum class QueueType : uint8_t
PlotConfig, PlotConfig,
ParamSetup, ParamSetup,
AckServerQueryNoop, AckServerQueryNoop,
AckSourceCodeNotAvailable,
CpuTopology, CpuTopology,
SingleStringData, SingleStringData,
SecondStringData, SecondStringData,
@ -100,6 +101,7 @@ enum class QueueType : uint8_t
ExternalName, ExternalName,
ExternalThreadName, ExternalThreadName,
SymbolCode, SymbolCode,
SourceCode,
NUM_TYPES NUM_TYPES
}; };
@ -653,6 +655,7 @@ static constexpr size_t QueueDataSize[] = {
sizeof( QueueHeader ) + sizeof( QueuePlotConfig ), sizeof( QueueHeader ) + sizeof( QueuePlotConfig ),
sizeof( QueueHeader ) + sizeof( QueueParamSetup ), sizeof( QueueHeader ) + sizeof( QueueParamSetup ),
sizeof( QueueHeader ), // server query acknowledgement sizeof( QueueHeader ), // server query acknowledgement
sizeof( QueueHeader ), // source code not available
sizeof( QueueHeader ) + sizeof( QueueCpuTopology ), sizeof( QueueHeader ) + sizeof( QueueCpuTopology ),
sizeof( QueueHeader ), // single string data sizeof( QueueHeader ), // single string data
sizeof( QueueHeader ), // second string data sizeof( QueueHeader ), // second string data
@ -669,6 +672,7 @@ static constexpr size_t QueueDataSize[] = {
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 ), // symbol code sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // symbol code
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // source code
}; };
static_assert( QueueItemSize == 32, "Queue item size not 32 bytes" ); static_assert( QueueItemSize == 32, "Queue item size not 32 bytes" );

View File

@ -2860,7 +2860,8 @@ void Worker::Exec()
m_data.plots.IsPending() || m_pendingCallstackId != 0 || m_pendingExternalNames != 0 || m_data.plots.IsPending() || m_pendingCallstackId != 0 || m_pendingExternalNames != 0 ||
m_pendingCallstackSubframes != 0 || m_pendingFrameImageData.image != nullptr || !m_pendingSymbols.empty() || m_pendingCallstackSubframes != 0 || m_pendingFrameImageData.image != nullptr || !m_pendingSymbols.empty() ||
!m_pendingSymbolCode.empty() || m_pendingCodeInformation != 0 || !m_serverQueryQueue.empty() || !m_pendingSymbolCode.empty() || m_pendingCodeInformation != 0 || !m_serverQueryQueue.empty() ||
m_pendingSourceLocationPayload != 0 || m_pendingSingleString.ptr != nullptr || m_pendingSecondString.ptr != nullptr ) m_pendingSourceLocationPayload != 0 || m_pendingSingleString.ptr != nullptr || m_pendingSecondString.ptr != nullptr ||
!m_sourceCodeQuery.empty() )
{ {
continue; continue;
} }
@ -2993,9 +2994,13 @@ void Worker::DispatchFailure( const QueueItem& ev, const char*& ptr )
{ {
ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer ); ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer );
if( ev.hdr.type == QueueType::FrameImageData || if( ev.hdr.type == QueueType::FrameImageData ||
ev.hdr.type == QueueType::SymbolCode ) ev.hdr.type == QueueType::SymbolCode ||
ev.hdr.type == QueueType::SourceCode )
{ {
if( ev.hdr.type == QueueType::SymbolCode ) m_serverQuerySpaceLeft++; if( ev.hdr.type == QueueType::SymbolCode || ev.hdr.type == QueueType::SourceCode )
{
m_serverQuerySpaceLeft++;
}
uint32_t sz; uint32_t sz;
memcpy( &sz, ptr, sizeof( sz ) ); memcpy( &sz, ptr, sizeof( sz ) );
ptr += sizeof( sz ) + sz; ptr += sizeof( sz ) + sz;
@ -3063,6 +3068,7 @@ void Worker::DispatchFailure( const QueueItem& ev, const char*& ptr )
case QueueType::SymbolInformation: case QueueType::SymbolInformation:
case QueueType::CodeInformation: case QueueType::CodeInformation:
case QueueType::AckServerQueryNoop: case QueueType::AckServerQueryNoop:
case QueueType::AckSourceCodeNotAvailable:
m_serverQuerySpaceLeft++; m_serverQuerySpaceLeft++;
break; break;
default: default:
@ -3092,13 +3098,53 @@ void Worker::QueryTerminate()
m_sock.Send( &query, ServerQueryPacketSize ); m_sock.Send( &query, ServerQueryPacketSize );
} }
void Worker::QuerySourceFile( const char* fn )
{
QueryDataTransfer( fn, strlen( fn ) + 1 );
Query( ServerQuerySourceCode, 0 );
}
void Worker::QueryDataTransfer( const void* ptr, size_t size )
{
Query( ServerQueryDataTransfer, size );
auto data = (const char*)ptr;
while( size > 0 )
{
uint64_t d8;
uint32_t d4;
if( size >= 12 )
{
memcpy( &d8, data, 8 );
memcpy( &d4, data+8, 4 );
data += 12;
size -= 12;
}
else if( size > 8 )
{
memcpy( &d8, data, 8 );
memset( &d4, 0, 4 );
memcpy( &d4, data+8, size-8 );
size = 0;
}
else
{
memset( &d8, 0, 8 );
memset( &d4, 0, 4 );
memcpy( &d8, data, size );
size = 0;
}
Query( ServerQueryDataTransferPart, d8, d4 );
}
}
bool Worker::DispatchProcess( const QueueItem& ev, const char*& ptr ) bool Worker::DispatchProcess( const QueueItem& ev, const char*& ptr )
{ {
if( ev.hdr.idx >= (int)QueueType::StringData ) if( ev.hdr.idx >= (int)QueueType::StringData )
{ {
ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer ); ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer );
if( ev.hdr.type == QueueType::FrameImageData || if( ev.hdr.type == QueueType::FrameImageData ||
ev.hdr.type == QueueType::SymbolCode ) ev.hdr.type == QueueType::SymbolCode ||
ev.hdr.type == QueueType::SourceCode )
{ {
uint32_t sz; uint32_t sz;
memcpy( &sz, ptr, sizeof( sz ) ); memcpy( &sz, ptr, sizeof( sz ) );
@ -3112,6 +3158,10 @@ bool Worker::DispatchProcess( const QueueItem& ev, const char*& ptr )
AddSymbolCode( ev.stringTransfer.ptr, ptr, sz ); AddSymbolCode( ev.stringTransfer.ptr, ptr, sz );
m_serverQuerySpaceLeft++; m_serverQuerySpaceLeft++;
break; break;
case QueueType::SourceCode:
AddSourceCode( ptr, sz );
m_serverQuerySpaceLeft++;
break;
default: default:
assert( false ); assert( false );
break; break;
@ -3699,6 +3749,18 @@ void Worker::AddSymbolCode( uint64_t ptr, const char* data, size_t sz )
cs_close( &handle ); cs_close( &handle );
} }
void Worker::AddSourceCode( const char* data, size_t sz )
{
assert( !m_sourceCodeQuery.empty() );
auto file = m_sourceCodeQuery.front();
m_sourceCodeQuery.erase( m_sourceCodeQuery.begin() );
if( m_data.sourceFileCache.find( file ) != m_data.sourceFileCache.end() ) return;
auto src = (char*)m_slab.AllocBig( sz );
memcpy( src, data, sz );
m_data.sourceFileCache.emplace( file, MemoryBlock{ src, uint32_t( sz ) } );
}
CallstackFrameId Worker::PackPointer( uint64_t ptr ) const CallstackFrameId Worker::PackPointer( uint64_t ptr ) const
{ {
assert( ( ( ptr & 0x3000000000000000 ) << 2 ) == ( ptr & 0xC000000000000000 ) ); assert( ( ( ptr & 0x3000000000000000 ) << 2 ) == ( ptr & 0xC000000000000000 ) );
@ -4346,6 +4408,11 @@ bool Worker::Process( const QueueItem& ev )
case QueueType::AckServerQueryNoop: case QueueType::AckServerQueryNoop:
m_serverQuerySpaceLeft++; m_serverQuerySpaceLeft++;
break; break;
case QueueType::AckSourceCodeNotAvailable:
assert( !m_sourceCodeQuery.empty() );
m_sourceCodeQuery.erase( m_sourceCodeQuery.begin() );
m_serverQuerySpaceLeft++;
break;
case QueueType::CpuTopology: case QueueType::CpuTopology:
ProcessCpuTopology( ev.cpuTopology ); ProcessCpuTopology( ev.cpuTopology );
break; break;
@ -7430,6 +7497,11 @@ void Worker::CacheSource( const StringRef& str )
fclose( f ); fclose( f );
m_data.sourceFileCache.emplace( file, MemoryBlock{ src, uint32_t( sz ) } ); m_data.sourceFileCache.emplace( file, MemoryBlock{ src, uint32_t( sz ) } );
} }
else if( m_executableTime != 0 )
{
m_sourceCodeQuery.emplace_back( file );
QuerySourceFile( file );
}
} }
uint64_t Worker::GetSourceFileCacheSize() const uint64_t Worker::GetSourceFileCacheSize() const

View File

@ -595,6 +595,8 @@ private:
void Exec(); void Exec();
void Query( ServerQuery type, uint64_t data, uint32_t extra = 0 ); void Query( ServerQuery type, uint64_t data, uint32_t extra = 0 );
void QueryTerminate(); void QueryTerminate();
void QuerySourceFile( const char* fn );
void QueryDataTransfer( const void* ptr, size_t size );
tracy_force_inline bool DispatchProcess( const QueueItem& ev, const char*& ptr ); tracy_force_inline bool DispatchProcess( const QueueItem& ev, const char*& ptr );
tracy_force_inline bool Process( const QueueItem& ev ); tracy_force_inline bool Process( const QueueItem& ev );
@ -752,6 +754,7 @@ private:
void AddExternalThreadName( uint64_t ptr, const char* str, size_t sz ); void AddExternalThreadName( uint64_t ptr, const char* str, size_t sz );
void AddFrameImageData( uint64_t ptr, const char* data, size_t sz ); void AddFrameImageData( uint64_t ptr, const char* data, size_t sz );
void AddSymbolCode( uint64_t ptr, const char* data, size_t sz ); void AddSymbolCode( uint64_t ptr, const char* data, size_t sz );
void AddSourceCode( const char* data, size_t sz );
tracy_force_inline void AddCallstackPayload( uint64_t ptr, const char* data, size_t sz ); tracy_force_inline void AddCallstackPayload( uint64_t ptr, const char* data, size_t sz );
tracy_force_inline void AddCallstackAllocPayload( uint64_t ptr, const char* data, size_t sz ); tracy_force_inline void AddCallstackAllocPayload( uint64_t ptr, const char* data, size_t sz );
@ -945,6 +948,7 @@ private:
size_t m_tmpBufSize = 0; size_t m_tmpBufSize = 0;
unordered_flat_map<uint64_t, uint32_t> m_nextCallstack; unordered_flat_map<uint64_t, uint32_t> m_nextCallstack;
std::vector<const char*> m_sourceCodeQuery;
}; };
} }