From d0d3bb1141da998a9b0e2724c125a19a7715b09b Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sun, 17 Dec 2017 18:44:31 +0100 Subject: [PATCH] Store shared lock bits only for shared locks. --- server/TracyEvent.hpp | 7 +- server/TracyView.cpp | 272 +++++++++++++++++++++++++++++------------- server/TracyView.hpp | 1 - 3 files changed, 195 insertions(+), 85 deletions(-) diff --git a/server/TracyEvent.hpp b/server/TracyEvent.hpp index 5ef92e40..fe6c5110 100644 --- a/server/TracyEvent.hpp +++ b/server/TracyEvent.hpp @@ -112,12 +112,17 @@ struct LockEvent uint8_t lockingThread; Type type; uint8_t lockCount; - uint64_t waitShared; uint64_t waitList; +}; + +struct LockEventShared : public LockEvent +{ + uint64_t waitShared; uint64_t sharedList; }; enum { LockEventSize = sizeof( LockEvent ) }; +enum { LockEventSharedSize = sizeof( LockEventShared ) }; enum { MaxLockThreads = sizeof( LockEvent::waitList ) * 8 }; static_assert( std::numeric_limits::max() >= MaxLockThreads, "Not enough space for lock count." ); diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 9d4be714..9c557464 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -308,11 +308,23 @@ View::View( FileRead& f ) } f.Read( &tsz, sizeof( tsz ) ); lockmap.timeline.reserve( tsz ); - for( uint64_t i=0; i(); - f.Read( lev, sizeof( LockEvent ) ); - lockmap.timeline.push_back( lev ); + 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 ) ); @@ -742,7 +754,7 @@ void View::ProcessLockAnnounce( const QueueLockAnnounce& ev ) else { it->second.srcloc = ShrinkSourceLocation( ev.lckloc ); - it->second.type = ev.type; + assert( it->second.type == ev.type ); it->second.visible = true; it->second.valid = true; } @@ -751,82 +763,95 @@ void View::ProcessLockAnnounce( const QueueLockAnnounce& ev ) void View::ProcessLockWait( const QueueLockWait& ev ) { - auto lev = m_slab.Alloc(); - lev->time = ev.time * m_timerMul; - lev->type = LockEvent::Type::Wait; - lev->srcloc = 0; - 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 = ev.time * m_timerMul; + lev->type = LockEvent::Type::Wait; + lev->srcloc = 0; + InsertLockEvent( it->second, lev, ev.thread ); } void View::ProcessLockObtain( const QueueLockObtain& ev ) { - auto lev = m_slab.Alloc(); + 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 = ev.time * m_timerMul; lev->type = LockEvent::Type::Obtain; lev->srcloc = 0; - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - InsertLockEvent( m_lockMap[ev.id], lev, ev.thread ); + InsertLockEvent( lock, lev, ev.thread ); } void View::ProcessLockRelease( const QueueLockRelease& ev ) { - auto lev = m_slab.Alloc(); + 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 = ev.time * m_timerMul; lev->type = LockEvent::Type::Release; lev->srcloc = 0; - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - InsertLockEvent( m_lockMap[ev.id], lev, ev.thread ); + InsertLockEvent( lock, lev, ev.thread ); } void View::ProcessLockSharedWait( const QueueLockWait& ev ) { - auto lev = m_slab.Alloc(); - lev->time = ev.time * m_timerMul; - lev->type = LockEvent::Type::WaitShared; - lev->srcloc = 0; - 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 = ev.time * m_timerMul; + lev->type = LockEvent::Type::WaitShared; + lev->srcloc = 0; + InsertLockEvent( it->second, lev, ev.thread ); } void View::ProcessLockSharedObtain( const QueueLockObtain& ev ) { - auto lev = m_slab.Alloc(); + 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 = ev.time * m_timerMul; lev->type = LockEvent::Type::ObtainShared; lev->srcloc = 0; - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - InsertLockEvent( m_lockMap[ev.id], lev, ev.thread ); + InsertLockEvent( lock, lev, ev.thread ); } void View::ProcessLockSharedRelease( const QueueLockRelease& ev ) { - auto lev = m_slab.Alloc(); + 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 = ev.time * m_timerMul; lev->type = LockEvent::Type::ReleaseShared; lev->srcloc = 0; - assert( m_lockMap.find( ev.id ) != m_lockMap.end() ); - InsertLockEvent( m_lockMap[ev.id], lev, ev.thread ); + InsertLockEvent( lock, lev, ev.thread ); } void View::ProcessLockMark( const QueueLockMark& ev ) @@ -1296,41 +1321,60 @@ void View::NewZone( ZoneEvent* zone, uint64_t thread ) } } -void View::InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread ) +static void UpdateLockCountLockable( LockMap& lockmap, size_t pos ) { - 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() ) + uint8_t lockingThread; + uint8_t lockCount; + uint64_t waitList; + + if( pos == 0 ) { - 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 ); + lockingThread = 0; + lockCount = 0; + waitList = 0; } 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 ) ); + 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++; } } -void View::UpdateLockCount( LockMap& lockmap, size_t pos ) +static void UpdateLockCountSharedLockable( LockMap& lockmap, size_t pos ) { auto& timeline = lockmap.timeline; uint8_t lockingThread; @@ -1349,7 +1393,7 @@ void View::UpdateLockCount( LockMap& lockmap, size_t pos ) } else { - const auto tl = timeline[pos-1]; + const auto tl = (LockEventShared*)timeline[pos-1]; lockingThread = tl->lockingThread; lockCount = tl->lockCount; waitShared = tl->waitShared; @@ -1362,7 +1406,7 @@ void View::UpdateLockCount( LockMap& lockmap, size_t pos ) // due to the async retrieval of data from threads that not possible. while( pos != end ) { - const auto tl = timeline[pos]; + const auto tl = (LockEventShared*)timeline[pos]; const auto tbit = uint64_t( 1 ) << tl->thread; switch( (LockEvent::Type)tl->type ) { @@ -1406,6 +1450,52 @@ void View::UpdateLockCount( LockMap& lockmap, size_t 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() ) @@ -2940,6 +3030,7 @@ static Vector::iterator GetNextLockEvent( const Vector:: static Vector::iterator GetNextLockEventShared( const Vector::iterator& it, const Vector::iterator& end, LockState& nextState, uint64_t threadBit ) { + const auto itptr = (const LockEventShared*)*it; auto next = it; next++; @@ -2948,10 +3039,11 @@ static Vector::iterator GetNextLockEventShared( const VectorlockCount != 0 ) + const auto ptr = (const LockEventShared*)*next; + if( ptr->lockCount != 0 ) { - const auto wait = (*next)->waitList | (*next)->waitShared; - if( GetThreadBit( (*next)->lockingThread ) == threadBit ) + const auto wait = ptr->waitList | ptr->waitShared; + if( GetThreadBit( ptr->lockingThread ) == threadBit ) { nextState = AreOtherWaiting( wait, threadBit ) ? LockState::HasBlockingLock : LockState::HasLock; break; @@ -2962,12 +3054,12 @@ static Vector::iterator GetNextLockEventShared( const VectorsharedList, threadBit ) ) + else if( IsThreadWaiting( ptr->sharedList, threadBit ) ) { - nextState = ( (*next)->waitList != 0 ) ? LockState::HasBlockingLock : LockState::HasLock; + nextState = ( ptr->waitList != 0 ) ? LockState::HasBlockingLock : LockState::HasLock; break; } - else if( (*next)->sharedList != 0 && IsThreadWaiting( (*next)->waitList, threadBit ) ) + else if( ptr->sharedList != 0 && IsThreadWaiting( ptr->waitList, threadBit ) ) { nextState = LockState::WaitLock; break; @@ -2978,25 +3070,26 @@ static Vector::iterator GetNextLockEventShared( const VectorlockCount == 0 && !IsThreadWaiting( (*next)->sharedList, threadBit ) ) + const auto ptr = (const LockEventShared*)*next; + if( ptr->lockCount == 0 && !IsThreadWaiting( ptr->sharedList, threadBit ) ) { nextState = LockState::Nothing; break; } - if( (*next)->waitList != 0 ) + if( ptr->waitList != 0 ) { - if( AreOtherWaiting( (*next)->waitList, threadBit ) ) + if( AreOtherWaiting( ptr->waitList, threadBit ) ) { nextState = LockState::HasBlockingLock; } break; } - else if( !IsThreadWaiting( (*next)->sharedList, threadBit ) && (*next)->waitShared != 0 ) + else if( !IsThreadWaiting( ptr->sharedList, threadBit ) && ptr->waitShared != 0 ) { nextState = LockState::HasBlockingLock; break; } - if( (*next)->waitList != (*it)->waitList || (*next)->waitShared != (*it)->waitShared || (*next)->lockCount != (*it)->lockCount || (*next)->sharedList != (*it)->sharedList ) + if( ptr->waitList != itptr->waitList || ptr->waitShared != itptr->waitShared || ptr->lockCount != itptr->lockCount || ptr->sharedList != itptr->sharedList ) { break; } @@ -3006,12 +3099,13 @@ static Vector::iterator GetNextLockEventShared( const VectorlockCount == 0 && !IsThreadWaiting( (*next)->sharedList, threadBit ) ) + const auto ptr = (const LockEventShared*)*next; + if( ptr->lockCount == 0 && !IsThreadWaiting( ptr->sharedList, threadBit ) ) { nextState = LockState::Nothing; break; } - if( (*next)->waitList != (*it)->waitList || (*next)->waitShared != (*it)->waitShared || (*next)->lockCount != (*it)->lockCount || (*next)->sharedList != (*it)->sharedList ) + if( ptr->waitList != itptr->waitList || ptr->waitShared != itptr->waitShared || ptr->lockCount != itptr->lockCount || ptr->sharedList != itptr->sharedList ) { break; } @@ -3021,22 +3115,23 @@ static Vector::iterator GetNextLockEventShared( const VectorlockingThread ) == threadBit ) + const auto ptr = (const LockEventShared*)*next; + if( GetThreadBit( ptr->lockingThread ) == threadBit ) { - const auto wait = (*next)->waitList | (*next)->waitShared; + const auto wait = ptr->waitList | ptr->waitShared; nextState = AreOtherWaiting( wait, threadBit ) ? LockState::HasBlockingLock : LockState::HasLock; break; } - if( IsThreadWaiting( (*next)->sharedList, threadBit ) ) + if( IsThreadWaiting( ptr->sharedList, threadBit ) ) { - nextState = ( (*next)->waitList != 0 ) ? LockState::HasBlockingLock : LockState::HasLock; + nextState = ( ptr->waitList != 0 ) ? LockState::HasBlockingLock : LockState::HasLock; break; } - if( (*next)->lockingThread != (*it)->lockingThread ) + if( ptr->lockingThread != itptr->lockingThread ) { break; } - if( (*next)->lockCount == 0 && !IsThreadWaiting( (*next)->waitShared, threadBit ) ) + if( ptr->lockCount == 0 && !IsThreadWaiting( ptr->waitShared, threadBit ) ) { break; } @@ -3109,22 +3204,23 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, } else { - if( (*vbegin)->lockCount != 0 ) + const auto ptr = (LockEventShared*)*vbegin; + if( ptr->lockCount != 0 ) { - if( (*vbegin)->lockingThread == thread ) + if( ptr->lockingThread == thread ) { - state = ( AreOtherWaiting( (*vbegin)->waitList, threadBit ) || AreOtherWaiting( (*vbegin)->waitShared, threadBit ) ) ? LockState::HasBlockingLock : LockState::HasLock; + state = ( AreOtherWaiting( ptr->waitList, threadBit ) || AreOtherWaiting( ptr->waitShared, threadBit ) ) ? LockState::HasBlockingLock : LockState::HasLock; } - else if( IsThreadWaiting( (*vbegin)->waitList, threadBit ) || IsThreadWaiting( (*vbegin)->waitShared, threadBit ) ) + else if( IsThreadWaiting( ptr->waitList, threadBit ) || IsThreadWaiting( ptr->waitShared, threadBit ) ) { state = LockState::WaitLock; } } - else if( IsThreadWaiting( (*vbegin)->sharedList, threadBit ) ) + else if( IsThreadWaiting( ptr->sharedList, threadBit ) ) { - state = (*vbegin)->waitList != 0 ? LockState::HasBlockingLock : LockState::HasLock; + state = ptr->waitList != 0 ? LockState::HasBlockingLock : LockState::HasLock; } - else if( (*vbegin)->sharedList != 0 && IsThreadWaiting( (*vbegin)->waitList, threadBit ) ) + else if( ptr->sharedList != 0 && IsThreadWaiting( ptr->waitList, threadBit ) ) { state = LockState::WaitLock; } @@ -4213,9 +4309,19 @@ void View::Write( FileWrite& f ) } sz = v.second.timeline.size(); f.Write( &sz, sizeof( sz ) ); - for( auto& lev : v.second.timeline ) + if( v.second.type == LockType::Lockable ) { - f.Write( lev, sizeof( LockEvent ) ); + for( auto& lev : v.second.timeline ) + { + f.Write( lev, sizeof( LockEvent ) ); + } + } + else + { + for( auto& lev : v.second.timeline ) + { + f.Write( lev, sizeof( LockEventShared ) ); + } } } diff --git a/server/TracyView.hpp b/server/TracyView.hpp index c283b327..376a842b 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -116,7 +116,6 @@ private: tracy_force_inline void NewZone( ZoneEvent* zone, uint64_t thread ); void InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread ); - void UpdateLockCount( LockMap& lockmap, size_t pos ); void InsertPlot( PlotData* plot, int64_t time, double val ); void HandlePlotName( uint64_t name, char* str, size_t sz );