diff --git a/client/TracyCallstack.cpp b/client/TracyCallstack.cpp index d81e729c..0d32390a 100644 --- a/client/TracyCallstack.cpp +++ b/client/TracyCallstack.cpp @@ -37,9 +37,9 @@ void InitCallstack() SymSetOptions( SYMOPT_LOAD_LINES ); } -CallstackEntry DecodeCallstackPtr( uint64_t ptr ) +CallstackEntryData DecodeCallstackPtr( uint64_t ptr ) { - CallstackEntry ret; + static CallstackEntry ret; const auto proc = GetCurrentProcess(); @@ -82,7 +82,7 @@ CallstackEntry DecodeCallstackPtr( uint64_t ptr ) ret.file = file; - return ret; + return { &ret, 1 }; } #elif TRACY_HAS_CALLSTACK >= 2 @@ -219,12 +219,12 @@ static void CallstackErrorCb( void* data, const char* msg, int errnum ) cb_num = 1; } -CallstackEntry DecodeCallstackPtr( uint64_t ptr ) +CallstackEntryData DecodeCallstackPtr( uint64_t ptr ) { cb_num = 0; backtrace_pcinfo( cb_bts, ptr, CallstackDataCb, CallstackErrorCb, nullptr ); assert( cb_num == 1 ); - return cb_data[0]; + return { cb_data, cb_num }; } #endif diff --git a/client/TracyCallstack.hpp b/client/TracyCallstack.hpp index 6e014580..8b61c5ec 100644 --- a/client/TracyCallstack.hpp +++ b/client/TracyCallstack.hpp @@ -41,7 +41,13 @@ struct CallstackEntry uint32_t line; }; -CallstackEntry DecodeCallstackPtr( uint64_t ptr ); +struct CallstackEntryData +{ + const CallstackEntry* data; + uint8_t size; +}; + +CallstackEntryData DecodeCallstackPtr( uint64_t ptr ); void InitCallstack(); #if TRACY_HAS_CALLSTACK == 1 diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp index 71e3dfab..04432cfc 100644 --- a/client/TracyProfiler.cpp +++ b/client/TracyProfiler.cpp @@ -1487,22 +1487,35 @@ void Profiler::SendCallstackPayload( uint64_t _ptr ) void Profiler::SendCallstackFrame( uint64_t ptr ) { #ifdef TRACY_HAS_CALLSTACK - auto frame = DecodeCallstackPtr( ptr ); + const auto frameData = DecodeCallstackPtr( ptr ); - SendString( uint64_t( frame.name ), frame.name, QueueType::CustomStringData ); - SendString( uint64_t( frame.file ), frame.file, QueueType::CustomStringData ); + { + QueueItem item; + MemWrite( &item.hdr.type, QueueType::CallstackFrameSize ); + MemWrite( &item.callstackFrameSize.ptr, ptr ); + MemWrite( &item.callstackFrameSize.size, frameData.size ); - QueueItem item; - MemWrite( &item.hdr.type, QueueType::CallstackFrame ); - MemWrite( &item.callstackFrame.ptr, ptr ); - MemWrite( &item.callstackFrame.name, (uint64_t)frame.name ); - MemWrite( &item.callstackFrame.file, (uint64_t)frame.file ); - MemWrite( &item.callstackFrame.line, frame.line ); + AppendData( &item, QueueDataSize[(int)QueueType::CallstackFrameSize] ); + } - AppendData( &item, QueueDataSize[(int)QueueType::CallstackFrame] ); + for( uint8_t i=0; i& trace, const Worker& worker, B } for( int8_t j=1; jdata; ImGui::TextDisabled( "%s", worker.GetString( frame->name ) ); ImGui::SameLine(); ImGui::Spacing(); @@ -3672,7 +3673,8 @@ void DrawZoneTrace( T zone, const std::vector& trace, const Worker& worker, B const auto csz = cs.size(); for( uint8_t i=1; idata; ImGui::TextDisabled( "%s", worker.GetString( frame->name ) ); ImGui::SameLine(); ImGui::Spacing(); @@ -5559,7 +5561,7 @@ void View::DrawFindZone() else { auto& callstack = m_worker.GetCallstack( v->first ); - hdrString = m_worker.GetString( m_worker.GetCallstackFrame( *callstack.begin() )->name ); + hdrString = m_worker.GetString( m_worker.GetCallstackFrame( *callstack.begin() )->data[0].name ); } break; default: @@ -6463,14 +6465,11 @@ void View::DrawCallstackWindow() ImGui::NextColumn(); int fidx = 0; + int bidx = 0; for( auto& entry : cs ) { - ImGui::Separator(); - ImGui::Text( "%i", fidx++ ); - ImGui::NextColumn(); - - auto frame = m_worker.GetCallstackFrame( entry ); - if( !frame ) + auto frameData = m_worker.GetCallstackFrame( entry ); + if( !frameData ) { char buf[32]; sprintf( buf, "%p", (void*)entry ); @@ -6484,64 +6483,81 @@ void View::DrawCallstackWindow() } else { - auto txt = m_worker.GetString( frame->name ); - ImGui::TextWrapped( "%s", txt ); - if( ImGui::IsItemClicked() ) + for( uint8_t f=0; fsize; f++ ) { - ImGui::SetClipboardText( txt ); - } - ImGui::NextColumn(); - ImGui::PushTextWrapPos( 0.0f ); - float indentVal = 0.f; - if( m_callstackBuzzAnim.Match( fidx ) ) - { - const auto time = m_callstackBuzzAnim.Time(); - indentVal = sin( time * 60.f ) * 10.f * time; - ImGui::Indent( indentVal ); - } - txt = m_worker.GetString( frame->file ); - if( m_showCallstackFrameAddress ) - { - ImGui::TextDisabled( "0x%" PRIx64, entry ); - if( ImGui::IsItemClicked() ) + const auto& frame = frameData->data[f]; + bidx++; + + ImGui::Separator(); + if( f == 0 ) { - char tmp[32]; - sprintf( tmp, "0x%" PRIx64, entry ); - ImGui::SetClipboardText( tmp ); - } - } - else - { - if( frame->line == 0 ) - { - ImGui::TextDisabled( "%s", txt ); + ImGui::Text( "%i", fidx++ ); } else { - ImGui::TextDisabled( "%s:%i", txt, frame->line ); + ImGui::TextDisabled( "inline" ); } + ImGui::NextColumn(); + + auto txt = m_worker.GetString( frame.name ); + ImGui::TextWrapped( "%s", txt ); if( ImGui::IsItemClicked() ) { ImGui::SetClipboardText( txt ); } - } - if( ImGui::IsItemClicked( 1 ) ) - { - if( FileExists( txt ) ) + ImGui::NextColumn(); + ImGui::PushTextWrapPos( 0.0f ); + float indentVal = 0.f; + if( m_callstackBuzzAnim.Match( bidx ) ) { - SetTextEditorFile( txt, frame->line ); + const auto time = m_callstackBuzzAnim.Time(); + indentVal = sin( time * 60.f ) * 10.f * time; + ImGui::Indent( indentVal ); + } + txt = m_worker.GetString( frame.file ); + if( m_showCallstackFrameAddress ) + { + ImGui::TextDisabled( "0x%" PRIx64, entry ); + if( ImGui::IsItemClicked() ) + { + char tmp[32]; + sprintf( tmp, "0x%" PRIx64, entry ); + ImGui::SetClipboardText( tmp ); + } } else { - m_callstackBuzzAnim.Enable( fidx, 0.5f ); + if( frame.line == 0 ) + { + ImGui::TextDisabled( "%s", txt ); + } + else + { + ImGui::TextDisabled( "%s:%i", txt, frame.line ); + } + if( ImGui::IsItemClicked() ) + { + ImGui::SetClipboardText( txt ); + } } + if( ImGui::IsItemClicked( 1 ) ) + { + if( FileExists( txt ) ) + { + SetTextEditorFile( txt, frame.line ); + } + else + { + m_callstackBuzzAnim.Enable( bidx, 0.5f ); + } + } + if( indentVal != 0.f ) + { + ImGui::Unindent( indentVal ); + } + ImGui::PopTextWrapPos(); + ImGui::NextColumn(); } - if( indentVal != 0.f ) - { - ImGui::Unindent( indentVal ); - } - ImGui::PopTextWrapPos(); - ImGui::NextColumn(); } } @@ -7910,7 +7926,7 @@ void View::DrawFrameTreeLevel( std::vector& tree, int& idx ) for( auto& v : tree ) { idx++; - auto frame = m_worker.GetCallstackFrame( v.frame ); + auto frame = m_worker.GetCallstackFrame( v.frame )->data; bool expand = false; if( v.children.empty() ) { @@ -8454,7 +8470,7 @@ void View::CallstackTooltip( uint32_t idx ) } else { - ImGui::Text( "%s", m_worker.GetString( frame->name ) ); + ImGui::Text( "%s", m_worker.GetString( frame->data->name ) ); } } ImGui::EndTooltip(); diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index e9961c39..59f64159 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #if ( defined _MSC_VER && _MSVC_LANG >= 201703L ) || __cplusplus >= 201703L # if __has_include() @@ -217,6 +218,8 @@ Worker::Worker( const char* addr ) , m_pendingThreads( 0 ) , m_pendingSourceLocation( 0 ) , m_pendingCallstackFrames( 0 ) + , m_pendingCallstackSubframes( 0 ) + , m_callstackFrameStaging( nullptr ) , m_traceVersion( CurrentVersion ) , m_loadTime( 0 ) { @@ -1020,17 +1023,41 @@ Worker::Worker( FileRead& f, EventType::Type eventMask ) m_data.callstackPayload.push_back_no_space_check( arr ); } - f.Read( sz ); - m_data.callstackFrameMap.reserve( sz ); - for( uint64_t i=0; i= FileVersion( 0, 4, 3 ) ) { - uint64_t ptr; - f.Read( ptr ); + f.Read( sz ); + m_data.callstackFrameMap.reserve( sz ); + for( uint64_t i=0; i(); - f.Read( frame, sizeof( CallstackFrame ) ); + auto frameData = m_slab.Alloc(); + f.Read( frameData->size ); - m_data.callstackFrameMap.emplace( ptr, frame ); + frameData->data = m_slab.Alloc( frameData->size ); + f.Read( frameData->data, sizeof( CallstackFrame ) * frameData->size ); + + m_data.callstackFrameMap.emplace( ptr, frameData ); + } + } + else + { + f.Read( sz ); + m_data.callstackFrameMap.reserve( sz ); + for( uint64_t i=0; i(); + frameData->size = 1; + + frameData->data = m_slab.Alloc(); + f.Read( frameData->data, sizeof( CallstackFrame ) ); + + m_data.callstackFrameMap.emplace( ptr, frameData ); + } } finishLoading: @@ -1201,7 +1228,7 @@ std::pair Worker::GetFrameRange( const FrameData& fd, int64_t from, i return std::make_pair( zbegin, zend ); } -const CallstackFrame* Worker::GetCallstackFrame( uint64_t ptr ) const +const CallstackFrameData* Worker::GetCallstackFrame( uint64_t ptr ) const { auto it = m_data.callstackFrameMap.find( ptr ); if( it == m_data.callstackFrameMap.end() ) @@ -1582,7 +1609,7 @@ void Worker::Exec() if( m_terminate ) { if( m_pendingStrings != 0 || m_pendingThreads != 0 || m_pendingSourceLocation != 0 || m_pendingCallstackFrames != 0 || - !m_pendingCustomStrings.empty() || m_data.plots.IsPending() || !m_pendingCallstacks.empty() ) + !m_pendingCustomStrings.empty() || m_data.plots.IsPending() || !m_pendingCallstacks.empty() || m_pendingCallstackSubframes != 0 ) { continue; } @@ -2197,6 +2224,9 @@ bool Worker::Process( const QueueItem& ev ) case QueueType::Callstack: ProcessCallstack( ev.callstack ); break; + case QueueType::CallstackFrameSize: + ProcessCallstackFrameSize( ev.callstackFrameSize ); + break; case QueueType::CallstackFrame: ProcessCallstackFrame( ev.callstackFrame ); break; @@ -2961,28 +2991,53 @@ void Worker::ProcessCallstack( const QueueCallstack& ev ) m_pendingCallstacks.erase( it ); } -void Worker::ProcessCallstackFrame( const QueueCallstackFrame& ev ) +void Worker::ProcessCallstackFrameSize( const QueueCallstackFrameSize& ev ) { + assert( !m_callstackFrameStaging ); + assert( m_pendingCallstackSubframes == 0 ); assert( m_pendingCallstackFrames > 0 ); m_pendingCallstackFrames--; + m_pendingCallstackSubframes = ev.size; + // Frames may be duplicated due to recursion auto fmit = m_data.callstackFrameMap.find( ev.ptr ); + if( fmit == m_data.callstackFrameMap.end() ) + { + m_callstackFrameStaging = m_slab.Alloc(); + m_callstackFrameStaging->size = ev.size; + m_callstackFrameStaging->data = m_slab.Alloc( ev.size ); + + m_callstackFrameStagingPtr = ev.ptr; + } +} + +void Worker::ProcessCallstackFrame( const QueueCallstackFrame& ev ) +{ + assert( m_pendingCallstackSubframes > 0 ); + auto nit = m_pendingCustomStrings.find( ev.name ); assert( nit != m_pendingCustomStrings.end() ); auto fit = m_pendingCustomStrings.find( ev.file ); assert( fit != m_pendingCustomStrings.end() ); - // Frames may be duplicated due to recursion - if( fmit == m_data.callstackFrameMap.end() ) + if( m_callstackFrameStaging ) { - CheckString( ev.file ); + const auto idx = m_callstackFrameStaging->size - m_pendingCallstackSubframes; - auto frame = m_slab.Alloc(); - frame->name = StringIdx( nit->second.idx ); - frame->file = StringIdx( fit->second.idx ); - frame->line = ev.line; + m_callstackFrameStaging->data[idx].name = StringIdx( nit->second.idx ); + m_callstackFrameStaging->data[idx].file = StringIdx( fit->second.idx ); + m_callstackFrameStaging->data[idx].line = ev.line; - m_data.callstackFrameMap.emplace( ev.ptr, frame ); + if( --m_pendingCallstackSubframes == 0 ) + { + assert( m_data.callstackFrameMap.find( m_callstackFrameStagingPtr ) == m_data.callstackFrameMap.end() ); + m_data.callstackFrameMap.emplace( m_callstackFrameStagingPtr, m_callstackFrameStaging ); + m_callstackFrameStaging = nullptr; + } + } + else + { + m_pendingCallstackSubframes--; } m_pendingCustomStrings.erase( nit ); @@ -3622,7 +3677,8 @@ void Worker::Write( FileWrite& f ) for( auto& frame : m_data.callstackFrameMap ) { f.Write( &frame.first, sizeof( uint64_t ) ); - f.Write( frame.second, sizeof( CallstackFrame ) ); + f.Write( &frame.second->size, sizeof( frame.second->size ) ); + f.Write( frame.second->data, sizeof( CallstackFrame ) * frame.second->size ); } } diff --git a/server/TracyWorker.hpp b/server/TracyWorker.hpp index b6d1297f..f1712e39 100644 --- a/server/TracyWorker.hpp +++ b/server/TracyWorker.hpp @@ -130,7 +130,7 @@ private: flat_hash_map*, uint32_t, VarArrayHasherPOT, VarArrayComparator> callstackMap; Vector*> callstackPayload; - flat_hash_map callstackFrameMap; + flat_hash_map callstackFrameMap; std::map lockMap; @@ -229,7 +229,7 @@ public: const MemData& GetMemData() const { return m_data.memory; } const VarArray& GetCallstack( uint32_t idx ) const { return *m_data.callstackPayload[idx]; } - const CallstackFrame* GetCallstackFrame( uint64_t ptr ) const; + const CallstackFrameData* GetCallstackFrame( uint64_t ptr ) const; const CrashEvent& GetCrashEvent() const { return m_data.m_crashEvent; } @@ -331,6 +331,7 @@ private: tracy_force_inline void ProcessMemFreeCallstack( const QueueMemFree& ev ); tracy_force_inline void ProcessCallstackMemory( const QueueCallstackMemory& ev ); tracy_force_inline void ProcessCallstack( const QueueCallstack& ev ); + tracy_force_inline void ProcessCallstackFrameSize( const QueueCallstackFrameSize& ev ); tracy_force_inline void ProcessCallstackFrame( const QueueCallstackFrame& ev ); tracy_force_inline void ProcessCrashReport( const QueueCrashReport& ev ); @@ -438,6 +439,10 @@ private: uint32_t m_pendingThreads; uint32_t m_pendingSourceLocation; uint32_t m_pendingCallstackFrames; + uint8_t m_pendingCallstackSubframes; + + CallstackFrameData* m_callstackFrameStaging; + uint64_t m_callstackFrameStagingPtr; uint64_t m_lastMemActionCallstack; bool m_lastMemActionWasAlloc;