diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp index 683ccc8a..2fa526fa 100644 --- a/client/TracyProfiler.cpp +++ b/client/TracyProfiler.cpp @@ -575,6 +575,12 @@ static void AckServerQuery() TracyLfqCommit; } +static void AckSourceCodeNotAvailable() +{ + TracyLfqPrepare( QueueType::AckSourceCodeNotAvailable ); + TracyLfqCommit; +} + static BroadcastMessage& GetBroadcastMessage( const char* procname, size_t pnsz, int& len, int port ) { static BroadcastMessage msg; @@ -1143,6 +1149,7 @@ Profiler::Profiler() , m_deferredQueue( 64*1024 ) #endif , m_paramCallback( nullptr ) + , m_queryData( nullptr ) { assert( !s_instance ); 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 ) { assert( type == QueueType::FrameImageData || - type == QueueType::SymbolCode ); + type == QueueType::SymbolCode || + type == QueueType::SourceCode ); QueueItem item; MemWrite( &item.hdr.type, type ); @@ -2649,6 +2657,20 @@ bool Profiler::HandleServerQuery() case ServerQueryCodeLocation: SendCodeLocation( ptr ); 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: assert( false ); break; @@ -3197,6 +3219,44 @@ void Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size ) 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 ) { #ifdef TRACY_HAS_CALLSTACK diff --git a/client/TracyProfiler.hpp b/client/TracyProfiler.hpp index fb8c8077..86185f73 100644 --- a/client/TracyProfiler.hpp +++ b/client/TracyProfiler.hpp @@ -691,6 +691,7 @@ private: void HandleParameter( uint64_t payload ); void HandleSymbolQuery( uint64_t symbol ); void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size ); + void HandleSourceCodeQuery(); void CalibrateTimer(); void CalibrateDelay(); @@ -808,6 +809,9 @@ private: #endif ParameterCallback m_paramCallback; + + char* m_queryData; + char* m_queryDataPtr; }; } diff --git a/common/TracyProtocol.hpp b/common/TracyProtocol.hpp index f36aeeed..2326a7f3 100644 --- a/common/TracyProtocol.hpp +++ b/common/TracyProtocol.hpp @@ -9,7 +9,7 @@ namespace tracy 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 }; using lz4sz_t = uint32_t; @@ -51,7 +51,10 @@ enum ServerQuery : uint8_t ServerQueryParameter, ServerQuerySymbol, ServerQuerySymbolCode, - ServerQueryCodeLocation + ServerQueryCodeLocation, + ServerQuerySourceCode, + ServerQueryDataTransfer, + ServerQueryDataTransferPart }; struct ServerQueryPacket diff --git a/common/TracyQueue.hpp b/common/TracyQueue.hpp index c315e769..8f933534 100644 --- a/common/TracyQueue.hpp +++ b/common/TracyQueue.hpp @@ -85,6 +85,7 @@ enum class QueueType : uint8_t PlotConfig, ParamSetup, AckServerQueryNoop, + AckSourceCodeNotAvailable, CpuTopology, SingleStringData, SecondStringData, @@ -100,6 +101,7 @@ enum class QueueType : uint8_t ExternalName, ExternalThreadName, SymbolCode, + SourceCode, NUM_TYPES }; @@ -653,6 +655,7 @@ static constexpr size_t QueueDataSize[] = { sizeof( QueueHeader ) + sizeof( QueuePlotConfig ), sizeof( QueueHeader ) + sizeof( QueueParamSetup ), sizeof( QueueHeader ), // server query acknowledgement + sizeof( QueueHeader ), // source code not available sizeof( QueueHeader ) + sizeof( QueueCpuTopology ), sizeof( QueueHeader ), // single 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 thread name sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // symbol code + sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // source code }; static_assert( QueueItemSize == 32, "Queue item size not 32 bytes" ); diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index 1f397559..b5822536 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -2860,7 +2860,8 @@ void Worker::Exec() m_data.plots.IsPending() || m_pendingCallstackId != 0 || m_pendingExternalNames != 0 || m_pendingCallstackSubframes != 0 || m_pendingFrameImageData.image != nullptr || !m_pendingSymbols.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; } @@ -2993,9 +2994,13 @@ void Worker::DispatchFailure( const QueueItem& ev, const char*& ptr ) { ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer ); 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; memcpy( &sz, ptr, sizeof( sz ) ); ptr += sizeof( sz ) + sz; @@ -3063,6 +3068,7 @@ void Worker::DispatchFailure( const QueueItem& ev, const char*& ptr ) case QueueType::SymbolInformation: case QueueType::CodeInformation: case QueueType::AckServerQueryNoop: + case QueueType::AckSourceCodeNotAvailable: m_serverQuerySpaceLeft++; break; default: @@ -3092,13 +3098,53 @@ void Worker::QueryTerminate() 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 ) { if( ev.hdr.idx >= (int)QueueType::StringData ) { ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer ); if( ev.hdr.type == QueueType::FrameImageData || - ev.hdr.type == QueueType::SymbolCode ) + ev.hdr.type == QueueType::SymbolCode || + ev.hdr.type == QueueType::SourceCode ) { uint32_t 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 ); m_serverQuerySpaceLeft++; break; + case QueueType::SourceCode: + AddSourceCode( ptr, sz ); + m_serverQuerySpaceLeft++; + break; default: assert( false ); break; @@ -3699,6 +3749,18 @@ void Worker::AddSymbolCode( uint64_t ptr, const char* data, size_t sz ) 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 { assert( ( ( ptr & 0x3000000000000000 ) << 2 ) == ( ptr & 0xC000000000000000 ) ); @@ -4346,6 +4408,11 @@ bool Worker::Process( const QueueItem& ev ) case QueueType::AckServerQueryNoop: m_serverQuerySpaceLeft++; break; + case QueueType::AckSourceCodeNotAvailable: + assert( !m_sourceCodeQuery.empty() ); + m_sourceCodeQuery.erase( m_sourceCodeQuery.begin() ); + m_serverQuerySpaceLeft++; + break; case QueueType::CpuTopology: ProcessCpuTopology( ev.cpuTopology ); break; @@ -7430,6 +7497,11 @@ void Worker::CacheSource( const StringRef& str ) fclose( f ); 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 diff --git a/server/TracyWorker.hpp b/server/TracyWorker.hpp index 3028df54..423366d1 100644 --- a/server/TracyWorker.hpp +++ b/server/TracyWorker.hpp @@ -595,6 +595,8 @@ private: void Exec(); void Query( ServerQuery type, uint64_t data, uint32_t extra = 0 ); 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 Process( const QueueItem& ev ); @@ -752,6 +754,7 @@ private: void AddExternalThreadName( uint64_t ptr, const char* str, 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 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 AddCallstackAllocPayload( uint64_t ptr, const char* data, size_t sz ); @@ -945,6 +948,7 @@ private: size_t m_tmpBufSize = 0; unordered_flat_map m_nextCallstack; + std::vector m_sourceCodeQuery; }; }