diff --git a/AUTHORS b/AUTHORS index c4029fdc..ebb43782 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Bartosz Taudul Kamil Klimek +Bartosz Szreder diff --git a/common/TracySocket.cpp b/common/TracySocket.cpp index f6dc63f7..96fb9e44 100644 --- a/common/TracySocket.cpp +++ b/common/TracySocket.cpp @@ -154,7 +154,7 @@ int Socket::Recv( void* _buf, int len, const timeval* tv ) } } -bool Socket::Read( void* _buf, int len, const timeval* tv, bool(*exitCb)() ) +bool Socket::Read( void* _buf, int len, const timeval* tv, std::function< bool() > exitCb ) { auto buf = (char*)_buf; diff --git a/common/TracySocket.hpp b/common/TracySocket.hpp index 4675620b..8eafa603 100644 --- a/common/TracySocket.hpp +++ b/common/TracySocket.hpp @@ -1,6 +1,8 @@ #ifndef __TRACYSOCKET_HPP__ #define __TRACYSOCKET_HPP__ +#include + struct timeval; namespace tracy @@ -19,7 +21,7 @@ public: int Send( const void* buf, int len ); int Recv( void* buf, int len, const timeval* tv ); - bool Read( void* buf, int len, const timeval* tv, bool(*exitCb)() ); + bool Read( void* buf, int len, const timeval* tv, std::function< bool() > exitCb ); bool HasData(); Socket( const Socket& ) = delete; diff --git a/server/TracyEvent.hpp b/server/TracyEvent.hpp index 69510642..742b1d9e 100644 --- a/server/TracyEvent.hpp +++ b/server/TracyEvent.hpp @@ -155,8 +155,6 @@ struct ThreadData { uint64_t id; uint64_t count; - bool showFull; - bool visible; Vector timeline; Vector stack; Vector messages; @@ -178,8 +176,6 @@ struct GpuCtxData Vector queue; Vector resync; uint8_t accuracyBits; - bool showFull; - bool visible; }; struct LockMap @@ -189,7 +185,6 @@ struct LockMap std::unordered_map threadMap; std::vector threadList; LockType type; - bool visible; bool valid; }; @@ -213,8 +208,6 @@ struct PlotData uint64_t name; double min; double max; - bool showFull; - bool visible; Vector data; Vector postpone; uint64_t postponeTime; diff --git a/server/TracyVector.hpp b/server/TracyVector.hpp index b3e13228..13011319 100644 --- a/server/TracyVector.hpp +++ b/server/TracyVector.hpp @@ -21,6 +21,7 @@ class Vector { public: using iterator = T*; + using const_iterator = const T*; Vector() : m_ptr( nullptr ) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 453f1080..f4c61d40 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -15,14 +15,10 @@ #include #include -#include "../common/TracyProtocol.hpp" #include "../common/TracySystem.hpp" -#include "../common/TracyQueue.hpp" #include "tracy_pdqsort.h" -#include "TracyFileRead.hpp" #include "TracyFileWrite.hpp" #include "TracyImGui.hpp" -#include "TracyPopcnt.hpp" #include "TracyView.hpp" #ifdef TRACY_FILESELECTOR @@ -119,27 +115,13 @@ enum { MinVisSize = 3 }; static View* s_instance = nullptr; View::View( const char* addr ) - : m_addr( addr ) - , m_shutdown( false ) - , m_connected( false ) - , m_hasData( false ) + : m_worker( addr ) , m_staticView( false ) - , m_sourceLocationExpand( { 0 } ) - , m_zonesCnt( 0 ) - , m_mbps( 64 ) - , m_compRatio( 1 ) - , m_pendingStrings( 0 ) - , m_pendingThreads( 0 ) - , m_pendingSourceLocation( 0 ) - , m_stream( LZ4_createStreamDecode() ) - , m_buffer( new char[TargetFrameSize*3 + 1] ) - , m_bufferOffset( 0 ) , m_frameScale( 0 ) , m_pause( false ) , m_frameStart( 0 ) , m_zvStart( 0 ) , m_zvEnd( 0 ) - , m_lastTime( 0 ) , m_zvHeight( 0 ) , m_zvScroll( 0 ) , m_zoneInfoWindow( nullptr ) @@ -157,26 +139,17 @@ View::View( const char* addr ) , m_drawPlots( true ) , m_onlyContendedLocks( false ) , m_namespace( Namespace::Full ) - , m_terminate( false ) { assert( s_instance == nullptr ); s_instance = this; ImGuiStyle& style = ImGui::GetStyle(); style.FrameRounding = 2.f; - - m_thread = std::thread( [this] { Worker(); } ); - SetThreadName( m_thread, "Tracy View" ); } View::View( FileRead& f ) - : m_shutdown( false ) - , m_connected( false ) - , m_hasData( true ) + : m_worker( f ) , m_staticView( true ) - , m_zonesCnt( 0 ) - , m_stream( nullptr ) - , m_buffer( nullptr ) , m_frameScale( 0 ) , m_pause( false ) , m_frameStart( 0 ) @@ -198,1501 +171,23 @@ View::View( FileRead& f ) , m_drawPlots( true ) , m_onlyContendedLocks( false ) , m_namespace( Namespace::Full ) - , m_terminate( false ) { assert( s_instance == nullptr ); s_instance = this; - - f.Read( &m_delay, sizeof( m_delay ) ); - f.Read( &m_resolution, sizeof( m_resolution ) ); - f.Read( &m_timerMul, sizeof( m_timerMul ) ); - f.Read( &m_lastTime, sizeof( m_lastTime ) ); - - uint64_t sz; - { - f.Read( &sz, sizeof( sz ) ); - assert( sz < 1024 ); - char tmp[1024]; - f.Read( tmp, sz ); - m_captureName = std::string( tmp, tmp+sz ); - } - - f.Read( &sz, sizeof( sz ) ); - m_frames.reserve( sz ); - for( uint64_t i=0; i pointerMap; - - f.Read( &sz, sizeof( sz ) ); - for( uint64_t i=0; i( ssz+1 ); - f.Read( dst, ssz ); - dst[ssz] = '\0'; - m_stringData.push_back( dst ); - pointerMap.emplace( ptr, dst ); - } - - f.Read( &sz, sizeof( sz ) ); - for( uint64_t i=0; isecond ); - } - - f.Read( &sz, sizeof( sz ) ); - for( uint64_t i=0; isecond ); - } - - f.Read( &sz, sizeof( sz ) ); - for( uint64_t i=0; i(); - f.Read( srcloc, sizeof( *srcloc ) ); - m_sourceLocationPayload.push_back( srcloc ); - } - - f.Read( &sz, sizeof( sz ) ); - for( uint64_t i=0; i(); - f.Read( lev, sizeof( LockEvent ) ); - lockmap.timeline.push_back( lev ); - } - } - else - { - for( uint64_t i=0; i(); - f.Read( lev, sizeof( LockEventShared ) ); - lockmap.timeline.push_back( lev ); - } - } - lockmap.visible = true; - m_lockMap.emplace( id, std::move( lockmap ) ); - } - - std::unordered_map msgMap; - f.Read( &sz, sizeof( sz ) ); - m_messages.reserve( sz ); - for( uint64_t i=0; i(); - f.Read( msgdata, sizeof( *msgdata ) ); - m_messages.push_back( msgdata ); - msgMap.emplace( ptr, msgdata ); - } - - f.Read( &sz, sizeof( sz ) ); - m_threads.reserve( sz ); - for( uint64_t i=0; i(); - f.Read( &td->id, sizeof( td->id ) ); - f.Read( &td->count, sizeof( td->count ) ); - ReadTimeline( f, td->timeline ); - uint64_t msz; - f.Read( &msz, sizeof( msz ) ); - td->messages.reserve( msz ); - for( uint64_t j=0; jmessages.push_back( msgMap[ptr] ); - } - td->showFull = true; - td->visible = true; - m_threads.push_back( td ); - } - - f.Read( &sz, sizeof( sz ) ); - m_gpuData.reserve( sz ); - for( uint64_t i=0; i(); - f.Read( &ctx->thread, sizeof( ctx->thread ) ); - f.Read( &ctx->accuracyBits, sizeof( ctx->accuracyBits ) ); - f.Read( &ctx->count, sizeof( ctx->count ) ); - ReadTimeline( f, ctx->timeline ); - ctx->showFull = true; - ctx->visible = true; - m_gpuData.push_back( ctx ); - } - - f.Read( &sz, sizeof( sz ) ); - m_plots.reserve( sz ); - for( uint64_t i=0; i(); - f.Read( &pd->name, sizeof( pd->name ) ); - f.Read( &pd->min, sizeof( pd->min ) ); - f.Read( &pd->max, sizeof( pd->max ) ); - pd->showFull = true; - pd->visible = true; - uint64_t psz; - f.Read( &psz, sizeof( psz ) ); - pd->data.reserve_and_use( psz ); - f.Read( pd->data.data(), psz * sizeof( PlotItem ) ); - m_plots.push_back( pd ); - } } View::~View() { - m_shutdown.store( true, std::memory_order_relaxed ); + m_worker.Shutdown(); if( !m_staticView ) { - m_thread.join(); + m_worker.Join(); } - delete[] m_buffer; - LZ4_freeStreamDecode( m_stream ); - assert( s_instance != nullptr ); s_instance = nullptr; } -bool View::ShouldExit() -{ - return s_instance->m_shutdown.load( std::memory_order_relaxed ); -} - -void View::Worker() -{ - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - - for(;;) - { - if( m_shutdown.load( std::memory_order_relaxed ) ) return; - if( !m_sock.Connect( m_addr.c_str(), "8086" ) ) continue; - - std::chrono::time_point t0; - - uint64_t bytes = 0; - uint64_t decBytes = 0; - - { - WelcomeMessage welcome; - if( !m_sock.Read( &welcome, sizeof( welcome ), &tv, ShouldExit ) ) goto close; - m_timerMul = welcome.timerMul; - m_frames.push_back( TscTime( welcome.initBegin ) ); - m_frames.push_back( TscTime( welcome.initEnd ) ); - m_lastTime = m_frames.back(); - m_delay = TscTime( welcome.delay ); - m_resolution = TscTime( welcome.resolution ); - - char dtmp[64]; - time_t date = welcome.epoch; - auto lt = localtime( &date ); - strftime( dtmp, 64, "%F %T", lt ); - char tmp[1024]; - sprintf( tmp, "%s @ %s###Profiler", welcome.programName, dtmp ); - m_captureName = tmp; - } - - m_hasData.store( true, std::memory_order_release ); - - LZ4_setStreamDecode( m_stream, nullptr, 0 ); - m_connected.store( true, std::memory_order_relaxed ); - - t0 = std::chrono::high_resolution_clock::now(); - - for(;;) - { - if( m_shutdown.load( std::memory_order_relaxed ) ) return; - - auto buf = m_buffer + m_bufferOffset; - char lz4buf[LZ4Size]; - lz4sz_t lz4sz; - if( !m_sock.Read( &lz4sz, sizeof( lz4sz ), &tv, ShouldExit ) ) goto close; - if( !m_sock.Read( lz4buf, lz4sz, &tv, ShouldExit ) ) goto close; - bytes += sizeof( lz4sz ) + lz4sz; - - auto sz = LZ4_decompress_safe_continue( m_stream, lz4buf, buf, lz4sz, TargetFrameSize ); - assert( sz >= 0 ); - decBytes += sz; - - char* ptr = buf; - const char* end = buf + sz; - - { - std::lock_guard lock( m_lock ); - while( ptr < end ) - { - auto ev = (const QueueItem*)ptr; - DispatchProcess( *ev, ptr ); - } - - m_bufferOffset += sz; - if( m_bufferOffset > TargetFrameSize * 2 ) m_bufferOffset = 0; - - HandlePostponedPlots(); - } - - auto t1 = std::chrono::high_resolution_clock::now(); - auto td = std::chrono::duration_cast( t1 - t0 ).count(); - enum { MbpsUpdateTime = 200 }; - if( td > MbpsUpdateTime ) - { - std::lock_guard lock( m_mbpslock ); - m_mbps.erase( m_mbps.begin() ); - m_mbps.emplace_back( bytes / ( td * 125.f ) ); - m_compRatio = float( bytes ) / decBytes; - t0 = t1; - bytes = 0; - decBytes = 0; - } - - if( m_terminate ) - { - if( m_pendingStrings != 0 || m_pendingThreads != 0 || m_pendingSourceLocation != 0 || - !m_pendingCustomStrings.empty() || !m_pendingPlots.empty() ) - { - continue; - } - bool done = true; - for( auto& v : m_threads ) - { - if( !v->stack.empty() ) - { - done = false; - break; - } - } - if( !done ) continue; - ServerQuery( ServerQueryTerminate, 0 ); - break; - } - } - -close: - m_sock.Close(); - m_connected.store( false, std::memory_order_relaxed ); - } -} - -void View::DispatchProcess( const QueueItem& ev, char*& ptr ) -{ - if( ev.hdr.type == QueueType::CustomStringData || ev.hdr.type == QueueType::StringData || ev.hdr.type == QueueType::ThreadName || ev.hdr.type == QueueType::PlotName || ev.hdr.type == QueueType::SourceLocationPayload ) - { - ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer ); - uint16_t sz; - memcpy( &sz, ptr, sizeof( sz ) ); - ptr += sizeof( sz ); - switch( ev.hdr.type ) - { - case QueueType::CustomStringData: - AddCustomString( ev.stringTransfer.ptr, ptr, sz ); - break; - case QueueType::StringData: - AddString( ev.stringTransfer.ptr, ptr, sz ); - break; - case QueueType::ThreadName: - AddThreadString( ev.stringTransfer.ptr, ptr, sz ); - break; - case QueueType::PlotName: - HandlePlotName( ev.stringTransfer.ptr, ptr, sz ); - break; - case QueueType::SourceLocationPayload: - AddSourceLocationPayload( ev.stringTransfer.ptr, ptr, sz ); - break; - default: - assert( false ); - break; - } - ptr += sz; - } - else - { - ptr += QueueDataSize[ev.hdr.idx]; - Process( ev ); - } -} - -void View::ServerQuery( uint8_t type, uint64_t data ) -{ - enum { DataSize = sizeof( type ) + sizeof( data ) }; - char tmp[DataSize]; - memcpy( tmp, &type, sizeof( type ) ); - memcpy( tmp + sizeof( type ), &data, sizeof( data ) ); - m_sock.Send( tmp, DataSize ); -} - -void View::Process( const QueueItem& ev ) -{ - switch( ev.hdr.type ) - { - case QueueType::ZoneBegin: - ProcessZoneBegin( ev.zoneBegin ); - break; - case QueueType::ZoneBeginAllocSrcLoc: - ProcessZoneBeginAllocSrcLoc( ev.zoneBegin ); - break; - case QueueType::ZoneEnd: - ProcessZoneEnd( ev.zoneEnd ); - break; - case QueueType::FrameMarkMsg: - ProcessFrameMark( ev.frameMark ); - break; - case QueueType::SourceLocation: - AddSourceLocation( ev.srcloc ); - break; - case QueueType::ZoneText: - ProcessZoneText( ev.zoneText ); - break; - case QueueType::LockAnnounce: - ProcessLockAnnounce( ev.lockAnnounce ); - break; - case QueueType::LockWait: - ProcessLockWait( ev.lockWait ); - break; - case QueueType::LockObtain: - ProcessLockObtain( ev.lockObtain ); - break; - case QueueType::LockRelease: - ProcessLockRelease( ev.lockRelease ); - break; - case QueueType::LockSharedWait: - ProcessLockSharedWait( ev.lockWait ); - break; - case QueueType::LockSharedObtain: - ProcessLockSharedObtain( ev.lockObtain ); - break; - case QueueType::LockSharedRelease: - ProcessLockSharedRelease( ev.lockRelease ); - break; - case QueueType::LockMark: - ProcessLockMark( ev.lockMark ); - break; - case QueueType::PlotData: - ProcessPlotData( ev.plotData ); - break; - case QueueType::Message: - ProcessMessage( ev.message ); - break; - case QueueType::MessageLiteral: - ProcessMessageLiteral( ev.message ); - break; - case QueueType::GpuNewContext: - ProcessGpuNewContext( ev.gpuNewContext ); - break; - case QueueType::GpuZoneBegin: - ProcessGpuZoneBegin( ev.gpuZoneBegin ); - break; - case QueueType::GpuZoneEnd: - ProcessGpuZoneEnd( ev.gpuZoneEnd ); - break; - case QueueType::GpuTime: - ProcessGpuTime( ev.gpuTime ); - break; - case QueueType::GpuResync: - ProcessGpuResync( ev.gpuResync ); - break; - case QueueType::Terminate: - m_terminate = true; - break; - default: - assert( false ); - break; - } -} - -void View::ProcessZoneBegin( const QueueZoneBegin& ev ) -{ - auto zone = m_slab.AllocInit(); - - CheckSourceLocation( ev.srcloc ); - - zone->start = TscTime( ev.time ); - zone->end = -1; - zone->srcloc = ShrinkSourceLocation( ev.srcloc ); - assert( ev.cpu == 0xFFFFFFFF || ev.cpu <= std::numeric_limits::max() ); - zone->cpu_start = ev.cpu == 0xFFFFFFFF ? -1 : (int8_t)ev.cpu; - - m_lastTime = std::max( m_lastTime, zone->start ); - - NewZone( zone, ev.thread ); -} - -void View::ProcessZoneBeginAllocSrcLoc( const QueueZoneBegin& ev ) -{ - auto it = m_pendingSourceLocationPayload.find( ev.srcloc ); - assert( it != m_pendingSourceLocationPayload.end() ); - - auto zone = m_slab.AllocInit(); - - zone->start = TscTime( ev.time ); - zone->end = -1; - zone->srcloc = it->second; - assert( ev.cpu == 0xFFFFFFFF || ev.cpu <= std::numeric_limits::max() ); - zone->cpu_start = ev.cpu == 0xFFFFFFFF ? -1 : (int8_t)ev.cpu; - - m_lastTime = std::max( m_lastTime, zone->start ); - - NewZone( zone, ev.thread ); - - m_pendingSourceLocationPayload.erase( it ); -} - -void View::ProcessZoneEnd( const QueueZoneEnd& ev ) -{ - auto tit = m_threadMap.find( ev.thread ); - assert( tit != m_threadMap.end() ); - - auto td = tit->second; - auto& stack = td->stack; - assert( !stack.empty() ); - auto zone = stack.back_and_pop(); - assert( zone->end == -1 ); - zone->end = TscTime( ev.time ); - assert( ev.cpu == 0xFFFFFFFF || ev.cpu <= std::numeric_limits::max() ); - zone->cpu_end = ev.cpu == 0xFFFFFFFF ? -1 : (int8_t)ev.cpu; - assert( zone->end >= zone->start ); - - m_lastTime = std::max( m_lastTime, zone->end ); -} - -void View::ProcessFrameMark( const QueueFrameMark& ev ) -{ - assert( !m_frames.empty() ); - const auto lastframe = m_frames.back(); - const auto time = TscTime( ev.time ); - assert( lastframe < time ); - m_frames.push_back_non_empty( time ); - m_lastTime = std::max( m_lastTime, time ); -} - -void View::ProcessZoneText( const QueueZoneText& ev ) -{ - auto tit = m_threadMap.find( ev.thread ); - assert( tit != m_threadMap.end() ); - - auto td = tit->second; - auto& stack = td->stack; - assert( !stack.empty() ); - auto zone = stack.back(); - auto it = m_pendingCustomStrings.find( ev.text ); - assert( it != m_pendingCustomStrings.end() ); - zone->text = StringIdx( it->second.idx ); - m_pendingCustomStrings.erase( it ); -} - -void View::ProcessLockAnnounce( const QueueLockAnnounce& ev ) -{ - auto it = m_lockMap.find( ev.id ); - if( it == m_lockMap.end() ) - { - LockMap lm; - lm.srcloc = ShrinkSourceLocation( ev.lckloc ); - lm.type = ev.type; - lm.visible = true; - lm.valid = true; - m_lockMap.emplace( ev.id, std::move( lm ) ); - } - else - { - it->second.srcloc = ShrinkSourceLocation( ev.lckloc ); - assert( it->second.type == ev.type ); - it->second.visible = true; - it->second.valid = true; - } - CheckSourceLocation( ev.lckloc ); -} - -void View::ProcessLockWait( const QueueLockWait& ev ) -{ - auto it = m_lockMap.find( ev.id ); - if( it == m_lockMap.end() ) - { - LockMap lm; - lm.valid = false; - lm.type = ev.type; - it = m_lockMap.emplace( ev.id, std::move( lm ) ).first; - } - - auto lev = ev.type == LockType::Lockable ? m_slab.Alloc() : m_slab.Alloc(); - lev->time = TscTime( ev.time ); - lev->type = LockEvent::Type::Wait; - lev->srcloc = 0; - - InsertLockEvent( it->second, lev, ev.thread ); -} - -void View::ProcessLockObtain( const QueueLockObtain& ev ) -{ - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - auto& lock = m_lockMap[ev.id]; - - auto lev = lock.type == LockType::Lockable ? m_slab.Alloc() : m_slab.Alloc(); - lev->time = TscTime( ev.time ); - lev->type = LockEvent::Type::Obtain; - lev->srcloc = 0; - - InsertLockEvent( lock, lev, ev.thread ); -} - -void View::ProcessLockRelease( const QueueLockRelease& ev ) -{ - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - auto& lock = m_lockMap[ev.id]; - - auto lev = lock.type == LockType::Lockable ? m_slab.Alloc() : m_slab.Alloc(); - lev->time = TscTime( ev.time ); - lev->type = LockEvent::Type::Release; - lev->srcloc = 0; - - InsertLockEvent( lock, lev, ev.thread ); -} - -void View::ProcessLockSharedWait( const QueueLockWait& ev ) -{ - auto it = m_lockMap.find( ev.id ); - if( it == m_lockMap.end() ) - { - LockMap lm; - lm.valid = false; - lm.type = ev.type; - it = m_lockMap.emplace( ev.id, std::move( lm ) ).first; - } - - assert( ev.type == LockType::SharedLockable ); - auto lev = m_slab.Alloc(); - lev->time = TscTime( ev.time ); - lev->type = LockEvent::Type::WaitShared; - lev->srcloc = 0; - - InsertLockEvent( it->second, lev, ev.thread ); -} - -void View::ProcessLockSharedObtain( const QueueLockObtain& ev ) -{ - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - auto& lock = m_lockMap[ev.id]; - - assert( lock.type == LockType::SharedLockable ); - auto lev = m_slab.Alloc(); - lev->time = TscTime( ev.time ); - lev->type = LockEvent::Type::ObtainShared; - lev->srcloc = 0; - - InsertLockEvent( lock, lev, ev.thread ); -} - -void View::ProcessLockSharedRelease( const QueueLockRelease& ev ) -{ - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - auto& lock = m_lockMap[ev.id]; - - assert( lock.type == LockType::SharedLockable ); - auto lev = m_slab.Alloc(); - lev->time = TscTime( ev.time ); - lev->type = LockEvent::Type::ReleaseShared; - lev->srcloc = 0; - - InsertLockEvent( lock, lev, ev.thread ); -} - -void View::ProcessLockMark( const QueueLockMark& ev ) -{ - CheckSourceLocation( ev.srcloc ); - auto lit = m_lockMap.find( ev.id ); - assert( lit != m_lockMap.end() ); - auto& lockmap = lit->second; - auto tid = lockmap.threadMap.find( ev.thread ); - assert( tid != lockmap.threadMap.end() ); - const auto thread = tid->second; - auto it = lockmap.timeline.end(); - for(;;) - { - --it; - if( (*it)->thread == thread ) - { - switch( (*it)->type ) - { - case LockEvent::Type::Obtain: - case LockEvent::Type::ObtainShared: - case LockEvent::Type::Wait: - case LockEvent::Type::WaitShared: - (*it)->srcloc = ShrinkSourceLocation( ev.srcloc ); - return; - default: - break; - } - } - } -} - -void View::ProcessPlotData( const QueuePlotData& ev ) -{ - PlotData* plot; - auto it = m_plotMap.find( ev.name ); - if( it == m_plotMap.end() ) - { - auto pit = m_pendingPlots.find( ev.name ); - if( pit == m_pendingPlots.end() ) - { - plot = m_slab.AllocInit(); - plot->name = ev.name; - plot->showFull = true; - plot->visible = true; - m_pendingPlots.emplace( ev.name, plot ); - ServerQuery( ServerQueryPlotName, ev.name ); - } - else - { - plot = pit->second; - } - } - else - { - plot = it->second; - } - - const auto time = TscTime( ev.time ); - m_lastTime = std::max( m_lastTime, time ); - switch( ev.type ) - { - case PlotDataType::Double: - InsertPlot( plot, time, ev.data.d ); - break; - case PlotDataType::Float: - InsertPlot( plot, time, (double)ev.data.f ); - break; - case PlotDataType::Int: - InsertPlot( plot, time, (double)ev.data.i ); - break; - default: - assert( false ); - break; - } -} - -void View::ProcessMessage( const QueueMessage& ev ) -{ - auto it = m_pendingCustomStrings.find( ev.text ); - assert( it != m_pendingCustomStrings.end() ); - auto msg = m_slab.Alloc(); - msg->time = TscTime( ev.time ); - msg->ref = StringRef( StringRef::Type::Idx, it->second.idx ); - m_lastTime = std::max( m_lastTime, msg->time ); - InsertMessageData( msg, ev.thread ); - m_pendingCustomStrings.erase( it ); -} - -void View::ProcessMessageLiteral( const QueueMessage& ev ) -{ - CheckString( ev.text ); - auto msg = m_slab.Alloc(); - msg->time = TscTime( ev.time ); - msg->ref = StringRef( StringRef::Type::Ptr, ev.text ); - m_lastTime = std::max( m_lastTime, msg->time ); - InsertMessageData( msg, ev.thread ); -} - -void View::ProcessGpuNewContext( const QueueGpuNewContext& ev ) -{ - assert( m_gpuCtxMap.find( ev.context ) == m_gpuCtxMap.end() ); - - auto gpu = m_slab.AllocInit(); - gpu->timeDiff = TscTime( ev.cpuTime ) - ev.gpuTime; - gpu->thread = ev.thread; - gpu->accuracyBits = ev.accuracyBits; - gpu->count = 0; - gpu->showFull = true; - gpu->visible = true; - m_gpuData.push_back( gpu ); - m_gpuCtxMap.emplace( ev.context, gpu ); -} - -void View::ProcessGpuZoneBegin( const QueueGpuZoneBegin& ev ) -{ - auto it = m_gpuCtxMap.find( ev.context ); - assert( it != m_gpuCtxMap.end() ); - auto ctx = it->second; - - CheckSourceLocation( ev.srcloc ); - - auto zone = m_slab.AllocInit(); - - zone->cpuStart = TscTime( ev.cpuTime ); - zone->cpuEnd = -1; - zone->gpuStart = std::numeric_limits::max(); - zone->gpuEnd = -1; - zone->srcloc = ShrinkSourceLocation( ev.srcloc ); - - m_lastTime = std::max( m_lastTime, zone->cpuStart ); - - auto timeline = &ctx->timeline; - if( !ctx->stack.empty() ) - { - timeline = &ctx->stack.back()->child; - } - - timeline->push_back( zone ); - - ctx->stack.push_back( zone ); - ctx->queue.push_back( zone ); -} - -void View::ProcessGpuZoneEnd( const QueueGpuZoneEnd& ev ) -{ - auto it = m_gpuCtxMap.find( ev.context ); - assert( it != m_gpuCtxMap.end() ); - auto ctx = it->second; - - assert( !ctx->stack.empty() ); - auto zone = ctx->stack.back_and_pop(); - ctx->queue.push_back( zone ); - - zone->cpuEnd = TscTime( ev.cpuTime ); - m_lastTime = std::max( m_lastTime, zone->cpuEnd ); -} - -void View::ProcessGpuTime( const QueueGpuTime& ev ) -{ - auto it = m_gpuCtxMap.find( ev.context ); - assert( it != m_gpuCtxMap.end() ); - auto ctx = it->second; - - auto zone = ctx->queue.front(); - if( zone->gpuStart == std::numeric_limits::max() ) - { - zone->gpuStart = ctx->timeDiff + ev.gpuTime; - m_lastTime = std::max( m_lastTime, zone->gpuStart ); - ctx->count++; - } - else - { - zone->gpuEnd = ctx->timeDiff + ev.gpuTime; - m_lastTime = std::max( m_lastTime, zone->gpuEnd ); - } - - ctx->queue.erase( ctx->queue.begin() ); - if( !ctx->resync.empty() ) - { - auto& resync = ctx->resync.front(); - assert( resync.events > 0 ); - resync.events--; - if( resync.events == 0 ) - { - ctx->timeDiff = resync.timeDiff; - ctx->resync.erase( ctx->resync.begin() ); - } - } -} - -void View::ProcessGpuResync( const QueueGpuResync& ev ) -{ - auto it = m_gpuCtxMap.find( ev.context ); - assert( it != m_gpuCtxMap.end() ); - auto ctx = it->second; - - const auto timeDiff = TscTime( ev.cpuTime ) - ev.gpuTime; - - if( ctx->queue.empty() ) - { - assert( ctx->resync.empty() ); - ctx->timeDiff = timeDiff; - } - else - { - if( ctx->resync.empty() ) - { - ctx->resync.push_back( { timeDiff, uint16_t( ctx->queue.size() ) } ); - } - else - { - const auto last = ctx->resync.back().events; - ctx->resync.push_back( { timeDiff, uint16_t( ctx->queue.size() - last ) } ); - } - } -} - -void View::CheckString( uint64_t ptr ) -{ - if( ptr == 0 ) return; - if( m_strings.find( ptr ) != m_strings.end() ) return; - - m_strings.emplace( ptr, "???" ); - m_pendingStrings++; - - ServerQuery( ServerQueryString, ptr ); -} - -void View::CheckThreadString( uint64_t id ) -{ - if( m_threadNames.find( id ) != m_threadNames.end() ) return; - - m_threadNames.emplace( id, "???" ); - m_pendingThreads++; - - ServerQuery( ServerQueryThreadString, id ); -} - -static const SourceLocation emptySourceLocation = {}; - -void View::CheckSourceLocation( uint64_t ptr ) -{ - if( m_sourceLocation.find( ptr ) != m_sourceLocation.end() ) - { - return; - } - else - { - NewSourceLocation( ptr ); - } -} - -void View::NewSourceLocation( uint64_t ptr ) -{ - m_sourceLocation.emplace( ptr, emptySourceLocation ); - m_pendingSourceLocation++; - m_sourceLocationQueue.push_back( ptr ); - - ServerQuery( ServerQuerySourceLocation, ptr ); -} - -void View::AddString( uint64_t ptr, char* str, size_t sz ) -{ - assert( m_pendingStrings > 0 ); - m_pendingStrings--; - auto it = m_strings.find( ptr ); - assert( it != m_strings.end() && strcmp( it->second, "???" ) == 0 ); - const auto sl = StoreString( str, sz ); - it->second = sl.ptr; -} - -void View::AddThreadString( uint64_t id, char* str, size_t sz ) -{ - assert( m_pendingThreads > 0 ); - m_pendingThreads--; - auto it = m_threadNames.find( id ); - assert( it != m_threadNames.end() && strcmp( it->second, "???" ) == 0 ); - const auto sl = StoreString( str, sz ); - it->second = sl.ptr; -} - -void View::AddCustomString( uint64_t ptr, char* str, size_t sz ) -{ - assert( m_pendingCustomStrings.find( ptr ) == m_pendingCustomStrings.end() ); - m_pendingCustomStrings.emplace( ptr, StoreString( str, sz ) ); -} - -StringLocation View::StoreString( char* str, size_t sz ) -{ - StringLocation ret; - const char backup = str[sz]; - str[sz] = '\0'; - auto sit = m_stringMap.find( str ); - if( sit == m_stringMap.end() ) - { - auto ptr = m_slab.Alloc( sz+1 ); - memcpy( ptr, str, sz+1 ); - ret.ptr = ptr; - ret.idx = m_stringData.size(); - m_stringMap.emplace( ptr, m_stringData.size() ); - m_stringData.push_back( ptr ); - } - else - { - ret.ptr = sit->first; - ret.idx = sit->second; - } - str[sz] = backup; - return ret; -} - -void View::AddSourceLocation( const QueueSourceLocation& srcloc ) -{ - assert( m_pendingSourceLocation > 0 ); - m_pendingSourceLocation--; - - const auto ptr = m_sourceLocationQueue.front(); - m_sourceLocationQueue.erase( m_sourceLocationQueue.begin() ); - - auto it = m_sourceLocation.find( ptr ); - assert( it != m_sourceLocation.end() ); - CheckString( srcloc.name ); - CheckString( srcloc.file ); - CheckString( srcloc.function ); - uint32_t color = ( srcloc.r << 16 ) | ( srcloc.g << 8 ) | srcloc.b; - it->second = SourceLocation { srcloc.name == 0 ? StringRef() : StringRef( StringRef::Ptr, srcloc.name ), StringRef( StringRef::Ptr, srcloc.function ), StringRef( StringRef::Ptr, srcloc.file ), srcloc.line, color }; -} - -void View::AddSourceLocationPayload( uint64_t ptr, char* data, size_t sz ) -{ - const auto start = data; - - assert( m_pendingSourceLocationPayload.find( ptr ) == m_pendingSourceLocationPayload.end() ); - - uint32_t color, line; - memcpy( &color, data, 4 ); - memcpy( &line, data + 4, 4 ); - data += 8; - auto end = data; - - while( *end ) end++; - const auto func = StoreString( data, end - data ); - end++; - - data = end; - while( *end ) end++; - const auto source = StoreString( data, end - data ); - end++; - - const auto nsz = sz - ( end - start ); - - color = ( ( color & 0x00FF0000 ) >> 16 ) | - ( ( color & 0x0000FF00 ) ) | - ( ( color & 0x000000FF ) << 16 ); - - SourceLocation srcloc { nsz == 0 ? StringRef() : StringRef( StringRef::Idx, StoreString( end, nsz ).idx ), StringRef( StringRef::Idx, func.idx ), StringRef( StringRef::Idx, source.idx ), line, color }; - auto it = m_sourceLocationPayloadMap.find( &srcloc ); - if( it == m_sourceLocationPayloadMap.end() ) - { - auto slptr = m_slab.Alloc(); - memcpy( slptr, &srcloc, sizeof( srcloc ) ); - uint32_t idx = m_sourceLocationPayload.size(); - m_sourceLocationPayloadMap.emplace( slptr, idx ); - m_pendingSourceLocationPayload.emplace( ptr, -int32_t( idx + 1 ) ); - m_sourceLocationPayload.push_back( slptr ); - } - else - { - m_pendingSourceLocationPayload.emplace( ptr, -int32_t( it->second + 1 ) ); - } -} - -uint32_t View::ShrinkSourceLocation( uint64_t srcloc ) -{ - auto it = m_sourceLocationShrink.find( srcloc ); - if( it != m_sourceLocationShrink.end() ) - { - return it->second; - } - else - { - return NewShrinkedSourceLocation( srcloc ); - } -} - -uint32_t View::NewShrinkedSourceLocation( uint64_t srcloc ) -{ - const auto sz = m_sourceLocationExpand.size(); - m_sourceLocationExpand.push_back( srcloc ); - m_sourceLocationShrink.emplace( srcloc, sz ); - return sz; -} - -void View::InsertMessageData( MessageData* msg, uint64_t thread ) -{ - if( m_messages.empty() ) - { - m_messages.push_back( msg ); - } - else if( m_messages.back()->time < msg->time ) - { - m_messages.push_back_non_empty( msg ); - } - else - { - auto mit = std::lower_bound( m_messages.begin(), m_messages.end(), msg->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); - m_messages.insert( mit, msg ); - } - - auto vec = &NoticeThread( thread )->messages; - if( vec->empty() ) - { - vec->push_back( msg ); - } - else if( vec->back()->time < msg->time ) - { - vec->push_back_non_empty( msg ); - } - else - { - auto tmit = std::lower_bound( vec->begin(), vec->end(), msg->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); - vec->insert( tmit, msg ); - } -} - -ThreadData* View::NoticeThread( uint64_t thread ) -{ - auto it = m_threadMap.find( thread ); - if( it != m_threadMap.end() ) - { - return it->second; - } - else - { - return NewThread( thread ); - } -} - -ThreadData* View::NewThread( uint64_t thread ) -{ - CheckThreadString( thread ); - auto td = m_slab.AllocInit(); - td->id = thread; - td->count = 0; - td->showFull = true; - td->visible = true; - m_threads.push_back( td ); - m_threadMap.emplace( thread, td ); - return td; -} - -void View::NewZone( ZoneEvent* zone, uint64_t thread ) -{ - m_zonesCnt++; - auto td = NoticeThread( thread ); - td->count++; - if( td->stack.empty() ) - { - td->stack.push_back( zone ); - td->timeline.push_back( zone ); - } - else - { - td->stack.back()->child.push_back( zone ); - td->stack.push_back_non_empty( zone ); - } -} - -static void UpdateLockCountLockable( LockMap& lockmap, size_t pos ) -{ - auto& timeline = lockmap.timeline; - uint8_t lockingThread; - uint8_t lockCount; - uint64_t waitList; - - if( pos == 0 ) - { - lockingThread = 0; - lockCount = 0; - waitList = 0; - } - else - { - const auto tl = timeline[pos-1]; - lockingThread = tl->lockingThread; - lockCount = tl->lockCount; - waitList = tl->waitList; - } - const auto end = timeline.size(); - - while( pos != end ) - { - const auto tl = timeline[pos]; - const auto tbit = uint64_t( 1 ) << tl->thread; - switch( (LockEvent::Type)tl->type ) - { - case LockEvent::Type::Wait: - waitList |= tbit; - break; - case LockEvent::Type::Obtain: - assert( lockCount < std::numeric_limits::max() ); - assert( ( waitList & tbit ) != 0 ); - waitList &= ~tbit; - lockingThread = tl->thread; - lockCount++; - break; - case LockEvent::Type::Release: - assert( lockCount > 0 ); - lockCount--; - break; - default: - break; - } - tl->lockingThread = lockingThread; - tl->waitList = waitList; - tl->lockCount = lockCount; - assert( tl->lockingThread == lockingThread ); - pos++; - } -} - -static void UpdateLockCountSharedLockable( LockMap& lockmap, size_t pos ) -{ - auto& timeline = lockmap.timeline; - uint8_t lockingThread; - uint8_t lockCount; - uint64_t waitShared; - uint64_t waitList; - uint64_t sharedList; - - if( pos == 0 ) - { - lockingThread = 0; - lockCount = 0; - waitShared = 0; - waitList = 0; - sharedList = 0; - } - else - { - const auto tl = (LockEventShared*)timeline[pos-1]; - lockingThread = tl->lockingThread; - lockCount = tl->lockCount; - waitShared = tl->waitShared; - waitList = tl->waitList; - sharedList = tl->sharedList; - } - const auto end = timeline.size(); - - // ObtainShared and ReleaseShared should assert on lockCount == 0, but - // due to the async retrieval of data from threads that not possible. - while( pos != end ) - { - const auto tl = (LockEventShared*)timeline[pos]; - const auto tbit = uint64_t( 1 ) << tl->thread; - switch( (LockEvent::Type)tl->type ) - { - case LockEvent::Type::Wait: - waitList |= tbit; - break; - case LockEvent::Type::WaitShared: - waitShared |= tbit; - break; - case LockEvent::Type::Obtain: - assert( lockCount < std::numeric_limits::max() ); - assert( ( waitList & tbit ) != 0 ); - waitList &= ~tbit; - lockingThread = tl->thread; - lockCount++; - break; - case LockEvent::Type::Release: - assert( lockCount > 0 ); - lockCount--; - break; - case LockEvent::Type::ObtainShared: - assert( ( waitShared & tbit ) != 0 ); - assert( ( sharedList & tbit ) == 0 ); - waitShared &= ~tbit; - sharedList |= tbit; - break; - case LockEvent::Type::ReleaseShared: - assert( ( sharedList & tbit ) != 0 ); - sharedList &= ~tbit; - break; - default: - break; - } - tl->lockingThread = lockingThread; - tl->waitShared = waitShared; - tl->waitList = waitList; - tl->sharedList = sharedList; - tl->lockCount = lockCount; - assert( tl->lockingThread == lockingThread ); - pos++; - } -} - -static inline void UpdateLockCount( LockMap& lockmap, size_t pos ) -{ - if( lockmap.type == LockType::Lockable ) - { - UpdateLockCountLockable( lockmap, pos ); - } - else - { - UpdateLockCountSharedLockable( lockmap, pos ); - } -} - -void View::InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread ) -{ - m_lastTime = std::max( m_lastTime, lev->time ); - - NoticeThread( thread ); - - auto it = lockmap.threadMap.find( thread ); - if( it == lockmap.threadMap.end() ) - { - assert( lockmap.threadList.size() < MaxLockThreads ); - it = lockmap.threadMap.emplace( thread, lockmap.threadList.size() ).first; - lockmap.threadList.emplace_back( thread ); - } - lev->thread = it->second; - assert( lev->thread == it->second ); - auto& timeline = lockmap.timeline; - if( timeline.empty() ) - { - timeline.push_back( lev ); - UpdateLockCount( lockmap, timeline.size() - 1 ); - } - else if( timeline.back()->time < lev->time ) - { - timeline.push_back_non_empty( lev ); - UpdateLockCount( lockmap, timeline.size() - 1 ); - } - else - { - auto it = std::lower_bound( timeline.begin(), timeline.end(), lev->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); - it = timeline.insert( it, lev ); - UpdateLockCount( lockmap, std::distance( timeline.begin(), it ) ); - } -} - -void View::InsertPlot( PlotData* plot, int64_t time, double val ) -{ - if( plot->data.empty() ) - { - plot->min = val; - plot->max = val; - plot->data.push_back( { time, val } ); - } - else if( plot->data.back().time < time ) - { - if( plot->min > val ) plot->min = val; - else if( plot->max < val ) plot->max = val; - plot->data.push_back_non_empty( { time, val } ); - } - else - { - if( plot->min > val ) plot->min = val; - else if( plot->max < val ) plot->max = val; - if( plot->postpone.empty() ) - { - plot->postponeTime = std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); - plot->postpone.push_back( { time, val } ); - } - else - { - plot->postpone.push_back_non_empty( { time, val } ); - } - } -} - -void View::HandlePlotName( uint64_t name, char* str, size_t sz ) -{ - auto pit = m_pendingPlots.find( name ); - assert( pit != m_pendingPlots.end() ); - - const auto sl = StoreString( str, sz ); - - auto it = m_plotRev.find( sl.ptr ); - if( it == m_plotRev.end() ) - { - m_plotMap.emplace( name, pit->second ); - m_plotRev.emplace( sl.ptr, pit->second ); - m_plots.push_back( pit->second ); - m_strings.emplace( name, sl.ptr ); - } - else - { - auto plot = it->second; - m_plotMap.emplace( name, plot ); - const auto& pp = pit->second->data; - for( auto& v : pp ) - { - InsertPlot( plot, v.time, v.val ); - } - // TODO what happens with the source data here? - } - - m_pendingPlots.erase( pit ); -} - -void View::HandlePostponedPlots() -{ - for( auto& plot : m_plots ) - { - auto& src = plot->postpone; - if( src.empty() ) continue; - if( std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count() - plot->postponeTime < 100 ) continue; - auto& dst = plot->data; - std::sort( src.begin(), src.end(), [] ( const auto& l, const auto& r ) { return l.time < r.time; } ); - const auto ds = std::lower_bound( dst.begin(), dst.end(), src.front().time, [] ( const auto& l, const auto& r ) { return l.time < r; } ); - const auto dsd = std::distance( dst.begin(), ds ) ; - const auto de = std::lower_bound( ds, dst.end(), src.back().time, [] ( const auto& l, const auto& r ) { return l.time < r; } ); - const auto ded = std::distance( dst.begin(), de ); - dst.insert( de, src.begin(), src.end() ); - std::inplace_merge( dst.begin() + dsd, dst.begin() + ded, dst.begin() + ded + src.size(), [] ( const auto& l, const auto& r ) { return l.time < r.time; } ); - src.clear(); - } -} - -int64_t View::GetFrameTime( size_t idx ) const -{ - if( idx < m_frames.size() - 1 ) - { - return m_frames[idx+1] - m_frames[idx]; - } - else - { - return m_lastTime == 0 ? 0 : m_lastTime - m_frames.back(); - } -} - -int64_t View::GetFrameBegin( size_t idx ) const -{ - assert( idx < m_frames.size() ); - return m_frames[idx]; -} - -int64_t View::GetFrameEnd( size_t idx ) const -{ - if( idx < m_frames.size() - 1 ) - { - return m_frames[idx+1]; - } - else - { - return m_lastTime; - } -} - -int64_t View::GetZoneEnd( const ZoneEvent& ev ) const -{ - auto ptr = &ev; - for(;;) - { - if( ptr->end != -1 ) return ptr->end; - if( ptr->child.empty() ) return ptr->start; - ptr = ptr->child.back(); - } -} - -int64_t View::GetZoneEnd( const GpuEvent& ev ) const -{ - auto ptr = &ev; - for(;;) - { - if( ptr->gpuEnd != -1 ) return ptr->gpuEnd; - if( ptr->child.empty() ) return ptr->gpuStart; - ptr = ptr->child.back(); - } -} - -const char* View::GetString( uint64_t ptr ) const -{ - const auto it = m_strings.find( ptr ); - if( it == m_strings.end() || it->second == nullptr ) - { - return "???"; - } - else - { - return it->second; - } -} - -const char* View::GetString( const StringRef& ref ) const -{ - if( ref.isidx ) - { - assert( ref.active ); - return m_stringData[ref.stridx]; - } - else - { - if( ref.active ) - { - return GetString( ref.strptr ); - } - else - { - return "???"; - } - } -} - -const char* View::GetString( const StringIdx& idx ) const -{ - assert( idx.active ); - return m_stringData[idx.idx]; -} - -const char* View::GetThreadString( uint64_t id ) const -{ - const auto it = m_threadNames.find( id ); - if( it == m_threadNames.end() ) - { - return "???"; - } - else - { - return it->second; - } -} - -const SourceLocation& View::GetSourceLocation( int32_t srcloc ) const -{ - if( srcloc < 0 ) - { - return *m_sourceLocationPayload[-srcloc-1]; - } - else - { - const auto it = m_sourceLocation.find( m_sourceLocationExpand[srcloc] ); - assert( it != m_sourceLocation.end() ); - return it->second; - } -} - const char* View::ShortenNamespace( const char* name ) const { if( m_namespace == Namespace::Full ) return name; @@ -1749,9 +244,9 @@ void View::Draw() void View::DrawImpl() { - if( !m_hasData.load( std::memory_order_acquire ) ) + if( !m_worker.HasData() ) { - ImGui::Begin( m_addr.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize ); + ImGui::Begin( m_worker.GetAddr().c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize ); ImGui::Text( "Waiting for connection..." ); ImGui::End(); return; @@ -1762,8 +257,8 @@ void View::DrawImpl() DrawConnection(); } - std::lock_guard lock( m_lock ); - ImGui::Begin( m_captureName.c_str(), nullptr, ImGuiWindowFlags_NoScrollbar ); + std::lock_guard lock( m_worker.GetDataLock() ); + ImGui::Begin( m_worker.GetCaptureName().c_str(), nullptr, ImGuiWindowFlags_NoScrollbar ); if( ImGui::Button( m_pause ? "Resume" : "Pause", ImVec2( 70, 0 ) ) ) m_pause = !m_pause; ImGui::SameLine(); if( ImGui::Button( "Options", ImVec2( 70, 0 ) ) ) m_showOptions = true; @@ -1772,7 +267,7 @@ void View::DrawImpl() ImGui::SameLine(); if ( ImGui::Button( "Find Zone", ImVec2( 70, 0 ) ) ) m_findZone.show = true; ImGui::SameLine(); - ImGui::Text( "Frames: %-7" PRIu64 " Time span: %-10s View span: %-10s Zones: %-13s Queue delay: %s Timer resolution: %s", m_frames.size(), TimeToString( m_lastTime - m_frames[0] ), TimeToString( m_zvEnd - m_zvStart ), RealToString( m_zonesCnt, true ), TimeToString( m_delay ), TimeToString( m_resolution ) ); + ImGui::Text( "Frames: %-7" PRIu64 " Time span: %-10s View span: %-10s Zones: %-13s Queue delay: %s Timer resolution: %s", m_worker.GetFrameCount(), TimeToString( m_worker.GetLastTime() - m_worker.GetFrameBegin( 0 ) ), TimeToString( m_zvEnd - m_zvStart ), RealToString( m_worker.GetZoneCount(), true ), TimeToString( m_worker.GetDelay() ), TimeToString( m_worker.GetResolution() ) ); DrawFrames(); DrawZones(); ImGui::End(); @@ -1811,9 +306,10 @@ void View::DrawConnection() const auto cs = ty * 0.9f; { - std::lock_guard lock( m_mbpslock ); - ImGui::Begin( m_addr.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize ); - const auto mbps = m_mbps.back(); + std::lock_guard lock( m_worker.GetMbpsDataLock() ); + ImGui::Begin( m_worker.GetAddr().c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize ); + const auto& mbpsVector = m_worker.GetMbpsData(); + const auto mbps = mbpsVector.back(); char buf[64]; if( mbps < 0.1f ) { @@ -1825,21 +321,21 @@ void View::DrawConnection() } ImGui::Dummy( ImVec2( cs, 0 ) ); ImGui::SameLine(); - ImGui::PlotLines( buf, m_mbps.data(), m_mbps.size(), 0, nullptr, 0, std::numeric_limits::max(), ImVec2( 150, 0 ) ); - ImGui::Text( "Ratio %.1f%% Real: %6.2f Mbps", m_compRatio * 100.f, mbps / m_compRatio ); + ImGui::PlotLines( buf, mbpsVector.data(), mbpsVector.size(), 0, nullptr, 0, std::numeric_limits::max(), ImVec2( 150, 0 ) ); + ImGui::Text( "Ratio %.1f%% Real: %6.2f Mbps", m_worker.GetCompRatio() * 100.f, mbps / m_worker.GetCompRatio() ); } ImGui::Text( "Memory usage: %.2f MB", memUsage.load( std::memory_order_relaxed ) / ( 1024.f * 1024.f ) ); const auto wpos = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin(); - ImGui::GetWindowDrawList()->AddCircleFilled( wpos + ImVec2( 1 + cs * 0.5, 3 + ty * 0.5 ), cs * 0.5, m_connected.load( std::memory_order_relaxed ) ? 0xFF2222CC : 0xFF444444, 10 ); + ImGui::GetWindowDrawList()->AddCircleFilled( wpos + ImVec2( 1 + cs * 0.5, 3 + ty * 0.5 ), cs * 0.5, m_worker.IsConnected() ? 0xFF2222CC : 0xFF444444, 10 ); - std::lock_guard lock( m_lock ); + std::lock_guard lock( m_worker.GetDataLock() ); { - const auto sz = m_frames.size(); + const auto sz = m_worker.GetFrameCount(); if( sz > 1 ) { - const auto dt = m_frames[sz-1] - m_frames[sz-2]; + const auto dt = m_worker.GetFrameTime( sz - 2 ); const auto dtm = dt / 1000000.f; const auto fps = 1000.f / dtm; ImGui::Text( "FPS: %6.1f Frame time: %.2f ms", fps, dtm ); @@ -1870,7 +366,7 @@ void View::DrawConnection() } if( f ) { - Write( *f ); + m_worker.Write( *f ); } } } @@ -1901,7 +397,7 @@ static int GetFrameGroup( int frameScale ) void View::DrawFrames() { - assert( !m_frames.empty() ); + assert( m_worker.GetFrameCount() != 0 ); enum { Height = 40 }; enum { MaxFrameTime = 50 * 1000 * 1000 }; // 50ms @@ -1936,19 +432,19 @@ void View::DrawFrames() const int fwidth = GetFrameWidth( m_frameScale ); const int group = GetFrameGroup( m_frameScale ); - const int total = m_frames.size(); + const int total = m_worker.GetFrameCount(); const int onScreen = ( w - 2 ) / fwidth; if( !m_pause ) { m_frameStart = ( total < onScreen * group ) ? 0 : total - onScreen * group; - m_zvStart = m_frames[std::max( 0, (int)m_frames.size() - 4 )]; - if( m_frames.size() == 1 ) + m_zvStart = m_worker.GetFrameBegin( std::max( 0, total - 4 ) ); + if( total == 1 ) { - m_zvEnd = m_lastTime; + m_zvEnd = m_worker.GetLastTime(); } else { - m_zvEnd = m_frames.back(); + m_zvEnd = m_worker.GetFrameBegin( total - 1 ); } } @@ -1978,11 +474,11 @@ void View::DrawFrames() ImGui::BeginTooltip(); if( group > 1 ) { - auto f = GetFrameTime( sel ); + auto f = m_worker.GetFrameTime( sel ); auto g = std::min( group, total - sel ); for( int j=1; j 1 ) { g = std::min( group, total - ( m_frameStart + idx ) ); for( int j=1; j zrange = m_worker.GetFrameRange( m_zvStart, m_zvEnd ); - auto zbegin = (int)std::distance( m_frames.begin(), zitbegin ); - if( zbegin > 0 && *zitbegin != m_zvStart ) zbegin--; - const auto zend = (int)std::distance( m_frames.begin(), zitend ); - - if( zend > m_frameStart && zbegin < m_frameStart + onScreen * group ) + if( zrange.second > m_frameStart && zrange.first < m_frameStart + onScreen * group ) { - auto x0 = std::max( 0, ( zbegin - m_frameStart ) * fwidth / group ); - auto x1 = std::min( onScreen * fwidth, ( zend - m_frameStart ) * fwidth / group ); + auto x1 = std::min( onScreen * fwidth, ( zrange.second - m_frameStart ) * fwidth / group ); + auto x0 = std::max( 0, ( zrange.first - m_frameStart ) * fwidth / group ); if( x0 == x1 ) x1 = x0 + 1; @@ -2190,7 +680,7 @@ bool View::DrawZoneFrames() if( tw == 0 ) { char buf[128]; - const auto t = m_zvStart - m_frames[0]; + const auto t = m_zvStart - m_worker.GetFrameBegin( 0 ); auto txt = TimeToString( t ); if( t >= 0 ) { @@ -2223,19 +713,14 @@ bool View::DrawZoneFrames() } } - const auto zitbegin = std::lower_bound( m_frames.begin(), m_frames.end(), m_zvStart ); - if( zitbegin == m_frames.end() ) return hover; - const auto zitend = std::lower_bound( zitbegin, m_frames.end(), m_zvEnd ); + const std::pair zrange = m_worker.GetFrameRange( m_zvStart, m_zvEnd ); + if( zrange.first == -1 ) return hover; - auto zbegin = (int)std::distance( m_frames.begin(), zitbegin ); - if( zbegin > 0 && *zitbegin != m_zvStart ) zbegin--; - const auto zend = (int)std::distance( m_frames.begin(), zitend ); - - for( int i=zbegin; iAddLine( wpos + ImVec2( ( fend - m_zvStart ) * pxns, 0 ), wpos + ImVec2( ( fend - m_zvStart ) * pxns, wh ), 0x22FFFFFF ); @@ -2353,14 +838,15 @@ void View::DrawZones() // gpu zones if( m_drawGpuZones ) { - for( size_t i=0; ivisible ) continue; + const auto& v = m_worker.GetGpuData()[i]; + if( !Visible( v ) ) continue; draw->AddLine( wpos + ImVec2( 0, offset + ostep - 1 ), wpos + ImVec2( w, offset + ostep - 1 ), 0x33FFFFFF ); - if( v->showFull ) + bool& showFull = ShowFull( v ); + if( showFull ) { draw->AddTriangleFilled( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( ty - to/2, offset + to/2 ), wpos + ImVec2( ty * 0.5, offset + to/2 + th ), 0xFFFFAAAA ); } @@ -2370,25 +856,25 @@ void View::DrawZones() } char buf[64]; sprintf( buf, "GPU context %i", i ); - draw->AddText( wpos + ImVec2( ty, offset ), v->showFull ? 0xFFFFAAAA : 0xFF886666, buf ); + draw->AddText( wpos + ImVec2( ty, offset ), showFull ? 0xFFFFAAAA : 0xFF886666, buf ); if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + ImGui::CalcTextSize( buf ).x, offset + ty ) ) ) { if( ImGui::IsMouseClicked( 0 ) ) { - v->showFull = !v->showFull; + showFull = !showFull; } ImGui::BeginTooltip(); ImGui::Text( "%s", buf ); ImGui::Separator(); - ImGui::Text( "Thread: %s", GetThreadString( v->thread ) ); + ImGui::Text( "Thread: %s", m_worker.GetThreadString( v->thread ) ); if( !v->timeline.empty() ) { const auto t = v->timeline.front()->gpuStart; if( t != std::numeric_limits::max() ) { - ImGui::Text( "Appeared at %s", TimeToString( t - m_frames[0] ) ); + ImGui::Text( "Appeared at %s", TimeToString( t - m_worker.GetFrameTime( 0 ) ) ); } } ImGui::Text( "Zone count: %s", RealToString( v->count, true ) ); @@ -2398,7 +884,7 @@ void View::DrawZones() } offset += ostep; - if( v->showFull ) + if( showFull ) { const auto depth = DrawGpuZoneLevel( v->timeline, hover, pxns, wpos, offset, 0, v->thread ); offset += ostep * depth; @@ -2409,13 +895,14 @@ void View::DrawZones() // zones LockHighlight nextLockHighlight { -1 }; - for( auto& v : m_threads ) + for( const auto& v : m_worker.GetThreadData() ) { - if( !v->visible ) continue; + if( !Visible( v ) ) continue; draw->AddLine( wpos + ImVec2( 0, offset + ostep - 1 ), wpos + ImVec2( w, offset + ostep - 1 ), 0x33FFFFFF ); - if( v->showFull ) + bool& showFull = ShowFull( v ); + if( showFull ) { draw->AddTriangleFilled( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( ty - to/2, offset + to/2 ), wpos + ImVec2( ty * 0.5, offset + to/2 + th ), 0xFFFFFFFF ); @@ -2442,10 +929,10 @@ void View::DrawZones() } else { - ImGui::Text( "%s", TimeToString( (*it)->time - m_frames[0] ) ); + ImGui::Text( "%s", TimeToString( (*it)->time - m_worker.GetFrameBegin( 0 ) ) ); ImGui::Separator(); ImGui::Text( "Message text:" ); - ImGui::TextColored( ImVec4( 0xCC / 255.f, 0xCC / 255.f, 0x22 / 255.f, 1.f ), "%s", GetString( (*it)->ref ) ); + ImGui::TextColored( ImVec4( 0xCC / 255.f, 0xCC / 255.f, 0x22 / 255.f, 1.f ), "%s", m_worker.GetString( (*it)->ref ) ); } ImGui::EndTooltip(); m_msgHighlight = *it; @@ -2457,7 +944,7 @@ void View::DrawZones() { draw->AddTriangle( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( to/2, offset + ty - to/2 ), wpos + ImVec2( to/2 + th, offset + ty * 0.5 ), 0xFF888888 ); } - const auto txt = GetThreadString( v->id ); + const auto txt = m_worker.GetThreadString( v->id ); const auto txtsz = ImGui::CalcTextSize( txt ); if( m_gpuThread == v->id ) { @@ -2469,21 +956,21 @@ void View::DrawZones() draw->AddRectFilled( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + txtsz.x + 4, offset + ty ), 0x4488DD88 ); draw->AddRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + txtsz.x + 4, offset + ty ), 0x8888DD88 ); } - draw->AddText( wpos + ImVec2( ty, offset ), v->showFull ? 0xFFFFFFFF : 0xFF888888, txt ); + draw->AddText( wpos + ImVec2( ty, offset ), showFull ? 0xFFFFFFFF : 0xFF888888, txt ); if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + txtsz.x, offset + ty ) ) ) { if( ImGui::IsMouseClicked( 0 ) ) { - v->showFull = !v->showFull; + showFull = !showFull; } ImGui::BeginTooltip(); - ImGui::Text( "%s", GetThreadString( v->id ) ); + ImGui::Text( "%s", m_worker.GetThreadString( v->id ) ); if( !v->timeline.empty() ) { ImGui::Separator(); - ImGui::Text( "Appeared at %s", TimeToString( v->timeline.front()->start - m_frames[0] ) ); + ImGui::Text( "Appeared at %s", TimeToString( v->timeline.front()->start - m_worker.GetFrameBegin( 0 ) ) ); ImGui::Text( "Zone count: %s", RealToString( v->count, true ) ); ImGui::Text( "Top-level zones: %s", RealToString( v->timeline.size(), true ) ); } @@ -2493,7 +980,7 @@ void View::DrawZones() offset += ostep; - if( v->showFull ) + if( showFull ) { m_lastCpu = -1; if( m_drawZones ) @@ -2565,11 +1052,13 @@ void View::DrawZones() int View::DrawZoneLevel( const Vector& vec, bool hover, double pxns, const ImVec2& wpos, int _offset, int depth ) { + const auto delay = m_worker.GetDelay(); + const auto resolution = m_worker.GetResolution(); // cast to uint64_t, so that unended zones (end = -1) are still drawn - auto it = std::lower_bound( vec.begin(), vec.end(), m_zvStart - m_delay, [] ( const auto& l, const auto& r ) { return (uint64_t)l->end < (uint64_t)r; } ); + auto it = std::lower_bound( vec.begin(), vec.end(), m_zvStart - delay, [] ( const auto& l, const auto& r ) { return (uint64_t)l->end < (uint64_t)r; } ); if( it == vec.end() ) return depth; - const auto zitend = std::lower_bound( it, vec.end(), m_zvEnd + m_resolution, [] ( const auto& l, const auto& r ) { return l->start < r; } ); + const auto zitend = std::lower_bound( it, vec.end(), m_zvEnd + resolution, [] ( const auto& l, const auto& r ) { return l->start < r; } ); if( it == zitend ) return depth; const auto w = ImGui::GetWindowContentRegionWidth() - 1; @@ -2577,8 +1066,8 @@ int View::DrawZoneLevel( const Vector& vec, bool hover, double pxns, const auto ostep = ty + 1; const auto offset = _offset + ostep * depth; auto draw = ImGui::GetWindowDrawList(); - const auto dsz = m_delay * pxns; - const auto rsz = m_resolution * pxns; + const auto dsz = delay * pxns; + const auto rsz = resolution * pxns; depth++; int maxdepth = depth; @@ -2586,9 +1075,9 @@ int View::DrawZoneLevel( const Vector& vec, bool hover, double pxns, while( it < zitend ) { auto& ev = **it; - auto& srcloc = GetSourceLocation( ev.srcloc ); + auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); const auto color = GetZoneColor( ev ); - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); const auto zsz = std::max( ( end - ev.start ) * pxns, pxns * 0.5 ); if( zsz < MinVisSize ) { @@ -2600,7 +1089,7 @@ int View::DrawZoneLevel( const Vector& vec, bool hover, double pxns, { ++it; if( it == zitend ) break; - const auto nend = GetZoneEnd( **it ); + const auto nend = m_worker.GetZoneEnd( **it ); const auto pxnext = ( nend - m_zvStart ) * pxns; if( pxnext - px1 >= MinVisSize * 2 ) break; px1 = pxnext; @@ -2652,11 +1141,11 @@ int View::DrawZoneLevel( const Vector& vec, bool hover, double pxns, const char* zoneName; if( srcloc.name.active ) { - zoneName = GetString( srcloc.name ); + zoneName = m_worker.GetString( srcloc.name ); } else { - zoneName = GetString( srcloc.function ); + zoneName = m_worker.GetString( srcloc.function ); } int dmul = ev.text.active ? 2 : 1; @@ -2759,11 +1248,13 @@ int View::DrawZoneLevel( const Vector& vec, bool hover, double pxns, int View::DrawGpuZoneLevel( const Vector& vec, bool hover, double pxns, const ImVec2& wpos, int _offset, int depth, uint64_t thread ) { + const auto delay = m_worker.GetDelay(); + const auto resolution = m_worker.GetResolution(); // cast to uint64_t, so that unended zones (end = -1) are still drawn - auto it = std::lower_bound( vec.begin(), vec.end(), m_zvStart - m_delay, [] ( const auto& l, const auto& r ) { return (uint64_t)l->gpuEnd < (uint64_t)r; } ); + auto it = std::lower_bound( vec.begin(), vec.end(), m_zvStart - delay, [] ( const auto& l, const auto& r ) { return (uint64_t)l->gpuEnd < (uint64_t)r; } ); if( it == vec.end() ) return depth; - const auto zitend = std::lower_bound( it, vec.end(), m_zvEnd + m_resolution, [] ( const auto& l, const auto& r ) { return l->gpuStart < r; } ); + const auto zitend = std::lower_bound( it, vec.end(), m_zvEnd + resolution, [] ( const auto& l, const auto& r ) { return l->gpuStart < r; } ); if( it == zitend ) return depth; const auto w = ImGui::GetWindowContentRegionWidth() - 1; @@ -2771,8 +1262,8 @@ int View::DrawGpuZoneLevel( const Vector& vec, bool hover, double pxn const auto ostep = ty + 1; const auto offset = _offset + ostep * depth; auto draw = ImGui::GetWindowDrawList(); - const auto dsz = m_delay * pxns; - const auto rsz = m_resolution * pxns; + const auto dsz = delay * pxns; + const auto rsz = resolution * pxns; depth++; int maxdepth = depth; @@ -2780,9 +1271,9 @@ int View::DrawGpuZoneLevel( const Vector& vec, bool hover, double pxn while( it < zitend ) { auto& ev = **it; - auto& srcloc = GetSourceLocation( ev.srcloc ); + auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); const auto color = GetZoneColor( ev ); - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); if( end == std::numeric_limits::max() ) break; const auto zsz = std::max( ( end - ev.gpuStart ) * pxns, pxns * 0.5 ); if( zsz < MinVisSize ) @@ -2795,7 +1286,7 @@ int View::DrawGpuZoneLevel( const Vector& vec, bool hover, double pxn { ++it; if( it == zitend ) break; - const auto nend = GetZoneEnd( **it ); + const auto nend = m_worker.GetZoneEnd( **it ); const auto pxnext = ( nend - m_zvStart ) * pxns; if( pxnext - px1 >= MinVisSize * 2 ) break; px1 = pxnext; @@ -2855,7 +1346,7 @@ int View::DrawGpuZoneLevel( const Vector& vec, bool hover, double pxn if( d > maxdepth ) maxdepth = d; } - const char* zoneName = GetString( srcloc.name ); + const char* zoneName = m_worker.GetString( srcloc.name ); auto tsz = ImGui::CalcTextSize( zoneName ); const auto pr0 = ( ev.gpuStart - m_zvStart ) * pxns; @@ -2953,7 +1444,7 @@ enum class LockState WaitLock // red }; -static Vector::iterator GetNextLockEvent( const Vector::iterator& it, const Vector::iterator& end, LockState& nextState, uint64_t threadBit ) +static Vector::const_iterator GetNextLockEvent( const Vector::const_iterator& it, const Vector::const_iterator& end, LockState& nextState, uint64_t threadBit ) { auto next = it; next++; @@ -3044,7 +1535,7 @@ static Vector::iterator GetNextLockEvent( const Vector:: return next; } -static Vector::iterator GetNextLockEventShared( const Vector::iterator& it, const Vector::iterator& end, LockState& nextState, uint64_t threadBit ) +static Vector::const_iterator GetNextLockEventShared( const Vector::const_iterator& it, const Vector::const_iterator& end, LockState& nextState, uint64_t threadBit ) { const auto itptr = (const LockEventShared*)*it; auto next = it; @@ -3169,23 +1660,25 @@ static LockState CombineLockState( LockState state, LockState next ) int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int _offset, LockHighlight& highlight ) { + const auto delay = m_worker.GetDelay(); + const auto resolution = m_worker.GetResolution(); const auto w = ImGui::GetWindowContentRegionWidth(); const auto ty = ImGui::GetFontSize(); const auto ostep = ty + 1; auto draw = ImGui::GetWindowDrawList(); - const auto dsz = m_delay * pxns; - const auto rsz = m_resolution * pxns; + const auto dsz = delay * pxns; + const auto rsz = resolution * pxns; int cnt = 0; - for( auto& v : m_lockMap ) + for( const auto& v : m_worker.GetLockMap() ) { - auto& lockmap = v.second; - if( !lockmap.visible || !lockmap.valid ) continue; + const auto& lockmap = v.second; + if( !Visible( &lockmap ) || !lockmap.valid ) continue; auto it = lockmap.threadMap.find( tid ); if( it == lockmap.threadMap.end() ) continue; - auto& tl = lockmap.timeline; + const auto& tl = lockmap.timeline; assert( !tl.empty() ); if( tl.back()->time < m_zvStart ) continue; @@ -3194,13 +1687,13 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, const auto thread = it->second; const auto threadBit = GetThreadBit( thread ); - auto vbegin = std::lower_bound( tl.begin(), tl.end(), m_zvStart - m_delay, [] ( const auto& l, const auto& r ) { return l->time < r; } ); - const auto vend = std::lower_bound( vbegin, tl.end(), m_zvEnd + m_resolution, [] ( const auto& l, const auto& r ) { return l->time < r; } ); + auto vbegin = std::lower_bound( tl.begin(), tl.end(), m_zvStart - delay, [] ( const auto& l, const auto& r ) { return l->time < r; } ); + const auto vend = std::lower_bound( vbegin, tl.end(), m_zvEnd + resolution, [] ( const auto& l, const auto& r ) { return l->time < r; } ); if( vbegin > tl.begin() ) vbegin--; bool drawn = false; - auto& srcloc = GetSourceLocation( lockmap.srcloc ); + const auto& srcloc = m_worker.GetSourceLocation( lockmap.srcloc ); const auto offset = _offset + ostep * cnt; LockState state = LockState::Nothing; @@ -3342,9 +1835,9 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, } ImGui::BeginTooltip(); - ImGui::Text( "Lock #%" PRIu32 ": %s", v.first, GetString( srcloc.function ) ); + ImGui::Text( "Lock #%" PRIu32 ": %s", v.first, m_worker.GetString( srcloc.function ) ); ImGui::Separator(); - ImGui::Text( "%s:%i", GetString( srcloc.file ), srcloc.line ); + ImGui::Text( "%s:%i", m_worker.GetString( srcloc.file ), srcloc.line ); ImGui::Text( "Time: %s", TimeToString( t1 - t0 ) ); ImGui::Separator(); @@ -3365,10 +1858,10 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, } if( markloc != 0 ) { - auto& marklocdata = GetSourceLocation( markloc ); + const auto& marklocdata = m_worker.GetSourceLocation( markloc ); ImGui::Text( "Lock event location:" ); - ImGui::Text( "%s", GetString( marklocdata.function ) ); - ImGui::Text( "%s:%i", GetString( marklocdata.file ), marklocdata.line ); + ImGui::Text( "%s", m_worker.GetString( marklocdata.function ) ); + ImGui::Text( "%s:%i", m_worker.GetString( marklocdata.file ), marklocdata.line ); ImGui::Separator(); } @@ -3379,11 +1872,11 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, case LockState::HasLock: if( (*vbegin)->lockCount == 1 ) { - ImGui::Text( "Thread \"%s\" has lock. No other threads are waiting.", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" has lock. No other threads are waiting.", m_worker.GetThreadString( tid ) ); } else { - ImGui::Text( "Thread \"%s\" has %i locks. No other threads are waiting.", GetThreadString( tid ), (*vbegin)->lockCount ); + ImGui::Text( "Thread \"%s\" has %i locks. No other threads are waiting.", m_worker.GetThreadString( tid ), (*vbegin)->lockCount ); } if( (*vbegin)->waitList != 0 ) { @@ -3395,11 +1888,11 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( (*vbegin)->lockCount == 1 ) { - ImGui::Text( "Thread \"%s\" has lock. Blocked threads (%i):", GetThreadString( tid ), TracyCountBits( (*vbegin)->waitList ) ); + ImGui::Text( "Thread \"%s\" has lock. Blocked threads (%i):", m_worker.GetThreadString( tid ), TracyCountBits( (*vbegin)->waitList ) ); } else { - ImGui::Text( "Thread \"%s\" has %i locks. Blocked threads (%i):", GetThreadString( tid ), (*vbegin)->lockCount, TracyCountBits( (*vbegin)->waitList ) ); + ImGui::Text( "Thread \"%s\" has %i locks. Blocked threads (%i):", m_worker.GetThreadString( tid ), (*vbegin)->lockCount, TracyCountBits( (*vbegin)->waitList ) ); } auto waitList = (*vbegin)->waitList; int t = 0; @@ -3408,7 +1901,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( waitList & 0x1 ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[t] ) ); } waitList >>= 1; t++; @@ -3420,14 +1913,14 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( (*vbegin)->lockCount > 0 ) { - ImGui::Text( "Thread \"%s\" is blocked by other thread:", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" is blocked by other thread:", m_worker.GetThreadString( tid ) ); } else { - ImGui::Text( "Thread \"%s\" waits to obtain lock after release by thread:", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" waits to obtain lock after release by thread:", m_worker.GetThreadString( tid ) ); } ImGui::Indent( ty ); - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[(*vbegin)->lockingThread] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[(*vbegin)->lockingThread] ) ); ImGui::Unindent( ty ); break; } @@ -3446,15 +1939,15 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, if( ptr->sharedList == 0 ) { assert( ptr->lockCount == 1 ); - ImGui::Text( "Thread \"%s\" has lock. No other threads are waiting.", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" has lock. No other threads are waiting.", m_worker.GetThreadString( tid ) ); } else if( TracyCountBits( ptr->sharedList ) == 1 ) { - ImGui::Text( "Thread \"%s\" has a sole shared lock. No other threads are waiting.", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" has a sole shared lock. No other threads are waiting.", m_worker.GetThreadString( tid ) ); } else { - ImGui::Text( "Thread \"%s\" has shared lock. No other threads are waiting.", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" has shared lock. No other threads are waiting.", m_worker.GetThreadString( tid ) ); ImGui::Text( "Threads sharing the lock (%i):", TracyCountBits( ptr->sharedList ) - 1 ); auto sharedList = ptr->sharedList; int t = 0; @@ -3463,7 +1956,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( sharedList & 0x1 && t != thread ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[t] ) ); } sharedList >>= 1; t++; @@ -3476,15 +1969,15 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, if( ptr->sharedList == 0 ) { assert( ptr->lockCount == 1 ); - ImGui::Text( "Thread \"%s\" has lock. Blocked threads (%i):", GetThreadString( tid ), TracyCountBits( ptr->waitList ) + TracyCountBits( ptr->waitShared ) ); + ImGui::Text( "Thread \"%s\" has lock. Blocked threads (%i):", m_worker.GetThreadString( tid ), TracyCountBits( ptr->waitList ) + TracyCountBits( ptr->waitShared ) ); } else if( TracyCountBits( ptr->sharedList ) == 1 ) { - ImGui::Text( "Thread \"%s\" has a sole shared lock. Blocked threads (%i):", GetThreadString( tid ), TracyCountBits( ptr->waitList ) + TracyCountBits( ptr->waitShared ) ); + ImGui::Text( "Thread \"%s\" has a sole shared lock. Blocked threads (%i):", m_worker.GetThreadString( tid ), TracyCountBits( ptr->waitList ) + TracyCountBits( ptr->waitShared ) ); } else { - ImGui::Text( "Thread \"%s\" has shared lock.", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" has shared lock.", m_worker.GetThreadString( tid ) ); ImGui::Text( "Threads sharing the lock (%i):", TracyCountBits( ptr->sharedList ) - 1 ); auto sharedList = ptr->sharedList; int t = 0; @@ -3493,7 +1986,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( sharedList & 0x1 && t != thread ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[t] ) ); } sharedList >>= 1; t++; @@ -3509,7 +2002,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( waitList & 0x1 ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[t] ) ); } waitList >>= 1; t++; @@ -3520,7 +2013,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( waitShared & 0x1 ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[t] ) ); } waitShared >>= 1; t++; @@ -3533,16 +2026,16 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, assert( ptr->lockCount == 0 || ptr->lockCount == 1 ); if( ptr->lockCount != 0 || ptr->sharedList != 0 ) { - ImGui::Text( "Thread \"%s\" is blocked by other threads (%i):", GetThreadString( tid ), ptr->lockCount + TracyCountBits( ptr->sharedList ) ); + ImGui::Text( "Thread \"%s\" is blocked by other threads (%i):", m_worker.GetThreadString( tid ), ptr->lockCount + TracyCountBits( ptr->sharedList ) ); } else { - ImGui::Text( "Thread \"%s\" waits to obtain lock after release by thread:", GetThreadString( tid ) ); + ImGui::Text( "Thread \"%s\" waits to obtain lock after release by thread:", m_worker.GetThreadString( tid ) ); } ImGui::Indent( ty ); if( ptr->lockCount != 0 ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[ptr->lockingThread] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[ptr->lockingThread] ) ); } auto sharedList = ptr->sharedList; int t = 0; @@ -3550,7 +2043,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, { if( sharedList & 0x1 ) { - ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) ); + ImGui::Text( "\"%s\"", m_worker.GetThreadString( lockmap.threadList[t] ) ); } sharedList >>= 1; t++; @@ -3602,7 +2095,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, if( drawn ) { char buf[1024]; - sprintf( buf, "%" PRIu32 ": %s", v.first, GetString( srcloc.function ) ); + sprintf( buf, "%" PRIu32 ": %s", v.first, m_worker.GetString( srcloc.function ) ); DrawTextContrast( draw, wpos + ImVec2( 0, offset ), 0xFF8888FF, buf ); if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + ImGui::CalcTextSize( buf ).x, offset + ty ) ) ) { @@ -3622,9 +2115,9 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, ImGui::Text( "Thread list:" ); ImGui::Separator(); ImGui::Indent( ty ); - for( auto& t : v.second.threadList ) + for( const auto& t : v.second.threadList ) { - ImGui::Text( "%s", GetThreadString( t ) ); + ImGui::Text( "%s", m_worker.GetThreadString( t ) ); } ImGui::Unindent( ty ); ImGui::Separator(); @@ -3651,13 +2144,14 @@ int View::DrawPlots( int offset, double pxns, const ImVec2& wpos, bool hover ) const auto th = ( ty - to ) * sqrt( 3 ) * 0.5; const auto nspx = 1.0 / pxns; - for( auto& v : m_plots ) + for( const auto& v : m_worker.GetPlots() ) { - if( !v->visible ) continue; + if( !Visible( v ) ) continue; assert( !v->data.empty() ); - if( v->showFull ) + bool& showFull = ShowFull( v ); + if( showFull ) { draw->AddTriangleFilled( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( ty - to/2, offset + to/2 ), wpos + ImVec2( ty * 0.5, offset + to/2 + th ), 0xFF44DDDD ); } @@ -3665,15 +2159,15 @@ int View::DrawPlots( int offset, double pxns, const ImVec2& wpos, bool hover ) { draw->AddTriangle( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( to/2, offset + ty - to/2 ), wpos + ImVec2( to/2 + th, offset + ty * 0.5 ), 0xFF226E6E ); } - const auto txt = GetString( v->name ); - draw->AddText( wpos + ImVec2( ty, offset ), v->showFull ? 0xFF44DDDD : 0xFF226E6E, txt ); + const auto txt = m_worker.GetString( v->name ); + draw->AddText( wpos + ImVec2( ty, offset ), showFull ? 0xFF44DDDD : 0xFF226E6E, txt ); draw->AddLine( wpos + ImVec2( 0, offset + ty - 1 ), wpos + ImVec2( w, offset + ty - 1 ), 0x8844DDDD ); if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + ImGui::CalcTextSize( txt ).x, offset + ty ) ) ) { if( ImGui::IsMouseClicked( 0 ) ) { - v->showFull = !v->showFull; + showFull = !showFull; } const auto tr = v->data.back().time - v->data.front().time; @@ -3700,11 +2194,11 @@ int View::DrawPlots( int offset, double pxns, const ImVec2& wpos, bool hover ) offset += ty; - if( v->showFull ) + if( showFull ) { - auto& vec = v->data; - auto it = std::lower_bound( vec.begin(), vec.end(), m_zvStart - m_delay, [] ( const auto& l, const auto& r ) { return l.time < r; } ); - auto end = std::lower_bound( it, vec.end(), m_zvEnd + m_resolution, [] ( const auto& l, const auto& r ) { return l.time < r; } ); + const auto& vec = v->data; + auto it = std::lower_bound( vec.begin(), vec.end(), m_zvStart - m_worker.GetDelay(), [] ( const auto& l, const auto& r ) { return l.time < r; } ); + auto end = std::lower_bound( it, vec.end(), m_zvEnd + m_worker.GetResolution(), [] ( const auto& l, const auto& r ) { return l.time < r; } ); if( end != vec.end() ) end++; if( it != vec.begin() ) it--; @@ -3885,33 +2379,33 @@ void View::DrawZoneInfoWindow() ImGui::Separator(); - auto& srcloc = GetSourceLocation( ev.srcloc ); + const auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); if( srcloc.name.active ) { - ImGui::Text( "Zone name: %s", GetString( srcloc.name ) ); + ImGui::Text( "Zone name: %s", m_worker.GetString( srcloc.name ) ); } - ImGui::Text( "Function: %s", GetString( srcloc.function ) ); - ImGui::Text( "Location: %s:%i", GetString( srcloc.file ), srcloc.line ); + ImGui::Text( "Function: %s", m_worker.GetString( srcloc.function ) ); + ImGui::Text( "Location: %s:%i", m_worker.GetString( srcloc.file ), srcloc.line ); if( ev.text.active ) { - ImGui::Text( "User text: %s", GetString( ev.text ) ); + ImGui::Text( "User text: %s", m_worker.GetString( ev.text ) ); dmul++; } ImGui::Separator(); - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); const auto ztime = end - ev.start; - ImGui::Text( "Time from start of program: %s", TimeToString( ev.start - m_frames[0] ) ); + ImGui::Text( "Time from start of program: %s", TimeToString( ev.start - m_worker.GetFrameBegin( 0 ) ) ); ImGui::Text( "Execution time: %s", TimeToString( ztime ) ); - ImGui::Text( "Without profiling: %s", TimeToString( ztime - m_delay * dmul ) ); + ImGui::Text( "Without profiling: %s", TimeToString( ztime - m_worker.GetDelay() * dmul ) ); auto ctt = std::make_unique( ev.child.size() ); auto cti = std::make_unique( ev.child.size() ); uint64_t ctime = 0; for( size_t i=0; istart; ctime += ct; ctt[i] = ct; @@ -3933,14 +2427,14 @@ void View::DrawZoneInfoWindow() for( size_t i=0; igpuStart; ctime += ct; ctt[i] = ct; @@ -4034,8 +2528,8 @@ void View::DrawGpuInfoWindow() for( size_t i=0; ivisible ); + ImGui::Checkbox( buf, &Visible( m_worker.GetGpuData()[i] ) ); } ImGui::Unindent( tw ); ImGui::Checkbox( "Draw CPU zones", &m_drawZones ); @@ -4086,30 +2580,30 @@ void View::DrawOptions() ImGui::SameLine(); ImGui::Checkbox( "Only contended", &m_onlyContendedLocks ); ImGui::Indent( tw ); - for( auto& l : m_lockMap ) + for( const auto& l : m_worker.GetLockMap() ) { if( l.second.valid ) { char buf[1024]; - sprintf( buf, "%" PRIu32 ": %s", l.first, GetString( GetSourceLocation( l.second.srcloc ).function ) ); - ImGui::Checkbox( buf , &l.second.visible ); + sprintf( buf, "%" PRIu32 ": %s", l.first, m_worker.GetString( m_worker.GetSourceLocation( l.second.srcloc ).function ) ); + ImGui::Checkbox( buf, &Visible( &l.second ) ); } } ImGui::Unindent( tw ); ImGui::Separator(); ImGui::Checkbox( "Draw plots", &m_drawPlots ); ImGui::Indent( tw ); - for( auto& p : m_plots ) + for( const auto& p : m_worker.GetPlots() ) { - ImGui::Checkbox( GetString( p->name ), &p->visible ); + ImGui::Checkbox( m_worker.GetString( p->name ), &Visible( p ) ); } ImGui::Unindent( tw ); ImGui::Separator(); ImGui::Text( "Visible threads:" ); ImGui::Indent( tw ); - for( auto& t : m_threads ) + for( const auto& t : m_worker.GetThreadData() ) { - ImGui::Checkbox( GetThreadString( t->id ), &t->visible ); + ImGui::Checkbox( m_worker.GetThreadString( t->id ), &Visible( t ) ); } ImGui::Unindent( tw ); ImGui::End(); @@ -4118,10 +2612,10 @@ void View::DrawOptions() void View::DrawMessages() { ImGui::Begin( "Messages", &m_showMessages ); - for( auto& v : m_messages ) + for( const auto& v : m_worker.GetMessages() ) { char tmp[64 * 1024]; - sprintf( tmp, "%10s | %s", TimeToString( v->time - m_frames[0] ), GetString( v->ref ) ); + sprintf( tmp, "%10s | %s", TimeToString( v->time - m_worker.GetFrameBegin( 0 ) ), m_worker.GetString( v->ref ) ); if( m_msgHighlight == v ) { ImGui::TextColored( ImVec4( 0xDD / 255.f, 0x22 / 255.f, 0x22 / 255.f, 1.f ), "%s", tmp ); @@ -4186,7 +2680,7 @@ void View::DrawFindZone() { for( auto& ev : v->timeline ) { - const auto timeSpan = GetZoneEnd( *ev ) - ev->start; + const auto timeSpan = m_worker.GetZoneEnd( *ev ) - ev->start; tmin = std::min( tmin, timeSpan ); tmax = std::max( tmax, timeSpan ); } @@ -4222,7 +2716,7 @@ void View::DrawFindZone() { for( auto& ev : v->timeline ) { - const auto timeSpan = GetZoneEnd( *ev ) - ev->start; + const auto timeSpan = m_worker.GetZoneEnd( *ev ) - ev->start; const auto bin = std::min( numBins - 1, int64_t( ( log10( timeSpan ) - tMinLog ) * idt ) ); bins[bin]++; binTime[bin] += timeSpan; @@ -4236,7 +2730,7 @@ void View::DrawFindZone() { for( auto& ev : v->timeline ) { - const auto timeSpan = GetZoneEnd( *ev ) - ev->start; + const auto timeSpan = m_worker.GetZoneEnd( *ev ) - ev->start; const auto bin = std::min( numBins - 1, int64_t( ( timeSpan - tmin ) * idt ) ); bins[bin]++; binTime[bin] += timeSpan; @@ -4378,13 +2872,13 @@ void View::DrawFindZone() ImGui::Separator(); for( auto& v : m_findZone.result ) { - const bool expand = ImGui::TreeNode( GetThreadString( v->id ) ); + const bool expand = ImGui::TreeNode( m_worker.GetThreadString( v->id ) ); ImGui::SameLine(); ImGui::TextColored( ImVec4( 0.5f, 0.5f, 0.5f, 1.0f ), "(%s)", RealToString( v->timeline.size(), true ) ); if( expand ) { - ImGui::Columns( 3, GetThreadString( v->id ) ); + ImGui::Columns( 3, m_worker.GetThreadString( v->id ) ); ImGui::Separator(); ImGui::Text( "Name" ); ImGui::NextColumn(); @@ -4398,17 +2892,17 @@ void View::DrawFindZone() { ImGui::PushID( ev ); - auto& srcloc = GetSourceLocation( ev->srcloc ); - if( ImGui::Selectable( GetString( srcloc.name.active ? srcloc.name : srcloc.function ), m_zoneInfoWindow == ev, ImGuiSelectableFlags_SpanAllColumns ) ) + auto& srcloc = m_worker.GetSourceLocation( ev->srcloc ); + if( ImGui::Selectable( m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ), m_zoneInfoWindow == ev, ImGuiSelectableFlags_SpanAllColumns ) ) { m_zoneInfoWindow = ev; } ImGui::NextColumn(); - ImGui::Text( TimeToString( ev->start - m_frames[0] ) ); + ImGui::Text( TimeToString( ev->start - m_worker.GetFrameBegin( 0 ) ) ); ImGui::NextColumn(); - const auto end = GetZoneEnd( *ev ); + const auto end = m_worker.GetZoneEnd( *ev ); ImGui::Text( TimeToString( end - ev->start ) ); ImGui::NextColumn(); @@ -4426,14 +2920,14 @@ void View::DrawFindZone() uint32_t View::GetZoneColor( const ZoneEvent& ev ) { - auto& srcloc = GetSourceLocation( ev.srcloc ); + const auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); const auto color = srcloc.color; return color != 0 ? ( color | 0xFF000000 ) : 0xFFCC5555; } uint32_t View::GetZoneColor( const GpuEvent& ev ) { - auto& srcloc = GetSourceLocation( ev.srcloc ); + const auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); const auto color = srcloc.color; return color != 0 ? ( color | 0xFF000000 ) : 0xFF222288; } @@ -4508,14 +3002,14 @@ float View::GetZoneThickness( const GpuEvent& ev ) void View::ZoomToZone( const ZoneEvent& ev ) { - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); if( end - ev.start <= 0 ) return; ZoomToRange( ev.start, end ); } void View::ZoomToZone( const GpuEvent& ev ) { - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); if( end - ev.gpuStart <= 0 ) return; ZoomToRange( ev.gpuStart, end ); } @@ -4540,24 +3034,24 @@ void View::ZoneTooltip( const ZoneEvent& ev ) { int dmul = ev.text.active ? 2 : 1; - auto& srcloc = GetSourceLocation( ev.srcloc ); + auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); - const auto filename = GetString( srcloc.file ); + const auto filename = m_worker.GetString( srcloc.file ); const auto line = srcloc.line; const char* func; const char* zoneName; if( srcloc.name.active ) { - zoneName = GetString( srcloc.name ); - func = GetString( srcloc.function ); + zoneName = m_worker.GetString( srcloc.name ); + func = m_worker.GetString( srcloc.function ); } else { - func = zoneName = GetString( srcloc.function ); + func = zoneName = m_worker.GetString( srcloc.function ); } - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); ImGui::BeginTooltip(); if( srcloc.name.active ) @@ -4572,7 +3066,7 @@ void View::ZoneTooltip( const ZoneEvent& ev ) ImGui::Separator(); ImGui::Text( "%s:%i", filename, line ); ImGui::Text( "Execution time: %s", TimeToString( end - ev.start ) ); - ImGui::Text( "Without profiling: %s", TimeToString( end - ev.start - m_delay * dmul ) ); + ImGui::Text( "Without profiling: %s", TimeToString( end - ev.start - m_worker.GetDelay() * dmul ) ); if( ev.cpu_start != -1 ) { if( ev.end == -1 || ev.cpu_start == ev.cpu_end ) @@ -4587,21 +3081,21 @@ void View::ZoneTooltip( const ZoneEvent& ev ) if( ev.text.active ) { ImGui::NewLine(); - ImGui::TextColored( ImVec4( 0xCC / 255.f, 0xCC / 255.f, 0x22 / 255.f, 1.f ), "%s", GetString( ev.text ) ); + ImGui::TextColored( ImVec4( 0xCC / 255.f, 0xCC / 255.f, 0x22 / 255.f, 1.f ), "%s", m_worker.GetString( ev.text ) ); } ImGui::EndTooltip(); } void View::ZoneTooltip( const GpuEvent& ev ) { - auto& srcloc = GetSourceLocation( ev.srcloc ); + const auto& srcloc = m_worker.GetSourceLocation( ev.srcloc ); - const auto name = GetString( srcloc.name ); - const auto filename = GetString( srcloc.file ); + const auto name = m_worker.GetString( srcloc.name ); + const auto filename = m_worker.GetString( srcloc.file ); const auto line = srcloc.line; - const auto func = GetString( srcloc.function ); + const auto func = m_worker.GetString( srcloc.function ); - const auto end = GetZoneEnd( ev ); + const auto end = m_worker.GetZoneEnd( ev ); ImGui::BeginTooltip(); ImGui::Text( "%s", name ); @@ -4617,7 +3111,7 @@ void View::ZoneTooltip( const GpuEvent& ev ) const ZoneEvent* View::GetZoneParent( const ZoneEvent& zone ) const { - for( auto& thread : m_threads ) + for( const auto& thread : m_worker.GetThreadData() ) { const ZoneEvent* parent = nullptr; const Vector* timeline = &thread->timeline; @@ -4638,7 +3132,7 @@ const ZoneEvent* View::GetZoneParent( const ZoneEvent& zone ) const const GpuEvent* View::GetZoneParent( const GpuEvent& zone ) const { - for( auto& ctx : m_gpuData ) + for( const auto& ctx : m_worker.GetGpuData() ) { const GpuEvent* parent = nullptr; const Vector* timeline = &ctx->timeline; @@ -4659,7 +3153,7 @@ const GpuEvent* View::GetZoneParent( const GpuEvent& zone ) const void View::FindZones() { - for( auto& v : m_threads ) + for( const auto& v : m_worker.GetThreadData() ) { auto thrOut = std::make_unique(); FindZones( v->timeline, thrOut->timeline, m_findZone.maxDepth ); @@ -4677,10 +3171,10 @@ void View::FindZones( const Vector& events, Vector& out, for( auto& ev : events ) { if( out.size() >= m_findZone.maxZonesPerThread ) break; - if( GetZoneEnd( *ev ) == ev->start ) continue; + if( m_worker.GetZoneEnd( *ev ) == ev->start ) continue; - auto& srcloc = GetSourceLocation( ev->srcloc ); - auto str = GetString( srcloc.name.active ? srcloc.name : srcloc.function ); + const auto& srcloc = m_worker.GetSourceLocation( ev->srcloc ); + const auto str = m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ); if( strstr( str, m_findZone.pattern ) != nullptr ) { @@ -4694,227 +3188,4 @@ void View::FindZones( const Vector& events, Vector& out, } } -void View::Write( FileWrite& f ) -{ - f.Write( &m_delay, sizeof( m_delay ) ); - f.Write( &m_resolution, sizeof( m_resolution ) ); - f.Write( &m_timerMul, sizeof( m_timerMul ) ); - f.Write( &m_lastTime, sizeof( m_lastTime ) ); - - uint64_t sz = m_captureName.size(); - f.Write( &sz, sizeof( sz ) ); - f.Write( m_captureName.c_str(), sz ); - - sz = m_frames.size(); - f.Write( &sz, sizeof( sz ) ); - f.Write( m_frames.data(), sizeof( uint64_t ) * sz ); - - sz = m_stringData.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_stringData ) - { - uint64_t ptr = (uint64_t)v; - f.Write( &ptr, sizeof( ptr ) ); - sz = strlen( v ); - f.Write( &sz, sizeof( sz ) ); - f.Write( v, sz ); - } - - sz = m_strings.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_strings ) - { - f.Write( &v.first, sizeof( v.first ) ); - uint64_t ptr = (uint64_t)v.second; - f.Write( &ptr, sizeof( ptr ) ); - } - - sz = m_threadNames.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_threadNames ) - { - f.Write( &v.first, sizeof( v.first ) ); - uint64_t ptr = (uint64_t)v.second; - f.Write( &ptr, sizeof( ptr ) ); - } - - sz = m_sourceLocation.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_sourceLocation ) - { - f.Write( &v.first, sizeof( v.first ) ); - f.Write( &v.second, sizeof( v.second ) ); - } - - sz = m_sourceLocationExpand.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_sourceLocationExpand ) - { - f.Write( &v, sizeof( v ) ); - } - - sz = m_sourceLocationPayload.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_sourceLocationPayload ) - { - f.Write( v, sizeof( *v ) ); - } - - sz = m_lockMap.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_lockMap ) - { - f.Write( &v.first, sizeof( v.first ) ); - f.Write( &v.second.srcloc, sizeof( v.second.srcloc ) ); - f.Write( &v.second.type, sizeof( v.second.type ) ); - f.Write( &v.second.valid, sizeof( v.second.valid ) ); - sz = v.second.threadList.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& t : v.second.threadList ) - { - f.Write( &t, sizeof( t ) ); - } - sz = v.second.timeline.size(); - f.Write( &sz, sizeof( sz ) ); - if( v.second.type == LockType::Lockable ) - { - for( auto& lev : v.second.timeline ) - { - f.Write( lev, sizeof( LockEvent ) ); - } - } - else - { - for( auto& lev : v.second.timeline ) - { - f.Write( lev, sizeof( LockEventShared ) ); - } - } - } - - sz = m_messages.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : m_messages ) - { - const auto ptr = (uint64_t)v; - f.Write( &ptr, sizeof( ptr ) ); - f.Write( v, sizeof( *v ) ); - } - - sz = m_threads.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& thread : m_threads ) - { - f.Write( &thread->id, sizeof( thread->id ) ); - f.Write( &thread->count, sizeof( thread->count ) ); - WriteTimeline( f, thread->timeline ); - sz = thread->messages.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& v : thread->messages ) - { - auto ptr = uint64_t( v ); - f.Write( &ptr, sizeof( ptr ) ); - } - } - - sz = m_gpuData.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& ctx : m_gpuData ) - { - f.Write( &ctx->thread, sizeof( ctx->thread ) ); - f.Write( &ctx->accuracyBits, sizeof( ctx->accuracyBits ) ); - f.Write( &ctx->count, sizeof( ctx->count ) ); - WriteTimeline( f, ctx->timeline ); - } - - sz = m_plots.size(); - f.Write( &sz, sizeof( sz ) ); - for( auto& plot : m_plots ) - { - f.Write( &plot->name, sizeof( plot->name ) ); - f.Write( &plot->min, sizeof( plot->min ) ); - f.Write( &plot->max, sizeof( plot->max ) ); - sz = plot->data.size(); - f.Write( &sz, sizeof( sz ) ); - f.Write( plot->data.data(), sizeof( PlotItem ) * sz ); - } -} - -void View::WriteTimeline( FileWrite& f, const Vector& vec ) -{ - uint64_t sz = vec.size(); - f.Write( &sz, sizeof( sz ) ); - - for( auto& v : vec ) - { - f.Write( &v->start, sizeof( v->start ) ); - f.Write( &v->end, sizeof( v->end ) ); - f.Write( &v->srcloc, sizeof( v->srcloc ) ); - f.Write( &v->cpu_start, sizeof( v->cpu_start ) ); - f.Write( &v->cpu_end, sizeof( v->cpu_end ) ); - f.Write( &v->text, sizeof( v->text ) ); - WriteTimeline( f, v->child ); - } -} - -void View::WriteTimeline( FileWrite& f, const Vector& vec ) -{ - uint64_t sz = vec.size(); - f.Write( &sz, sizeof( sz ) ); - - for( auto& v : vec ) - { - f.Write( &v->cpuStart, sizeof( v->cpuStart ) ); - f.Write( &v->cpuEnd, sizeof( v->cpuEnd ) ); - f.Write( &v->gpuStart, sizeof( v->gpuStart ) ); - f.Write( &v->gpuEnd, sizeof( v->gpuEnd ) ); - f.Write( &v->srcloc, sizeof( v->srcloc ) ); - WriteTimeline( f, v->child ); - } -} - -void View::ReadTimeline( FileRead& f, Vector& vec ) -{ - uint64_t sz; - f.Read( &sz, sizeof( sz ) ); - vec.reserve( sz ); - - for( uint64_t i=0; i(); - - m_zonesCnt++; - vec.push_back( zone ); - - f.Read( &zone->start, sizeof( zone->start ) ); - f.Read( &zone->end, sizeof( zone->end ) ); - f.Read( &zone->srcloc, sizeof( zone->srcloc ) ); - f.Read( &zone->cpu_start, sizeof( zone->cpu_start ) ); - f.Read( &zone->cpu_end, sizeof( zone->cpu_end ) ); - f.Read( &zone->text, sizeof( zone->text ) ); - ReadTimeline( f, zone->child ); - } -} - -void View::ReadTimeline( FileRead& f, Vector& vec ) -{ - uint64_t sz; - f.Read( &sz, sizeof( sz ) ); - vec.reserve( sz ); - - for( uint64_t i=0; i(); - - vec.push_back( zone ); - - f.Read( &zone->cpuStart, sizeof( zone->cpuStart ) ); - f.Read( &zone->cpuEnd, sizeof( zone->cpuEnd ) ); - f.Read( &zone->gpuStart, sizeof( zone->gpuStart ) ); - f.Read( &zone->gpuEnd, sizeof( zone->gpuEnd ) ); - f.Read( &zone->srcloc, sizeof( zone->srcloc ) ); - ReadTimeline( f, zone->child ); - } -} - } diff --git a/server/TracyView.hpp b/server/TracyView.hpp index b8a105f5..757c2a8c 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -8,13 +8,8 @@ #include #include -#include "../common/tracy_lz4.hpp" -#include "../common/TracySocket.hpp" -#include "../common/TracyQueue.hpp" -#include "TracyCharUtil.hpp" -#include "TracyEvent.hpp" -#include "TracySlab.hpp" #include "TracyVector.hpp" +#include "TracyWorker.hpp" #include "tracy_benaphore.h" #include "tracy_flat_hash_map.hpp" @@ -25,17 +20,9 @@ namespace tracy struct QueueItem; class FileRead; -class FileWrite; class View { - template - struct nohash - { - size_t operator()( const T& v ) { return (size_t)v; } - typedef tracy::power_of_two_hash_policy hash_policy; - }; - struct Animation { bool active = false; @@ -51,7 +38,6 @@ public: View( FileRead& f ); ~View(); - static bool ShouldExit(); static void Draw(); private: @@ -62,76 +48,6 @@ private: Short }; - void Worker(); - - tracy_force_inline void DispatchProcess( const QueueItem& ev, char*& ptr ); - - void ServerQuery( uint8_t type, uint64_t data ); - - tracy_force_inline void Process( const QueueItem& ev ); - tracy_force_inline void ProcessZoneBegin( const QueueZoneBegin& ev ); - tracy_force_inline void ProcessZoneBeginAllocSrcLoc( const QueueZoneBegin& ev ); - tracy_force_inline void ProcessZoneEnd( const QueueZoneEnd& ev ); - tracy_force_inline void ProcessFrameMark( const QueueFrameMark& ev ); - tracy_force_inline void ProcessZoneText( const QueueZoneText& ev ); - tracy_force_inline void ProcessLockAnnounce( const QueueLockAnnounce& ev ); - tracy_force_inline void ProcessLockWait( const QueueLockWait& ev ); - tracy_force_inline void ProcessLockObtain( const QueueLockObtain& ev ); - tracy_force_inline void ProcessLockRelease( const QueueLockRelease& ev ); - tracy_force_inline void ProcessLockSharedWait( const QueueLockWait& ev ); - tracy_force_inline void ProcessLockSharedObtain( const QueueLockObtain& ev ); - tracy_force_inline void ProcessLockSharedRelease( const QueueLockRelease& ev ); - tracy_force_inline void ProcessLockMark( const QueueLockMark& ev ); - tracy_force_inline void ProcessPlotData( const QueuePlotData& ev ); - tracy_force_inline void ProcessMessage( const QueueMessage& ev ); - tracy_force_inline void ProcessMessageLiteral( const QueueMessage& ev ); - tracy_force_inline void ProcessGpuNewContext( const QueueGpuNewContext& ev ); - tracy_force_inline void ProcessGpuZoneBegin( const QueueGpuZoneBegin& ev ); - tracy_force_inline void ProcessGpuZoneEnd( const QueueGpuZoneEnd& ev ); - tracy_force_inline void ProcessGpuTime( const QueueGpuTime& ev ); - tracy_force_inline void ProcessGpuResync( const QueueGpuResync& ev ); - - void CheckString( uint64_t ptr ); - void CheckThreadString( uint64_t id ); - - tracy_force_inline void CheckSourceLocation( uint64_t ptr ); - void NewSourceLocation( uint64_t ptr ); - - void AddString( uint64_t ptr, char* str, size_t sz ); - void AddThreadString( uint64_t id, char* str, size_t sz ); - void AddCustomString( uint64_t ptr, char* str, size_t sz ); - void AddSourceLocation( const QueueSourceLocation& srcloc ); - void AddSourceLocationPayload( uint64_t ptr, char* data, size_t sz ); - - StringLocation StoreString( char* str, size_t sz ); - - tracy_force_inline uint32_t ShrinkSourceLocation( uint64_t srcloc ); - uint32_t NewShrinkedSourceLocation( uint64_t srcloc ); - - void InsertMessageData( MessageData* msg, uint64_t thread ); - - tracy_force_inline ThreadData* NoticeThread( uint64_t thread ); - ThreadData* NewThread( uint64_t thread ); - - tracy_force_inline void NewZone( ZoneEvent* zone, uint64_t thread ); - - void InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread ); - - void InsertPlot( PlotData* plot, int64_t time, double val ); - void HandlePlotName( uint64_t name, char* str, size_t sz ); - void HandlePostponedPlots(); - - int64_t GetFrameTime( size_t idx ) const; - int64_t GetFrameBegin( size_t idx ) const; - int64_t GetFrameEnd( size_t idx ) const; - int64_t GetZoneEnd( const ZoneEvent& ev ) const; - int64_t GetZoneEnd( const GpuEvent& ev ) const; - const char* GetString( uint64_t ptr ) const; - const char* GetString( const StringRef& ref ) const; - const char* GetString( const StringIdx& idx ) const; - const char* GetThreadString( uint64_t id ) const; - const SourceLocation& GetSourceLocation( int32_t srcloc ) const; - const char* ShortenNamespace( const char* name ) const; void DrawHelpMarker( const char* desc ) const; @@ -177,69 +93,33 @@ private: void FindZones(); void FindZones( const Vector &events, Vector &out, const int maxdepth = 0 ); - void Write( FileWrite& f ); - void WriteTimeline( FileWrite& f, const Vector& vec ); - void WriteTimeline( FileWrite& f, const Vector& vec ); - void ReadTimeline( FileRead& f, Vector& vec ); - void ReadTimeline( FileRead& f, Vector& vec ); + template + bool& Visible( const T* ptr ) + { + static std::map visible; + if( visible.find( ptr ) == visible.end() ) + { + visible[ptr] = true; + } - int64_t TscTime( int64_t tsc ) { return int64_t( tsc * m_timerMul ); } - int64_t TscTime( uint64_t tsc ) { return int64_t( tsc * m_timerMul ); } + return visible[ptr]; + } - std::string m_addr; + template + bool& ShowFull( const T* ptr ) + { + static std::map showFull; + if( showFull.find( ptr ) == showFull.end() ) + { + showFull[ptr] = true; + } - Socket m_sock; - std::thread m_thread; - std::atomic m_shutdown; - std::atomic m_connected; - std::atomic m_hasData; + return showFull[ptr]; + } + + Worker m_worker; bool m_staticView; - // this block must be locked - NonRecursiveBenaphore m_lock; - Vector m_frames; - Vector m_threads; - Vector m_plots; - Vector m_messages; - Vector m_gpuData; - flat_hash_map> m_strings; - flat_hash_map> m_threadNames; - flat_hash_map> m_sourceLocation; - std::vector m_sourceLocationExpand; - std::map m_lockMap; - uint64_t m_zonesCnt; - - Vector m_stringData; - std::unordered_map m_stringMap; - - Vector m_sourceLocationPayload; - flat_hash_map m_sourceLocationPayloadMap; - - NonRecursiveBenaphore m_mbpslock; - std::vector m_mbps; - float m_compRatio; - - // not used for vis - no need to lock - flat_hash_map> m_pendingCustomStrings; - flat_hash_map> m_threadMap; - flat_hash_map> m_gpuCtxMap; - flat_hash_map> m_plotMap; - std::unordered_map m_plotRev; - flat_hash_map> m_pendingPlots; - flat_hash_map> m_sourceLocationShrink; - flat_hash_map> m_pendingSourceLocationPayload; - Vector m_sourceLocationQueue; - - uint32_t m_pendingStrings; - uint32_t m_pendingThreads; - uint32_t m_pendingSourceLocation; - - Slab<64*1024*1024> m_slab; - - LZ4_streamDecode_t* m_stream; - char* m_buffer; - int m_bufferOffset; - int m_frameScale; bool m_pause; int m_frameStart; @@ -248,11 +128,6 @@ private: int64_t m_zvEnd; int64_t m_lastTime; - int64_t m_delay; - int64_t m_resolution; - double m_timerMul; - std::string m_captureName; - int8_t m_lastCpu; int m_zvHeight; @@ -294,8 +169,6 @@ private: bool logVal = false; bool logTime = false; } m_findZone; - - bool m_terminate; }; } diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp new file mode 100644 index 00000000..aaa40d4d --- /dev/null +++ b/server/TracyWorker.cpp @@ -0,0 +1,1749 @@ +#include + +#include "../common/TracyProtocol.hpp" +#include "../common/TracySystem.hpp" +#include "TracyFileRead.hpp" +#include "TracyFileWrite.hpp" +#include "TracyWorker.hpp" + +namespace tracy +{ + +Worker::Worker( const char* addr ) + : m_addr( addr ) + , m_connected( false ) + , m_hasData( false ) + , m_shutdown( false ) + , m_terminate( false ) + , m_stream( LZ4_createStreamDecode() ) + , m_buffer( new char[TargetFrameSize*3 + 1] ) + , m_bufferOffset( 0 ) + , m_pendingStrings( 0 ) + , m_pendingThreads( 0 ) + , m_pendingSourceLocation( 0 ) +{ + m_data.sourceLocationExpand.push_back( 0 ); + + m_thread = std::thread( [this] { Exec(); } ); + SetThreadName( m_thread, "Tracy Worker" ); +} + +Worker::Worker( FileRead& f ) + : m_connected( false ) + , m_hasData( true ) + , m_shutdown( false ) + , m_terminate( false ) + , m_stream( nullptr ) + , m_buffer( nullptr ) +{ + f.Read( &m_delay, sizeof( m_delay ) ); + f.Read( &m_resolution, sizeof( m_resolution ) ); + f.Read( &m_timerMul, sizeof( m_timerMul ) ); + f.Read( &m_data.lastTime, sizeof( m_data.lastTime ) ); + + uint64_t sz; + { + f.Read( &sz, sizeof( sz ) ); + assert( sz < 1024 ); + char tmp[1024]; + f.Read( tmp, sz ); + m_captureName = std::string( tmp, tmp+sz ); + } + + f.Read( &sz, sizeof( sz ) ); + m_data.frames.reserve( sz ); + for( uint64_t i=0; i pointerMap; + + f.Read( &sz, sizeof( sz ) ); + for( uint64_t i=0; i( ssz+1 ); + f.Read( dst, ssz ); + dst[ssz] = '\0'; + m_data.stringData.push_back( dst ); + pointerMap.emplace( ptr, dst ); + } + + f.Read( &sz, sizeof( sz ) ); + for( uint64_t i=0; isecond ); + } + + f.Read( &sz, sizeof( sz ) ); + for( uint64_t i=0; isecond ); + } + + f.Read( &sz, sizeof( sz ) ); + for( uint64_t i=0; i(); + f.Read( srcloc, sizeof( *srcloc ) ); + m_data.sourceLocationPayload.push_back( srcloc ); + } + + f.Read( &sz, sizeof( sz ) ); + for( uint64_t i=0; i(); + f.Read( lev, sizeof( LockEvent ) ); + lockmap.timeline.push_back( lev ); + } + } + else + { + for( uint64_t i=0; i(); + f.Read( lev, sizeof( LockEventShared ) ); + lockmap.timeline.push_back( lev ); + } + } + m_data.lockMap.emplace( id, std::move( lockmap ) ); + } + + std::unordered_map msgMap; + f.Read( &sz, sizeof( sz ) ); + m_data.messages.reserve( sz ); + for( uint64_t i=0; i(); + f.Read( msgdata, sizeof( *msgdata ) ); + m_data.messages.push_back( msgdata ); + msgMap.emplace( ptr, msgdata ); + } + + f.Read( &sz, sizeof( sz ) ); + m_data.threads.reserve( sz ); + for( uint64_t i=0; i(); + f.Read( &td->id, sizeof( td->id ) ); + f.Read( &td->count, sizeof( td->count ) ); + ReadTimeline( f, td->timeline ); + uint64_t msz; + f.Read( &msz, sizeof( msz ) ); + td->messages.reserve( msz ); + for( uint64_t j=0; jmessages.push_back( msgMap[ptr] ); + } + m_data.threads.push_back( td ); + } + + f.Read( &sz, sizeof( sz ) ); + m_data.gpuData.reserve( sz ); + for( uint64_t i=0; i(); + f.Read( &ctx->thread, sizeof( ctx->thread ) ); + f.Read( &ctx->accuracyBits, sizeof( ctx->accuracyBits ) ); + f.Read( &ctx->count, sizeof( ctx->count ) ); + ReadTimeline( f, ctx->timeline ); + m_data.gpuData.push_back( ctx ); + } + + f.Read( &sz, sizeof( sz ) ); + m_data.plots.reserve( sz ); + for( uint64_t i=0; i(); + f.Read( &pd->name, sizeof( pd->name ) ); + f.Read( &pd->min, sizeof( pd->min ) ); + f.Read( &pd->max, sizeof( pd->max ) ); + uint64_t psz; + f.Read( &psz, sizeof( psz ) ); + pd->data.reserve_and_use( psz ); + f.Read( pd->data.data(), psz * sizeof( PlotItem ) ); + m_data.plots.push_back( pd ); + } +} + +Worker::~Worker() +{ + delete [] m_buffer; + LZ4_freeStreamDecode( m_stream ); +} + +void Worker::Join() +{ + if ( m_thread.joinable() ) + { + m_thread.join(); + } +} + +int64_t Worker::GetFrameTime( size_t idx ) const +{ + if( idx < m_data.frames.size() - 1 ) + { + return m_data.frames[idx+1] - m_data.frames[idx]; + } + else + { + return m_data.lastTime == 0 ? 0 : m_data.lastTime - m_data.frames.back(); + } +} + +int64_t Worker::GetFrameBegin( size_t idx ) const +{ + assert( idx < m_data.frames.size() ); + return m_data.frames[idx]; +} + +int64_t Worker::GetFrameEnd( size_t idx ) const +{ + if( idx < m_data.frames.size() - 1 ) + { + return m_data.frames[idx+1]; + } + else + { + return m_data.lastTime; + } +} + +std::pair Worker::GetFrameRange( int64_t from, int64_t to ) +{ + const auto zitbegin = std::lower_bound( m_data.frames.begin(), m_data.frames.end(), from ); + if( zitbegin == m_data.frames.end() ) return std::make_pair( -1, -1 ); + const auto zitend = std::lower_bound( zitbegin, m_data.frames.end(), to ); + + int zbegin = std::distance( m_data.frames.begin(), zitbegin ); + if( zbegin > 0 && *zitbegin != from) --zbegin; + const int zend = std::distance( m_data.frames.begin(), zitend ); + + return std::make_pair( zbegin, zend ); +} + +int64_t Worker::GetZoneEnd( const ZoneEvent& ev ) const +{ + auto ptr = &ev; + for(;;) + { + if( ptr->end != -1 ) return ptr->end; + if( ptr->child.empty() ) return ptr->start; + ptr = ptr->child.back(); + } +} + +int64_t Worker::GetZoneEnd( const GpuEvent& ev ) const +{ + auto ptr = &ev; + for(;;) + { + if( ptr->gpuEnd != -1 ) return ptr->gpuEnd; + if( ptr->child.empty() ) return ptr->gpuStart; + ptr = ptr->child.back(); + } +} + +const char* Worker::GetString( uint64_t ptr ) const +{ + const auto it = m_data.strings.find( ptr ); + if( it == m_data.strings.end() || it->second == nullptr ) + { + return "???"; + } + else + { + return it->second; + } +} + +const char* Worker::GetString( const StringRef& ref ) const +{ + if( ref.isidx ) + { + assert( ref.active ); + return m_data.stringData[ref.stridx]; + } + else + { + if( ref.active ) + { + return GetString( ref.strptr ); + } + else + { + return "???"; + } + } +} + +const char* Worker::GetString( const StringIdx& idx ) const +{ + assert( idx.active ); + return m_data.stringData[idx.idx]; +} + +const char* Worker::GetThreadString( uint64_t id ) const +{ + const auto it = m_data.threadNames.find( id ); + if( it == m_data.threadNames.end() ) + { + return "???"; + } + else + { + return it->second; + } +} + +const SourceLocation& Worker::GetSourceLocation( int32_t srcloc ) const +{ + if( srcloc < 0 ) + { + return *m_data.sourceLocationPayload[-srcloc-1]; + } + else + { + const auto it = m_data.sourceLocation.find( m_data.sourceLocationExpand[srcloc] ); + assert( it != m_data.sourceLocation.end() ); + return it->second; + } +} + +void Worker::Exec() +{ + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 10000; + + auto ShouldExit = [this] + { + return m_shutdown.load( std::memory_order_relaxed ); + }; + + for(;;) + { + if( m_shutdown.load( std::memory_order_relaxed ) ) return; + if( !m_sock.Connect( m_addr.c_str(), "8086" ) ) continue; + + std::chrono::time_point t0; + + uint64_t bytes = 0; + uint64_t decBytes = 0; + + { + WelcomeMessage welcome; + if( !m_sock.Read( &welcome, sizeof( welcome ), &tv, ShouldExit ) ) goto close; + m_timerMul = welcome.timerMul; + m_data.frames.push_back( TscTime( welcome.initBegin ) ); + m_data.frames.push_back( TscTime( welcome.initEnd ) ); + m_data.lastTime = m_data.frames.back(); + m_delay = TscTime( welcome.delay ); + m_resolution = TscTime( welcome.resolution ); + + char dtmp[64]; + time_t date = welcome.epoch; + auto lt = localtime( &date ); + strftime( dtmp, 64, "%F %T", lt ); + char tmp[1024]; + sprintf( tmp, "%s @ %s###Profiler", welcome.programName, dtmp ); + m_captureName = tmp; + } + + m_hasData.store( true, std::memory_order_release ); + + LZ4_setStreamDecode( m_stream, nullptr, 0 ); + m_connected.store( true, std::memory_order_relaxed ); + + t0 = std::chrono::high_resolution_clock::now(); + + for(;;) + { + if( m_shutdown.load( std::memory_order_relaxed ) ) return; + + auto buf = m_buffer + m_bufferOffset; + char lz4buf[LZ4Size]; + lz4sz_t lz4sz; + if( !m_sock.Read( &lz4sz, sizeof( lz4sz ), &tv, ShouldExit ) ) goto close; + if( !m_sock.Read( lz4buf, lz4sz, &tv, ShouldExit ) ) goto close; + bytes += sizeof( lz4sz ) + lz4sz; + + auto sz = LZ4_decompress_safe_continue( m_stream, lz4buf, buf, lz4sz, TargetFrameSize ); + assert( sz >= 0 ); + decBytes += sz; + + char* ptr = buf; + const char* end = buf + sz; + + { + std::lock_guard lock( m_data.lock ); + while( ptr < end ) + { + auto ev = (const QueueItem*)ptr; + DispatchProcess( *ev, ptr ); + } + + m_bufferOffset += sz; + if( m_bufferOffset > TargetFrameSize * 2 ) m_bufferOffset = 0; + + HandlePostponedPlots(); + } + + auto t1 = std::chrono::high_resolution_clock::now(); + auto td = std::chrono::duration_cast( t1 - t0 ).count(); + enum { MbpsUpdateTime = 200 }; + if( td > MbpsUpdateTime ) + { + std::lock_guard lock( m_mbpsData.lock ); + m_mbpsData.mbps.erase( m_mbpsData.mbps.begin() ); + m_mbpsData.mbps.emplace_back( bytes / ( td * 125.f ) ); + m_mbpsData.compRatio = float( bytes ) / decBytes; + t0 = t1; + bytes = 0; + decBytes = 0; + } + + if( m_terminate ) + { + if( m_pendingStrings != 0 || m_pendingThreads != 0 || m_pendingSourceLocation != 0 || + !m_pendingCustomStrings.empty() || !m_pendingPlots.empty() ) + { + continue; + } + bool done = true; + for( auto& v : m_data.threads ) + { + if( !v->stack.empty() ) + { + done = false; + break; + } + } + if( !done ) continue; + ServerQuery( ServerQueryTerminate, 0 ); + break; + } + } + +close: + m_sock.Close(); + m_connected.store( false, std::memory_order_relaxed ); + } +} + +void Worker::ServerQuery( uint8_t type, uint64_t data ) +{ + enum { DataSize = sizeof( type ) + sizeof( data ) }; + char tmp[DataSize]; + memcpy( tmp, &type, sizeof( type ) ); + memcpy( tmp + sizeof( type ), &data, sizeof( data ) ); + m_sock.Send( tmp, DataSize ); +} + +void Worker::DispatchProcess( const QueueItem& ev, char*& ptr ) +{ + if( ev.hdr.type == QueueType::CustomStringData || ev.hdr.type == QueueType::StringData + || ev.hdr.type == QueueType::ThreadName || ev.hdr.type == QueueType::PlotName || ev.hdr.type == QueueType::SourceLocationPayload ) + { + ptr += sizeof( QueueHeader ) + sizeof( QueueStringTransfer ); + uint16_t sz; + memcpy( &sz, ptr, sizeof( sz ) ); + ptr += sizeof( sz ); + switch( ev.hdr.type ) + { + case QueueType::CustomStringData: + AddCustomString( ev.stringTransfer.ptr, ptr, sz ); + break; + case QueueType::StringData: + AddString( ev.stringTransfer.ptr, ptr, sz ); + break; + case QueueType::ThreadName: + AddThreadString( ev.stringTransfer.ptr, ptr, sz ); + break; + case QueueType::PlotName: + HandlePlotName( ev.stringTransfer.ptr, ptr, sz ); + break; + case QueueType::SourceLocationPayload: + AddSourceLocationPayload( ev.stringTransfer.ptr, ptr, sz ); + break; + default: + assert( false ); + break; + } + ptr += sz; + } + else + { + ptr += QueueDataSize[ev.hdr.idx]; + Process( ev ); + } +} + +void Worker::CheckSourceLocation( uint64_t ptr ) +{ + if( m_data.sourceLocation.find( ptr ) != m_data.sourceLocation.end() ) + { + return; + } + else + { + NewSourceLocation( ptr ); + } +} + +void Worker::NewSourceLocation( uint64_t ptr ) +{ + static const SourceLocation emptySourceLocation = {}; + + m_data.sourceLocation.emplace( ptr, emptySourceLocation ); + m_pendingSourceLocation++; + m_sourceLocationQueue.push_back( ptr ); + + ServerQuery( ServerQuerySourceLocation, ptr ); +} + +uint32_t Worker::ShrinkSourceLocation( uint64_t srcloc ) +{ + auto it = m_sourceLocationShrink.find( srcloc ); + if( it != m_sourceLocationShrink.end() ) + { + return it->second; + } + else + { + return NewShrinkedSourceLocation( srcloc ); + } +} + +uint32_t Worker::NewShrinkedSourceLocation( uint64_t srcloc ) +{ + const auto sz = m_data.sourceLocationExpand.size(); + m_data.sourceLocationExpand.push_back( srcloc ); + m_sourceLocationShrink.emplace( srcloc, sz ); + return sz; +} + +void Worker::InsertMessageData( MessageData* msg, uint64_t thread ) +{ + if( m_data.messages.empty() ) + { + m_data.messages.push_back( msg ); + } + else if( m_data.messages.back()->time < msg->time ) + { + m_data.messages.push_back_non_empty( msg ); + } + else + { + auto mit = std::lower_bound( m_data.messages.begin(), m_data.messages.end(), msg->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); + m_data.messages.insert( mit, msg ); + } + + auto vec = &NoticeThread( thread )->messages; + if( vec->empty() ) + { + vec->push_back( msg ); + } + else if( vec->back()->time < msg->time ) + { + vec->push_back_non_empty( msg ); + } + else + { + auto tmit = std::lower_bound( vec->begin(), vec->end(), msg->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); + vec->insert( tmit, msg ); + } +} + +ThreadData* Worker::NoticeThread( uint64_t thread ) +{ + auto it = m_threadMap.find( thread ); + if( it != m_threadMap.end() ) + { + return it->second; + } + else + { + return NewThread( thread ); + } +} + +ThreadData* Worker::NewThread( uint64_t thread ) +{ + CheckThreadString( thread ); + auto td = m_slab.AllocInit(); + td->id = thread; + td->count = 0; + m_data.threads.push_back( td ); + m_threadMap.emplace( thread, td ); + return td; +} + +void Worker::NewZone( ZoneEvent* zone, uint64_t thread ) +{ + m_data.zonesCnt++; + auto td = NoticeThread( thread ); + td->count++; + if( td->stack.empty() ) + { + td->stack.push_back( zone ); + td->timeline.push_back( zone ); + } + else + { + td->stack.back()->child.push_back( zone ); + td->stack.push_back_non_empty( zone ); + } +} + +static void UpdateLockCountLockable( LockMap& lockmap, size_t pos ) +{ + auto& timeline = lockmap.timeline; + uint8_t lockingThread; + uint8_t lockCount; + uint64_t waitList; + + if( pos == 0 ) + { + lockingThread = 0; + lockCount = 0; + waitList = 0; + } + else + { + const auto tl = timeline[pos-1]; + lockingThread = tl->lockingThread; + lockCount = tl->lockCount; + waitList = tl->waitList; + } + const auto end = timeline.size(); + + while( pos != end ) + { + const auto tl = timeline[pos]; + const auto tbit = uint64_t( 1 ) << tl->thread; + switch( (LockEvent::Type)tl->type ) + { + case LockEvent::Type::Wait: + waitList |= tbit; + break; + case LockEvent::Type::Obtain: + assert( lockCount < std::numeric_limits::max() ); + assert( ( waitList & tbit ) != 0 ); + waitList &= ~tbit; + lockingThread = tl->thread; + lockCount++; + break; + case LockEvent::Type::Release: + assert( lockCount > 0 ); + lockCount--; + break; + default: + break; + } + tl->lockingThread = lockingThread; + tl->waitList = waitList; + tl->lockCount = lockCount; + assert( tl->lockingThread == lockingThread ); + pos++; + } +} + +static void UpdateLockCountSharedLockable( LockMap& lockmap, size_t pos ) +{ + auto& timeline = lockmap.timeline; + uint8_t lockingThread; + uint8_t lockCount; + uint64_t waitShared; + uint64_t waitList; + uint64_t sharedList; + + if( pos == 0 ) + { + lockingThread = 0; + lockCount = 0; + waitShared = 0; + waitList = 0; + sharedList = 0; + } + else + { + const auto tl = (LockEventShared*)timeline[pos-1]; + lockingThread = tl->lockingThread; + lockCount = tl->lockCount; + waitShared = tl->waitShared; + waitList = tl->waitList; + sharedList = tl->sharedList; + } + const auto end = timeline.size(); + + // ObtainShared and ReleaseShared should assert on lockCount == 0, but + // due to the async retrieval of data from threads that not possible. + while( pos != end ) + { + const auto tl = (LockEventShared*)timeline[pos]; + const auto tbit = uint64_t( 1 ) << tl->thread; + switch( (LockEvent::Type)tl->type ) + { + case LockEvent::Type::Wait: + waitList |= tbit; + break; + case LockEvent::Type::WaitShared: + waitShared |= tbit; + break; + case LockEvent::Type::Obtain: + assert( lockCount < std::numeric_limits::max() ); + assert( ( waitList & tbit ) != 0 ); + waitList &= ~tbit; + lockingThread = tl->thread; + lockCount++; + break; + case LockEvent::Type::Release: + assert( lockCount > 0 ); + lockCount--; + break; + case LockEvent::Type::ObtainShared: + assert( ( waitShared & tbit ) != 0 ); + assert( ( sharedList & tbit ) == 0 ); + waitShared &= ~tbit; + sharedList |= tbit; + break; + case LockEvent::Type::ReleaseShared: + assert( ( sharedList & tbit ) != 0 ); + sharedList &= ~tbit; + break; + default: + break; + } + tl->lockingThread = lockingThread; + tl->waitShared = waitShared; + tl->waitList = waitList; + tl->sharedList = sharedList; + tl->lockCount = lockCount; + assert( tl->lockingThread == lockingThread ); + pos++; + } +} + +static inline void UpdateLockCount( LockMap& lockmap, size_t pos ) +{ + if( lockmap.type == LockType::Lockable ) + { + UpdateLockCountLockable( lockmap, pos ); + } + else + { + UpdateLockCountSharedLockable( lockmap, pos ); + } +} + +void Worker::InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread ) +{ + m_data.lastTime = std::max( m_data.lastTime, lev->time ); + + NoticeThread( thread ); + + auto it = lockmap.threadMap.find( thread ); + if( it == lockmap.threadMap.end() ) + { + assert( lockmap.threadList.size() < MaxLockThreads ); + it = lockmap.threadMap.emplace( thread, lockmap.threadList.size() ).first; + lockmap.threadList.emplace_back( thread ); + } + lev->thread = it->second; + assert( lev->thread == it->second ); + auto& timeline = lockmap.timeline; + if( timeline.empty() ) + { + timeline.push_back( lev ); + UpdateLockCount( lockmap, timeline.size() - 1 ); + } + else if( timeline.back()->time < lev->time ) + { + timeline.push_back_non_empty( lev ); + UpdateLockCount( lockmap, timeline.size() - 1 ); + } + else + { + auto it = std::lower_bound( timeline.begin(), timeline.end(), lev->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); + it = timeline.insert( it, lev ); + UpdateLockCount( lockmap, std::distance( timeline.begin(), it ) ); + } +} + +void Worker::CheckString( uint64_t ptr ) +{ + if( ptr == 0 ) return; + if( m_data.strings.find( ptr ) != m_data.strings.end() ) return; + + m_data.strings.emplace( ptr, "???" ); + m_pendingStrings++; + + ServerQuery( ServerQueryString, ptr ); +} + +void Worker::CheckThreadString( uint64_t id ) +{ + if( m_data.threadNames.find( id ) != m_data.threadNames.end() ) return; + + m_data.threadNames.emplace( id, "???" ); + m_pendingThreads++; + + ServerQuery( ServerQueryThreadString, id ); +} + +void Worker::AddSourceLocation( const QueueSourceLocation& srcloc ) +{ + assert( m_pendingSourceLocation > 0 ); + m_pendingSourceLocation--; + + const auto ptr = m_sourceLocationQueue.front(); + m_sourceLocationQueue.erase( m_sourceLocationQueue.begin() ); + + auto it = m_data.sourceLocation.find( ptr ); + assert( it != m_data.sourceLocation.end() ); + CheckString( srcloc.name ); + CheckString( srcloc.file ); + CheckString( srcloc.function ); + uint32_t color = ( srcloc.r << 16 ) | ( srcloc.g << 8 ) | srcloc.b; + it->second = SourceLocation { srcloc.name == 0 ? StringRef() : StringRef( StringRef::Ptr, srcloc.name ), StringRef( StringRef::Ptr, srcloc.function ), StringRef( StringRef::Ptr, srcloc.file ), srcloc.line, color }; +} + +void Worker::AddSourceLocationPayload( uint64_t ptr, char* data, size_t sz ) +{ + const auto start = data; + + assert( m_pendingSourceLocationPayload.find( ptr ) == m_pendingSourceLocationPayload.end() ); + + uint32_t color, line; + memcpy( &color, data, 4 ); + memcpy( &line, data + 4, 4 ); + data += 8; + auto end = data; + + while( *end ) end++; + const auto func = StoreString( data, end - data ); + end++; + + data = end; + while( *end ) end++; + const auto source = StoreString( data, end - data ); + end++; + + const auto nsz = sz - ( end - start ); + + color = ( ( color & 0x00FF0000 ) >> 16 ) | + ( ( color & 0x0000FF00 ) ) | + ( ( color & 0x000000FF ) << 16 ); + + SourceLocation srcloc { nsz == 0 ? StringRef() : StringRef( StringRef::Idx, StoreString( end, nsz ).idx ), StringRef( StringRef::Idx, func.idx ), StringRef( StringRef::Idx, source.idx ), line, color }; + auto it = m_data.sourceLocationPayloadMap.find( &srcloc ); + if( it == m_data.sourceLocationPayloadMap.end() ) + { + auto slptr = m_slab.Alloc(); + memcpy( slptr, &srcloc, sizeof( srcloc ) ); + uint32_t idx = m_data.sourceLocationPayload.size(); + m_data.sourceLocationPayloadMap.emplace( slptr, idx ); + m_pendingSourceLocationPayload.emplace( ptr, -int32_t( idx + 1 ) ); + m_data.sourceLocationPayload.push_back( slptr ); + } + else + { + m_pendingSourceLocationPayload.emplace( ptr, -int32_t( it->second + 1 ) ); + } +} + +void Worker::AddString( uint64_t ptr, char* str, size_t sz ) +{ + assert( m_pendingStrings > 0 ); + m_pendingStrings--; + auto it = m_data.strings.find( ptr ); + assert( it != m_data.strings.end() && strcmp( it->second, "???" ) == 0 ); + const auto sl = StoreString( str, sz ); + it->second = sl.ptr; +} + +void Worker::AddThreadString( uint64_t id, char* str, size_t sz ) +{ + assert( m_pendingThreads > 0 ); + m_pendingThreads--; + auto it = m_data.threadNames.find( id ); + assert( it != m_data.threadNames.end() && strcmp( it->second, "???" ) == 0 ); + const auto sl = StoreString( str, sz ); + it->second = sl.ptr; +} + +void Worker::AddCustomString( uint64_t ptr, char* str, size_t sz ) +{ + assert( m_pendingCustomStrings.find( ptr ) == m_pendingCustomStrings.end() ); + m_pendingCustomStrings.emplace( ptr, StoreString( str, sz ) ); +} + +void Worker::InsertPlot( PlotData* plot, int64_t time, double val ) +{ + if( plot->data.empty() ) + { + plot->min = val; + plot->max = val; + plot->data.push_back( { time, val } ); + } + else if( plot->data.back().time < time ) + { + if( plot->min > val ) plot->min = val; + else if( plot->max < val ) plot->max = val; + plot->data.push_back_non_empty( { time, val } ); + } + else + { + if( plot->min > val ) plot->min = val; + else if( plot->max < val ) plot->max = val; + if( plot->postpone.empty() ) + { + plot->postponeTime = std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); + plot->postpone.push_back( { time, val } ); + } + else + { + plot->postpone.push_back_non_empty( { time, val } ); + } + } +} + +void Worker::HandlePlotName( uint64_t name, char* str, size_t sz ) +{ + auto pit = m_pendingPlots.find( name ); + assert( pit != m_pendingPlots.end() ); + + const auto sl = StoreString( str, sz ); + + auto it = m_plotRev.find( sl.ptr ); + if( it == m_plotRev.end() ) + { + m_plotMap.emplace( name, pit->second ); + m_plotRev.emplace( sl.ptr, pit->second ); + m_data.plots.push_back( pit->second ); + m_data.strings.emplace( name, sl.ptr ); + } + else + { + auto plot = it->second; + m_plotMap.emplace( name, plot ); + const auto& pp = pit->second->data; + for( auto& v : pp ) + { + InsertPlot( plot, v.time, v.val ); + } + // TODO what happens with the source data here? + } + + m_pendingPlots.erase( pit ); +} + +void Worker::HandlePostponedPlots() +{ + for( auto& plot : m_data.plots ) + { + auto& src = plot->postpone; + if( src.empty() ) continue; + if( std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count() - plot->postponeTime < 100 ) continue; + auto& dst = plot->data; + std::sort( src.begin(), src.end(), [] ( const auto& l, const auto& r ) { return l.time < r.time; } ); + const auto ds = std::lower_bound( dst.begin(), dst.end(), src.front().time, [] ( const auto& l, const auto& r ) { return l.time < r; } ); + const auto dsd = std::distance( dst.begin(), ds ) ; + const auto de = std::lower_bound( ds, dst.end(), src.back().time, [] ( const auto& l, const auto& r ) { return l.time < r; } ); + const auto ded = std::distance( dst.begin(), de ); + dst.insert( de, src.begin(), src.end() ); + std::inplace_merge( dst.begin() + dsd, dst.begin() + ded, dst.begin() + ded + src.size(), [] ( const auto& l, const auto& r ) { return l.time < r.time; } ); + src.clear(); + } +} + +StringLocation Worker::StoreString( char* str, size_t sz ) +{ + StringLocation ret; + const char backup = str[sz]; + str[sz] = '\0'; + auto sit = m_data.stringMap.find( str ); + if( sit == m_data.stringMap.end() ) + { + auto ptr = m_slab.Alloc( sz+1 ); + memcpy( ptr, str, sz+1 ); + ret.ptr = ptr; + ret.idx = m_data.stringData.size(); + m_data.stringMap.emplace( ptr, m_data.stringData.size() ); + m_data.stringData.push_back( ptr ); + } + else + { + ret.ptr = sit->first; + ret.idx = sit->second; + } + str[sz] = backup; + return ret; +} + +void Worker::Process( const QueueItem& ev ) +{ + switch( ev.hdr.type ) + { + case QueueType::ZoneBegin: + ProcessZoneBegin( ev.zoneBegin ); + break; + case QueueType::ZoneBeginAllocSrcLoc: + ProcessZoneBeginAllocSrcLoc( ev.zoneBegin ); + break; + case QueueType::ZoneEnd: + ProcessZoneEnd( ev.zoneEnd ); + break; + case QueueType::FrameMarkMsg: + ProcessFrameMark( ev.frameMark ); + break; + case QueueType::SourceLocation: + AddSourceLocation( ev.srcloc ); + break; + case QueueType::ZoneText: + ProcessZoneText( ev.zoneText ); + break; + case QueueType::LockAnnounce: + ProcessLockAnnounce( ev.lockAnnounce ); + break; + case QueueType::LockWait: + ProcessLockWait( ev.lockWait ); + break; + case QueueType::LockObtain: + ProcessLockObtain( ev.lockObtain ); + break; + case QueueType::LockRelease: + ProcessLockRelease( ev.lockRelease ); + break; + case QueueType::LockSharedWait: + ProcessLockSharedWait( ev.lockWait ); + break; + case QueueType::LockSharedObtain: + ProcessLockSharedObtain( ev.lockObtain ); + break; + case QueueType::LockSharedRelease: + ProcessLockSharedRelease( ev.lockRelease ); + break; + case QueueType::LockMark: + ProcessLockMark( ev.lockMark ); + break; + case QueueType::PlotData: + ProcessPlotData( ev.plotData ); + break; + case QueueType::Message: + ProcessMessage( ev.message ); + break; + case QueueType::MessageLiteral: + ProcessMessageLiteral( ev.message ); + break; + case QueueType::GpuNewContext: + ProcessGpuNewContext( ev.gpuNewContext ); + break; + case QueueType::GpuZoneBegin: + ProcessGpuZoneBegin( ev.gpuZoneBegin ); + break; + case QueueType::GpuZoneEnd: + ProcessGpuZoneEnd( ev.gpuZoneEnd ); + break; + case QueueType::GpuTime: + ProcessGpuTime( ev.gpuTime ); + break; + case QueueType::GpuResync: + ProcessGpuResync( ev.gpuResync ); + break; + case QueueType::Terminate: + m_terminate = true; + break; + default: + assert( false ); + break; + } +} + +void Worker::ProcessZoneBegin( const QueueZoneBegin& ev ) +{ + auto zone = m_slab.AllocInit(); + + CheckSourceLocation( ev.srcloc ); + + zone->start = TscTime( ev.time ); + zone->end = -1; + zone->srcloc = ShrinkSourceLocation( ev.srcloc ); + assert( ev.cpu == 0xFFFFFFFF || ev.cpu <= std::numeric_limits::max() ); + zone->cpu_start = ev.cpu == 0xFFFFFFFF ? -1 : (int8_t)ev.cpu; + + m_data.lastTime = std::max( m_data.lastTime, zone->start ); + + NewZone( zone, ev.thread ); +} + +void Worker::ProcessZoneBeginAllocSrcLoc( const QueueZoneBegin& ev ) +{ + auto it = m_pendingSourceLocationPayload.find( ev.srcloc ); + assert( it != m_pendingSourceLocationPayload.end() ); + + auto zone = m_slab.AllocInit(); + + zone->start = TscTime( ev.time ); + zone->end = -1; + zone->srcloc = it->second; + assert( ev.cpu == 0xFFFFFFFF || ev.cpu <= std::numeric_limits::max() ); + zone->cpu_start = ev.cpu == 0xFFFFFFFF ? -1 : (int8_t)ev.cpu; + + m_data.lastTime = std::max( m_data.lastTime, zone->start ); + + NewZone( zone, ev.thread ); + + m_pendingSourceLocationPayload.erase( it ); +} + +void Worker::ProcessZoneEnd( const QueueZoneEnd& ev ) +{ + auto tit = m_threadMap.find( ev.thread ); + assert( tit != m_threadMap.end() ); + + auto td = tit->second; + auto& stack = td->stack; + assert( !stack.empty() ); + auto zone = stack.back_and_pop(); + assert( zone->end == -1 ); + zone->end = TscTime( ev.time ); + assert( ev.cpu == 0xFFFFFFFF || ev.cpu <= std::numeric_limits::max() ); + zone->cpu_end = ev.cpu == 0xFFFFFFFF ? -1 : (int8_t)ev.cpu; + assert( zone->end >= zone->start ); + + m_data.lastTime = std::max( m_data.lastTime, zone->end ); +} + +void Worker::ProcessFrameMark( const QueueFrameMark& ev ) +{ + assert( !m_data.frames.empty() ); + const auto lastframe = m_data.frames.back(); + const auto time = TscTime( ev.time ); + assert( lastframe < time ); + m_data.frames.push_back_non_empty( time ); + m_data.lastTime = std::max( m_data.lastTime, time ); +} + +void Worker::ProcessZoneText( const QueueZoneText& ev ) +{ + auto tit = m_threadMap.find( ev.thread ); + assert( tit != m_threadMap.end() ); + + auto td = tit->second; + auto& stack = td->stack; + assert( !stack.empty() ); + auto zone = stack.back(); + auto it = m_pendingCustomStrings.find( ev.text ); + assert( it != m_pendingCustomStrings.end() ); + zone->text = StringIdx( it->second.idx ); + m_pendingCustomStrings.erase( it ); +} + +void Worker::ProcessLockAnnounce( const QueueLockAnnounce& ev ) +{ + auto it = m_data.lockMap.find( ev.id ); + if( it == m_data.lockMap.end() ) + { + LockMap lm; + lm.srcloc = ShrinkSourceLocation( ev.lckloc ); + lm.type = ev.type; + m_data.lockMap.emplace( ev.id, std::move( lm ) ); + } + else + { + it->second.srcloc = ShrinkSourceLocation( ev.lckloc ); + assert( it->second.type == ev.type ); + it->second.valid = true; + } + CheckSourceLocation( ev.lckloc ); +} + +void Worker::ProcessLockWait( const QueueLockWait& ev ) +{ + auto it = m_data.lockMap.find( ev.id ); + if( it == m_data.lockMap.end() ) + { + LockMap lm; + lm.valid = false; + lm.type = ev.type; + it = m_data.lockMap.emplace( ev.id, std::move( lm ) ).first; + } + + auto lev = ev.type == LockType::Lockable ? m_slab.Alloc() : m_slab.Alloc(); + lev->time = TscTime( ev.time ); + lev->type = LockEvent::Type::Wait; + lev->srcloc = 0; + + InsertLockEvent( it->second, lev, ev.thread ); +} + +void Worker::ProcessLockObtain( const QueueLockObtain& ev ) +{ + assert( m_data.lockMap.find( ev.id ) != m_data.lockMap.end() ); + auto& lock = m_data.lockMap[ev.id]; + + auto lev = lock.type == LockType::Lockable ? m_slab.Alloc() : m_slab.Alloc(); + lev->time = TscTime( ev.time ); + lev->type = LockEvent::Type::Obtain; + lev->srcloc = 0; + + InsertLockEvent( lock, lev, ev.thread ); +} + +void Worker::ProcessLockRelease( const QueueLockRelease& ev ) +{ + assert( m_data.lockMap.find( ev.id ) != m_data.lockMap.end() ); + auto& lock = m_data.lockMap[ev.id]; + + auto lev = lock.type == LockType::Lockable ? m_slab.Alloc() : m_slab.Alloc(); + lev->time = TscTime( ev.time ); + lev->type = LockEvent::Type::Release; + lev->srcloc = 0; + + InsertLockEvent( lock, lev, ev.thread ); +} + +void Worker::ProcessLockSharedWait( const QueueLockWait& ev ) +{ + auto it = m_data.lockMap.find( ev.id ); + if( it == m_data.lockMap.end() ) + { + LockMap lm; + lm.valid = false; + lm.type = ev.type; + it = m_data.lockMap.emplace( ev.id, std::move( lm ) ).first; + } + + assert( ev.type == LockType::SharedLockable ); + auto lev = m_slab.Alloc(); + lev->time = TscTime( ev.time ); + lev->type = LockEvent::Type::WaitShared; + lev->srcloc = 0; + + InsertLockEvent( it->second, lev, ev.thread ); +} + +void Worker::ProcessLockSharedObtain( const QueueLockObtain& ev ) +{ + assert( m_data.lockMap.find( ev.id ) != m_data.lockMap.end() ); + auto& lock = m_data.lockMap[ev.id]; + + assert( lock.type == LockType::SharedLockable ); + auto lev = m_slab.Alloc(); + lev->time = TscTime( ev.time ); + lev->type = LockEvent::Type::ObtainShared; + lev->srcloc = 0; + + InsertLockEvent( lock, lev, ev.thread ); +} + +void Worker::ProcessLockSharedRelease( const QueueLockRelease& ev ) +{ + assert( m_data.lockMap.find( ev.id ) != m_data.lockMap.end() ); + auto& lock = m_data.lockMap[ev.id]; + + assert( lock.type == LockType::SharedLockable ); + auto lev = m_slab.Alloc(); + lev->time = TscTime( ev.time ); + lev->type = LockEvent::Type::ReleaseShared; + lev->srcloc = 0; + + InsertLockEvent( lock, lev, ev.thread ); +} + +void Worker::ProcessLockMark( const QueueLockMark& ev ) +{ + CheckSourceLocation( ev.srcloc ); + auto lit = m_data.lockMap.find( ev.id ); + assert( lit != m_data.lockMap.end() ); + auto& lockmap = lit->second; + auto tid = lockmap.threadMap.find( ev.thread ); + assert( tid != lockmap.threadMap.end() ); + const auto thread = tid->second; + auto it = lockmap.timeline.end(); + for(;;) + { + --it; + if( (*it)->thread == thread ) + { + switch( (*it)->type ) + { + case LockEvent::Type::Obtain: + case LockEvent::Type::ObtainShared: + case LockEvent::Type::Wait: + case LockEvent::Type::WaitShared: + (*it)->srcloc = ShrinkSourceLocation( ev.srcloc ); + return; + default: + break; + } + } + } +} + +void Worker::ProcessPlotData( const QueuePlotData& ev ) +{ + PlotData* plot; + auto it = m_plotMap.find( ev.name ); + if( it == m_plotMap.end() ) + { + auto pit = m_pendingPlots.find( ev.name ); + if( pit == m_pendingPlots.end() ) + { + plot = m_slab.AllocInit(); + plot->name = ev.name; + m_pendingPlots.emplace( ev.name, plot ); + ServerQuery( ServerQueryPlotName, ev.name ); + } + else + { + plot = pit->second; + } + } + else + { + plot = it->second; + } + + const auto time = TscTime( ev.time ); + m_data.lastTime = std::max( m_data.lastTime, time ); + switch( ev.type ) + { + case PlotDataType::Double: + InsertPlot( plot, time, ev.data.d ); + break; + case PlotDataType::Float: + InsertPlot( plot, time, (double)ev.data.f ); + break; + case PlotDataType::Int: + InsertPlot( plot, time, (double)ev.data.i ); + break; + default: + assert( false ); + break; + } +} + +void Worker::ProcessMessage( const QueueMessage& ev ) +{ + auto it = m_pendingCustomStrings.find( ev.text ); + assert( it != m_pendingCustomStrings.end() ); + auto msg = m_slab.Alloc(); + msg->time = TscTime( ev.time ); + msg->ref = StringRef( StringRef::Type::Idx, it->second.idx ); + m_data.lastTime = std::max( m_data.lastTime, msg->time ); + InsertMessageData( msg, ev.thread ); + m_pendingCustomStrings.erase( it ); +} + +void Worker::ProcessMessageLiteral( const QueueMessage& ev ) +{ + CheckString( ev.text ); + auto msg = m_slab.Alloc(); + msg->time = TscTime( ev.time ); + msg->ref = StringRef( StringRef::Type::Ptr, ev.text ); + m_data.lastTime = std::max( m_data.lastTime, msg->time ); + InsertMessageData( msg, ev.thread ); +} + +void Worker::ProcessGpuNewContext( const QueueGpuNewContext& ev ) +{ + assert( m_gpuCtxMap.find( ev.context ) == m_gpuCtxMap.end() ); + + auto gpu = m_slab.AllocInit(); + gpu->timeDiff = TscTime( ev.cpuTime ) - ev.gpuTime; + gpu->thread = ev.thread; + gpu->accuracyBits = ev.accuracyBits; + gpu->count = 0; + m_data.gpuData.push_back( gpu ); + m_gpuCtxMap.emplace( ev.context, gpu ); +} + +void Worker::ProcessGpuZoneBegin( const QueueGpuZoneBegin& ev ) +{ + auto it = m_gpuCtxMap.find( ev.context ); + assert( it != m_gpuCtxMap.end() ); + auto ctx = it->second; + + CheckSourceLocation( ev.srcloc ); + + auto zone = m_slab.AllocInit(); + + zone->cpuStart = TscTime( ev.cpuTime ); + zone->cpuEnd = -1; + zone->gpuStart = std::numeric_limits::max(); + zone->gpuEnd = -1; + zone->srcloc = ShrinkSourceLocation( ev.srcloc ); + + m_data.lastTime = std::max( m_data.lastTime, zone->cpuStart ); + + auto timeline = &ctx->timeline; + if( !ctx->stack.empty() ) + { + timeline = &ctx->stack.back()->child; + } + + timeline->push_back( zone ); + + ctx->stack.push_back( zone ); + ctx->queue.push_back( zone ); +} + +void Worker::ProcessGpuZoneEnd( const QueueGpuZoneEnd& ev ) +{ + auto it = m_gpuCtxMap.find( ev.context ); + assert( it != m_gpuCtxMap.end() ); + auto ctx = it->second; + + assert( !ctx->stack.empty() ); + auto zone = ctx->stack.back_and_pop(); + ctx->queue.push_back( zone ); + + zone->cpuEnd = TscTime( ev.cpuTime ); + m_data.lastTime = std::max( m_data.lastTime, zone->cpuEnd ); +} + +void Worker::ProcessGpuTime( const QueueGpuTime& ev ) +{ + auto it = m_gpuCtxMap.find( ev.context ); + assert( it != m_gpuCtxMap.end() ); + auto ctx = it->second; + + auto zone = ctx->queue.front(); + if( zone->gpuStart == std::numeric_limits::max() ) + { + zone->gpuStart = ctx->timeDiff + ev.gpuTime; + m_data.lastTime = std::max( m_data.lastTime, zone->gpuStart ); + ctx->count++; + } + else + { + zone->gpuEnd = ctx->timeDiff + ev.gpuTime; + m_data.lastTime = std::max( m_data.lastTime, zone->gpuEnd ); + } + + ctx->queue.erase( ctx->queue.begin() ); + if( !ctx->resync.empty() ) + { + auto& resync = ctx->resync.front(); + assert( resync.events > 0 ); + resync.events--; + if( resync.events == 0 ) + { + ctx->timeDiff = resync.timeDiff; + ctx->resync.erase( ctx->resync.begin() ); + } + } +} + +void Worker::ProcessGpuResync( const QueueGpuResync& ev ) +{ + auto it = m_gpuCtxMap.find( ev.context ); + assert( it != m_gpuCtxMap.end() ); + auto ctx = it->second; + + const auto timeDiff = TscTime( ev.cpuTime ) - ev.gpuTime; + + if( ctx->queue.empty() ) + { + assert( ctx->resync.empty() ); + ctx->timeDiff = timeDiff; + } + else + { + if( ctx->resync.empty() ) + { + ctx->resync.push_back( { timeDiff, uint16_t( ctx->queue.size() ) } ); + } + else + { + const auto last = ctx->resync.back().events; + ctx->resync.push_back( { timeDiff, uint16_t( ctx->queue.size() - last ) } ); + } + } +} + +void Worker::ReadTimeline( FileRead& f, Vector& vec ) +{ + uint64_t sz; + f.Read( &sz, sizeof( sz ) ); + vec.reserve( sz ); + + for( uint64_t i=0; i(); + + m_data.zonesCnt++; + vec.push_back( zone ); + + f.Read( &zone->start, sizeof( zone->start ) ); + f.Read( &zone->end, sizeof( zone->end ) ); + f.Read( &zone->srcloc, sizeof( zone->srcloc ) ); + f.Read( &zone->cpu_start, sizeof( zone->cpu_start ) ); + f.Read( &zone->cpu_end, sizeof( zone->cpu_end ) ); + f.Read( &zone->text, sizeof( zone->text ) ); + ReadTimeline( f, zone->child ); + } +} + +void Worker::ReadTimeline( FileRead& f, Vector& vec ) +{ + uint64_t sz; + f.Read( &sz, sizeof( sz ) ); + vec.reserve( sz ); + + for( uint64_t i=0; i(); + + vec.push_back( zone ); + + f.Read( &zone->cpuStart, sizeof( zone->cpuStart ) ); + f.Read( &zone->cpuEnd, sizeof( zone->cpuEnd ) ); + f.Read( &zone->gpuStart, sizeof( zone->gpuStart ) ); + f.Read( &zone->gpuEnd, sizeof( zone->gpuEnd ) ); + f.Read( &zone->srcloc, sizeof( zone->srcloc ) ); + ReadTimeline( f, zone->child ); + } +} + +void Worker::Write( FileWrite& f ) +{ + f.Write( &m_delay, sizeof( m_delay ) ); + f.Write( &m_resolution, sizeof( m_resolution ) ); + f.Write( &m_timerMul, sizeof( m_timerMul ) ); + f.Write( &m_data.lastTime, sizeof( m_data.lastTime ) ); + + uint64_t sz = m_captureName.size(); + f.Write( &sz, sizeof( sz ) ); + f.Write( m_captureName.c_str(), sz ); + + sz = m_data.frames.size(); + f.Write( &sz, sizeof( sz ) ); + f.Write( m_data.frames.data(), sizeof( uint64_t ) * sz ); + + sz = m_data.stringData.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.stringData ) + { + uint64_t ptr = (uint64_t)v; + f.Write( &ptr, sizeof( ptr ) ); + sz = strlen( v ); + f.Write( &sz, sizeof( sz ) ); + f.Write( v, sz ); + } + + sz = m_data.strings.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.strings ) + { + f.Write( &v.first, sizeof( v.first ) ); + uint64_t ptr = (uint64_t)v.second; + f.Write( &ptr, sizeof( ptr ) ); + } + + sz = m_data.threadNames.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.threadNames ) + { + f.Write( &v.first, sizeof( v.first ) ); + uint64_t ptr = (uint64_t)v.second; + f.Write( &ptr, sizeof( ptr ) ); + } + + sz = m_data.sourceLocation.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.sourceLocation ) + { + f.Write( &v.first, sizeof( v.first ) ); + f.Write( &v.second, sizeof( v.second ) ); + } + + sz = m_data.sourceLocationExpand.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.sourceLocationExpand ) + { + f.Write( &v, sizeof( v ) ); + } + + sz = m_data.sourceLocationPayload.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.sourceLocationPayload ) + { + f.Write( v, sizeof( *v ) ); + } + + sz = m_data.lockMap.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.lockMap ) + { + f.Write( &v.first, sizeof( v.first ) ); + f.Write( &v.second.srcloc, sizeof( v.second.srcloc ) ); + f.Write( &v.second.type, sizeof( v.second.type ) ); + f.Write( &v.second.valid, sizeof( v.second.valid ) ); + sz = v.second.threadList.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& t : v.second.threadList ) + { + f.Write( &t, sizeof( t ) ); + } + sz = v.second.timeline.size(); + f.Write( &sz, sizeof( sz ) ); + if( v.second.type == LockType::Lockable ) + { + for( auto& lev : v.second.timeline ) + { + f.Write( lev, sizeof( LockEvent ) ); + } + } + else + { + for( auto& lev : v.second.timeline ) + { + f.Write( lev, sizeof( LockEventShared ) ); + } + } + } + + sz = m_data.messages.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : m_data.messages ) + { + const auto ptr = (uint64_t)v; + f.Write( &ptr, sizeof( ptr ) ); + f.Write( v, sizeof( *v ) ); + } + + sz = m_data.threads.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& thread : m_data.threads ) + { + f.Write( &thread->id, sizeof( thread->id ) ); + f.Write( &thread->count, sizeof( thread->count ) ); + WriteTimeline( f, thread->timeline ); + sz = thread->messages.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& v : thread->messages ) + { + auto ptr = uint64_t( v ); + f.Write( &ptr, sizeof( ptr ) ); + } + } + + sz = m_data.gpuData.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& ctx : m_data.gpuData ) + { + f.Write( &ctx->thread, sizeof( ctx->thread ) ); + f.Write( &ctx->accuracyBits, sizeof( ctx->accuracyBits ) ); + f.Write( &ctx->count, sizeof( ctx->count ) ); + WriteTimeline( f, ctx->timeline ); + } + + sz = m_data.plots.size(); + f.Write( &sz, sizeof( sz ) ); + for( auto& plot : m_data.plots ) + { + f.Write( &plot->name, sizeof( plot->name ) ); + f.Write( &plot->min, sizeof( plot->min ) ); + f.Write( &plot->max, sizeof( plot->max ) ); + sz = plot->data.size(); + f.Write( &sz, sizeof( sz ) ); + f.Write( plot->data.data(), sizeof( PlotItem ) * sz ); + } +} + +void Worker::WriteTimeline( FileWrite& f, const Vector& vec ) +{ + uint64_t sz = vec.size(); + f.Write( &sz, sizeof( sz ) ); + + for( auto& v : vec ) + { + f.Write( &v->start, sizeof( v->start ) ); + f.Write( &v->end, sizeof( v->end ) ); + f.Write( &v->srcloc, sizeof( v->srcloc ) ); + f.Write( &v->cpu_start, sizeof( v->cpu_start ) ); + f.Write( &v->cpu_end, sizeof( v->cpu_end ) ); + f.Write( &v->text, sizeof( v->text ) ); + WriteTimeline( f, v->child ); + } +} + +void Worker::WriteTimeline( FileWrite& f, const Vector& vec ) +{ + uint64_t sz = vec.size(); + f.Write( &sz, sizeof( sz ) ); + + for( auto& v : vec ) + { + f.Write( &v->cpuStart, sizeof( v->cpuStart ) ); + f.Write( &v->cpuEnd, sizeof( v->cpuEnd ) ); + f.Write( &v->gpuStart, sizeof( v->gpuStart ) ); + f.Write( &v->gpuEnd, sizeof( v->gpuEnd ) ); + f.Write( &v->srcloc, sizeof( v->srcloc ) ); + WriteTimeline( f, v->child ); + } +} + +} diff --git a/server/TracyWorker.hpp b/server/TracyWorker.hpp new file mode 100644 index 00000000..50b3911d --- /dev/null +++ b/server/TracyWorker.hpp @@ -0,0 +1,221 @@ +#ifndef __TRACYWORKER_HPP__ +#define __TRACYWORKER_HPP__ + +#include +#include +#include +#include +#include +#include + +#include "../common/tracy_lz4.hpp" +#include "../common/TracyForceInline.hpp" +#include "../common/TracyQueue.hpp" +#include "../common/TracySocket.hpp" +#include "tracy_benaphore.h" +#include "tracy_flat_hash_map.hpp" +#include "TracyEvent.hpp" +#include "TracySlab.hpp" + +namespace tracy +{ + +class FileRead; +class FileWrite; + +template +struct nohash +{ + size_t operator()( const T& v ) { return (size_t)v; } + typedef tracy::power_of_two_hash_policy hash_policy; +}; + +class Worker +{ + struct DataBlock + { + DataBlock() : zonesCnt( 0 ), lastTime( 0 ) {} + + NonRecursiveBenaphore lock; + Vector frames; + Vector gpuData; + Vector messages; + Vector plots; + Vector threads; + uint64_t zonesCnt; + int64_t lastTime; + + flat_hash_map> strings; + Vector stringData; + std::unordered_map stringMap; + flat_hash_map> threadNames; + + flat_hash_map> sourceLocation; + Vector sourceLocationPayload; + flat_hash_map sourceLocationPayloadMap; + std::vector sourceLocationExpand; + + std::map lockMap; + }; + + struct MbpsBlock + { + MbpsBlock() : mbps( 64 ), compRatio( 1.0 ) {} + + NonRecursiveBenaphore lock; + std::vector mbps; + float compRatio; + }; + +public: + Worker( const char* addr ); + Worker( FileRead& f ); + ~Worker(); + + const std::string& GetAddr() const { return m_addr; } + const std::string& GetCaptureName() const { return m_captureName; } + int64_t GetDelay() const { return m_delay; } + int64_t GetResolution() const { return m_resolution; } + + NonRecursiveBenaphore& GetDataLock() { return m_data.lock; } + size_t GetFrameCount() const { return m_data.frames.size(); } + int64_t GetLastTime() const { return m_data.lastTime; } + uint64_t GetZoneCount() const { return m_data.zonesCnt; } + + int64_t GetFrameTime( size_t idx ) const; + int64_t GetFrameBegin( size_t idx ) const; + int64_t GetFrameEnd( size_t idx ) const; + std::pair GetFrameRange( int64_t from, int64_t to ); + + const std::map& GetLockMap() const { return m_data.lockMap; } + const Vector& GetMessages() const { return m_data.messages; } + const Vector& GetGpuData() const { return m_data.gpuData; } + const Vector& GetPlots() const { return m_data.plots; } + const Vector& GetThreadData() const { return m_data.threads; } + + int64_t GetZoneEnd( const ZoneEvent& ev ) const; + int64_t GetZoneEnd( const GpuEvent& ev ) const; + const char* GetString( uint64_t ptr ) const; + const char* GetString( const StringRef& ref ) const; + const char* GetString( const StringIdx& idx ) const; + const char* GetThreadString( uint64_t id ) const; + const SourceLocation& GetSourceLocation( int32_t srcloc ) const; + + NonRecursiveBenaphore& GetMbpsDataLock() { return m_mbpsData.lock; } + const std::vector& GetMbpsData() const { return m_mbpsData.mbps; } + float GetCompRatio() const { return m_mbpsData.compRatio; } + + bool HasData() const { return m_hasData.load( std::memory_order_acquire ); } + bool IsConnected() const { return m_connected.load( std::memory_order_relaxed ); } + void Shutdown() { m_shutdown.store( true, std::memory_order_relaxed ); } + + void Join(); + void Write( FileWrite& f ); + +private: + void Exec(); + void ServerQuery( uint8_t type, uint64_t data ); + + tracy_force_inline void DispatchProcess( const QueueItem& ev, char*& ptr ); + tracy_force_inline void Process( const QueueItem& ev ); + tracy_force_inline void ProcessZoneBegin( const QueueZoneBegin& ev ); + tracy_force_inline void ProcessZoneBeginAllocSrcLoc( const QueueZoneBegin& ev ); + tracy_force_inline void ProcessZoneEnd( const QueueZoneEnd& ev ); + tracy_force_inline void ProcessFrameMark( const QueueFrameMark& ev ); + tracy_force_inline void ProcessZoneText( const QueueZoneText& ev ); + tracy_force_inline void ProcessLockAnnounce( const QueueLockAnnounce& ev ); + tracy_force_inline void ProcessLockWait( const QueueLockWait& ev ); + tracy_force_inline void ProcessLockObtain( const QueueLockObtain& ev ); + tracy_force_inline void ProcessLockRelease( const QueueLockRelease& ev ); + tracy_force_inline void ProcessLockSharedWait( const QueueLockWait& ev ); + tracy_force_inline void ProcessLockSharedObtain( const QueueLockObtain& ev ); + tracy_force_inline void ProcessLockSharedRelease( const QueueLockRelease& ev ); + tracy_force_inline void ProcessLockMark( const QueueLockMark& ev ); + tracy_force_inline void ProcessPlotData( const QueuePlotData& ev ); + tracy_force_inline void ProcessMessage( const QueueMessage& ev ); + tracy_force_inline void ProcessMessageLiteral( const QueueMessage& ev ); + tracy_force_inline void ProcessGpuNewContext( const QueueGpuNewContext& ev ); + tracy_force_inline void ProcessGpuZoneBegin( const QueueGpuZoneBegin& ev ); + tracy_force_inline void ProcessGpuZoneEnd( const QueueGpuZoneEnd& ev ); + tracy_force_inline void ProcessGpuTime( const QueueGpuTime& ev ); + tracy_force_inline void ProcessGpuResync( const QueueGpuResync& ev ); + + tracy_force_inline void CheckSourceLocation( uint64_t ptr ); + void NewSourceLocation( uint64_t ptr ); + tracy_force_inline uint32_t ShrinkSourceLocation( uint64_t srcloc ); + uint32_t NewShrinkedSourceLocation( uint64_t srcloc ); + + void InsertMessageData( MessageData* msg, uint64_t thread ); + + ThreadData* NewThread( uint64_t thread ); + ThreadData* NoticeThread( uint64_t thread ); + + tracy_force_inline void NewZone( ZoneEvent* zone, uint64_t thread ); + + void InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread ); + + void CheckString( uint64_t ptr ); + void CheckThreadString( uint64_t id ); + + void AddSourceLocation( const QueueSourceLocation& srcloc ); + void AddSourceLocationPayload( uint64_t ptr, char* data, size_t sz ); + + void AddString( uint64_t ptr, char* str, size_t sz ); + void AddThreadString( uint64_t id, char* str, size_t sz ); + void AddCustomString( uint64_t ptr, char* str, size_t sz ); + + void InsertPlot( PlotData* plot, int64_t time, double val ); + void HandlePlotName( uint64_t name, char* str, size_t sz ); + void HandlePostponedPlots(); + + StringLocation StoreString( char* str, size_t sz ); + + void ReadTimeline( FileRead& f, Vector& vec ); + void ReadTimeline( FileRead& f, Vector& vec ); + + void WriteTimeline( FileWrite& f, const Vector& vec ); + void WriteTimeline( FileWrite& f, const Vector& vec ); + + int64_t TscTime( int64_t tsc ) { return int64_t( tsc * m_timerMul ); } + int64_t TscTime( uint64_t tsc ) { return int64_t( tsc * m_timerMul ); } + + Socket m_sock; + std::string m_addr; + + std::thread m_thread; + std::atomic m_connected; + std::atomic m_hasData; + std::atomic m_shutdown; + + int64_t m_delay; + int64_t m_resolution; + double m_timerMul; + std::string m_captureName; + bool m_terminate; + LZ4_streamDecode_t* m_stream; + char* m_buffer; + int m_bufferOffset; + + flat_hash_map> m_gpuCtxMap; + flat_hash_map> m_pendingCustomStrings; + flat_hash_map> m_pendingPlots; + flat_hash_map> m_plotMap; + std::unordered_map m_plotRev; + flat_hash_map> m_pendingSourceLocationPayload; + Vector m_sourceLocationQueue; + flat_hash_map> m_sourceLocationShrink; + flat_hash_map> m_threadMap; + + uint32_t m_pendingStrings; + uint32_t m_pendingThreads; + uint32_t m_pendingSourceLocation; + + Slab<64*1024*1024> m_slab; + + DataBlock m_data; + MbpsBlock m_mbpsData; +}; + +} + +#endif diff --git a/standalone/build/win32/Tracy.vcxproj b/standalone/build/win32/Tracy.vcxproj index c63360e5..a7b31807 100644 --- a/standalone/build/win32/Tracy.vcxproj +++ b/standalone/build/win32/Tracy.vcxproj @@ -91,6 +91,7 @@ + diff --git a/standalone/build/win32/Tracy.vcxproj.filters b/standalone/build/win32/Tracy.vcxproj.filters index c2845152..e6b2f4df 100644 --- a/standalone/build/win32/Tracy.vcxproj.filters +++ b/standalone/build/win32/Tracy.vcxproj.filters @@ -33,6 +33,9 @@ server + + server + src