1
0
mirror of https://github.com/wolfpld/tracy.git synced 2025-03-20 07:40:02 +08:00

Fix locks with more than two threads.

This commit is contained in:
Bartosz Taudul 2017-10-08 23:03:38 +02:00
parent 45cb4b144f
commit a6c5993401
3 changed files with 210 additions and 112 deletions

View File

@ -1,6 +1,8 @@
#ifndef __TRACYEVENT_HPP__ #ifndef __TRACYEVENT_HPP__
#define __TRACYEVENT_HPP__ #define __TRACYEVENT_HPP__
#include <limits>
#include "TracyVector.hpp" #include "TracyVector.hpp"
namespace tracy namespace tracy
@ -40,15 +42,19 @@ struct LockEvent
}; };
int64_t time; int64_t time;
uint64_t thread;
uint64_t srcloc; uint64_t srcloc;
uint64_t waitList;
uint8_t thread;
uint8_t lockingThread;
uint8_t lockCount; uint8_t lockCount;
uint8_t waitCount;
Type type; Type type;
}; };
enum { LockEventSize = sizeof( LockEvent ) }; enum { LockEventSize = sizeof( LockEvent ) };
enum { MaxLockThreads = sizeof( LockEvent::waitList ) * 8 };
static_assert( std::numeric_limits<decltype(LockEvent::lockCount)>::max() >= MaxLockThreads, "Not enough space for lock count." );
#pragma pack() #pragma pack()
} }

View File

@ -67,7 +67,7 @@ View::View( const char* addr )
, m_zvStart( 0 ) , m_zvStart( 0 )
, m_zvEnd( 0 ) , m_zvEnd( 0 )
, m_zoneInfoWindow( nullptr ) , m_zoneInfoWindow( nullptr )
, m_lockHighlight( nullptr ) , m_lockHighlight { -1 }
{ {
assert( s_instance == nullptr ); assert( s_instance == nullptr );
s_instance = this; s_instance = this;
@ -181,7 +181,8 @@ View::View( FileRead& f )
{ {
uint64_t t; uint64_t t;
f.Read( &t, sizeof( t ) ); f.Read( &t, sizeof( t ) );
lockmap.threads.emplace( t ); lockmap.threadMap.emplace( t, lockmap.threadList.size() );
lockmap.threadList.emplace_back( t );
} }
f.Read( &tsz, sizeof( tsz ) ); f.Read( &tsz, sizeof( tsz ) );
for( uint64_t i=0; i<tsz; i++ ) for( uint64_t i=0; i<tsz; i++ )
@ -508,47 +509,50 @@ void View::ProcessLockWait( const QueueLockWait& ev )
{ {
auto lev = m_slab.Alloc<LockEvent>(); auto lev = m_slab.Alloc<LockEvent>();
lev->time = ev.time * m_timerMul; lev->time = ev.time * m_timerMul;
lev->thread = ev.thread;
lev->type = LockEvent::Type::Wait; lev->type = LockEvent::Type::Wait;
lev->srcloc = 0; lev->srcloc = 0;
std::lock_guard<std::mutex> lock( m_lock ); std::lock_guard<std::mutex> lock( m_lock );
InsertLockEvent( m_lockMap[ev.id], lev ); InsertLockEvent( m_lockMap[ev.id], lev, ev.thread );
} }
void View::ProcessLockObtain( const QueueLockObtain& ev ) void View::ProcessLockObtain( const QueueLockObtain& ev )
{ {
auto lev = m_slab.Alloc<LockEvent>(); auto lev = m_slab.Alloc<LockEvent>();
lev->time = ev.time * m_timerMul; lev->time = ev.time * m_timerMul;
lev->thread = ev.thread;
lev->type = LockEvent::Type::Obtain; lev->type = LockEvent::Type::Obtain;
lev->srcloc = 0; lev->srcloc = 0;
std::lock_guard<std::mutex> lock( m_lock ); std::lock_guard<std::mutex> lock( m_lock );
InsertLockEvent( m_lockMap[ev.id], lev ); InsertLockEvent( m_lockMap[ev.id], lev, ev.thread );
} }
void View::ProcessLockRelease( const QueueLockRelease& ev ) void View::ProcessLockRelease( const QueueLockRelease& ev )
{ {
auto lev = m_slab.Alloc<LockEvent>(); auto lev = m_slab.Alloc<LockEvent>();
lev->time = ev.time * m_timerMul; lev->time = ev.time * m_timerMul;
lev->thread = ev.thread;
lev->type = LockEvent::Type::Release; lev->type = LockEvent::Type::Release;
lev->srcloc = 0; lev->srcloc = 0;
std::lock_guard<std::mutex> lock( m_lock ); std::lock_guard<std::mutex> lock( m_lock );
InsertLockEvent( m_lockMap[ev.id], lev ); InsertLockEvent( m_lockMap[ev.id], lev, ev.thread );
} }
void View::ProcessLockMark( const QueueLockMark& ev ) void View::ProcessLockMark( const QueueLockMark& ev )
{ {
CheckSourceLocation( ev.srcloc ); CheckSourceLocation( ev.srcloc );
auto lit = m_lockMap.find( ev.id );
assert( lit != m_lockMap.end() );
std::lock_guard<std::mutex> lock( m_lock ); std::lock_guard<std::mutex> lock( m_lock );
auto it = m_lockMap[ev.id].timeline.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(;;) for(;;)
{ {
--it; --it;
if( (*it)->thread == ev.thread ) if( (*it)->thread == thread )
{ {
switch( (*it)->type ) switch( (*it)->type )
{ {
@ -707,42 +711,52 @@ void View::InsertZone( Event* zone, Event* parent, Vector<Event*>& vec )
} }
} }
void View::InsertLockEvent( LockMap& lockmap, LockEvent* lev ) void View::InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread )
{ {
lockmap.threads.insert( lev->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;
auto& timeline = lockmap.timeline; auto& timeline = lockmap.timeline;
if( timeline.empty() || timeline.back()->time < lev->time ) if( timeline.empty() || timeline.back()->time < lev->time )
{ {
timeline.push_back( lev ); timeline.push_back( lev );
UpdateLockCount( timeline, timeline.size() - 1 ); UpdateLockCount( lockmap, timeline.size() - 1 );
} }
else else
{ {
auto it = std::lower_bound( timeline.begin(), timeline.end(), lev->time, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } ); 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 ); it = timeline.insert( it, lev );
UpdateLockCount( timeline, std::distance( timeline.begin(), it ) ); UpdateLockCount( lockmap, std::distance( timeline.begin(), it ) );
} }
} }
void View::UpdateLockCount( Vector<LockEvent*>& timeline, size_t pos ) void View::UpdateLockCount( LockMap& lockmap, size_t pos )
{ {
auto& timeline = lockmap.timeline;
uint8_t lockingThread = pos == 0 ? 0 : timeline[pos-1]->lockingThread;
uint8_t lockCount = pos == 0 ? 0 : timeline[pos-1]->lockCount; uint8_t lockCount = pos == 0 ? 0 : timeline[pos-1]->lockCount;
uint8_t waitCount = pos == 0 ? 0 : timeline[pos-1]->waitCount; uint64_t waitList = pos == 0 ? 0 : timeline[pos-1]->waitList;
const auto end = timeline.size(); const auto end = timeline.size();
while( pos != end ) while( pos != end )
{ {
const auto tbit = 1 << timeline[pos]->thread;
switch( timeline[pos]->type ) switch( timeline[pos]->type )
{ {
case LockEvent::Type::Wait: case LockEvent::Type::Wait:
assert( waitCount < std::numeric_limits<uint8_t>::max() ); waitList |= tbit;
waitCount++;
break; break;
case LockEvent::Type::Obtain: case LockEvent::Type::Obtain:
assert( lockCount < std::numeric_limits<uint8_t>::max() ); assert( lockCount < std::numeric_limits<uint8_t>::max() );
assert( waitCount > 0 ); assert( waitList | tbit != 0 );
waitList &= ~tbit;
lockingThread = timeline[pos]->thread;
lockCount++; lockCount++;
waitCount--;
break; break;
case LockEvent::Type::Release: case LockEvent::Type::Release:
assert( lockCount > 0 ); assert( lockCount > 0 );
@ -751,8 +765,9 @@ void View::UpdateLockCount( Vector<LockEvent*>& timeline, size_t pos )
default: default:
break; break;
} }
timeline[pos]->lockingThread = lockingThread;
timeline[pos]->waitList = waitList;
timeline[pos]->lockCount = lockCount; timeline[pos]->lockCount = lockCount;
timeline[pos]->waitCount = waitCount;
pos++; pos++;
} }
} }
@ -1339,7 +1354,7 @@ void View::DrawZones()
while( false ); while( false );
// zones // zones
const LockEvent* nextLockHighlight = nullptr; LockHighlight nextLockHighlight { -1 };
const auto ostep = ImGui::GetFontSize() + 1; const auto ostep = ImGui::GetFontSize() + 1;
int offset = 20; int offset = 20;
for( auto& v : m_threads ) for( auto& v : m_threads )
@ -1527,7 +1542,12 @@ int View::DrawZoneLevel( const Vector<Event*>& vec, bool hover, double pxns, con
return maxdepth; return maxdepth;
} }
int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int _offset, const LockEvent*& highlight ) static inline bool IsThreadWaiting( uint64_t bitlist, uint8_t thread )
{
return ( bitlist & ( 1 << thread ) ) != 0;
}
int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int _offset, LockHighlight& highlight )
{ {
enum class State enum class State
{ {
@ -1541,50 +1561,21 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
for( auto& v : m_lockMap ) for( auto& v : m_lockMap )
{ {
auto& lockmap = v.second; auto& lockmap = v.second;
if( lockmap.threads.find( tid ) == lockmap.threads.end() ) continue; auto it = lockmap.threadMap.find( tid );
if( it == lockmap.threadMap.end() ) continue;
auto& tl = lockmap.timeline; auto& tl = lockmap.timeline;
assert( !tl.empty() ); assert( !tl.empty() );
if( tl.back()->time < m_zvStart ) continue; if( tl.back()->time < m_zvStart ) continue;
const auto thread = it->second;
auto vbegin = std::lower_bound( tl.begin(), tl.end(), m_zvStart - m_delay, [] ( const auto& l, const auto& r ) { return l->time < r; } ); 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( tl.begin(), tl.end(), m_zvEnd + m_resolution, [] ( const auto& l, const auto& r ) { return l->time < r; } ); const auto vend = std::lower_bound( tl.begin(), tl.end(), m_zvEnd + m_resolution, [] ( const auto& l, const auto& r ) { return l->time < r; } );
auto vendn = tl.end();
auto blc = (*vbegin)->lockCount;
auto bth = (*vbegin)->thread;
if( vbegin > tl.begin() ) vbegin--; if( vbegin > tl.begin() ) vbegin--;
State state = State::Nothing;
if( (*vbegin)->lockCount > 0 || ( blc > 0 && bth == tid ) )
{
auto it = vbegin;
bool waiting = (*vbegin)->waitCount > 0;
for(;;)
{
if( (*it)->type == LockEvent::Type::Obtain )
{
if( (*it)->thread == tid )
{
state = waiting ? State::HasBlockingLock : State::HasLock;
}
break;
}
--it;
}
if( state == State::Nothing && (*vbegin)->waitCount > 0 )
{
auto it = vbegin;
for(;;)
{
if( (*it)->waitCount == 0 ) break;
if( (*it)->type == LockEvent::Type::Wait && (*it)->thread == tid )
{
state = State::WaitLock;
break;
}
--it;
}
}
}
bool drawn = false; bool drawn = false;
const auto w = ImGui::GetWindowContentRegionWidth(); const auto w = ImGui::GetWindowContentRegionWidth();
const auto ty = ImGui::GetFontSize(); const auto ty = ImGui::GetFontSize();
@ -1595,6 +1586,26 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
const auto dsz = m_delay * pxns; const auto dsz = m_delay * pxns;
const auto rsz = m_resolution * pxns; const auto rsz = m_resolution * pxns;
State state = State::Nothing;
if( (*vbegin)->lockCount != 0 )
{
if( (*vbegin)->lockingThread == thread )
{
if( (*vbegin)->waitList == 0 )
{
state = State::HasLock;
}
else
{
state = State::HasBlockingLock;
}
}
else if( IsThreadWaiting( (*vbegin)->waitList, thread ) )
{
state = State::WaitLock;
}
}
while( vbegin < vend ) while( vbegin < vend )
{ {
State nextState = State::Nothing; State nextState = State::Nothing;
@ -1604,22 +1615,42 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
switch( state ) switch( state )
{ {
case State::Nothing: case State::Nothing:
while( next != tl.end() ) while( next < vendn )
{ {
if( (*next)->thread == tid && (*next)->lockCount > 0 ) if( (*next)->lockCount != 0 )
{ {
nextState = (*next)->waitCount > 0 ? State::WaitLock : State::HasLock; if( (*next)->lockingThread == thread )
break; {
if( (*next)->waitList == 0 )
{
nextState = State::HasLock;
break;
}
else
{
nextState = State::HasBlockingLock;
break;
}
}
else if( IsThreadWaiting( (*next)->waitList, thread ) )
{
nextState = State::WaitLock;
break;
}
} }
next++; next++;
} }
break; break;
case State::HasLock: case State::HasLock:
nextState = State::Nothing; nextState = State::HasLock;
while( next != tl.end() ) while( next < vendn )
{ {
if( (*next)->lockCount == 0 ) break; if( (*next)->lockCount == 0 )
if( (*next)->waitCount > 0 ) {
nextState = State::Nothing;
break;
}
if( (*next)->waitList != 0 )
{ {
nextState = State::HasBlockingLock; nextState = State::HasBlockingLock;
break; break;
@ -1628,19 +1659,46 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
} }
break; break;
case State::HasBlockingLock: case State::HasBlockingLock:
nextState = State::Nothing; nextState = State::HasBlockingLock;
while( next != tl.end() ) while( next < vendn )
{ {
if( (*next)->lockCount == 0 ) break; if( (*next)->lockCount == 0 )
// Can't go back to non-blocking lock. At least not yet. Maybe with timed mutex. But no support now. {
nextState = State::Nothing;
break;
}
if( (*next)->waitList != (*vbegin)->waitList )
{
break;
}
next++; next++;
} }
break; break;
case State::WaitLock: case State::WaitLock:
nextState = State::HasLock; nextState = State::WaitLock;
while( next != tl.end() ) while( next < vendn )
{ {
if( (*next)->type == LockEvent::Type::Obtain && (*next)->thread == tid ) break; if( (*next)->lockingThread == thread )
{
if( (*next)->waitList == 0 )
{
nextState = State::HasLock;
break;
}
else
{
nextState = State::HasBlockingLock;
break;
}
}
if( (*next)->lockingThread != (*vbegin)->lockingThread )
{
break;
}
if( (*next)->lockCount == 0 )
{
break;
}
next++; next++;
} }
break; break;
@ -1660,7 +1718,43 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
bool itemHovered = hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( px1, double( w + 10 ) ), offset + ty ) ); bool itemHovered = hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( px1, double( w + 10 ) ), offset + ty ) );
if( itemHovered ) if( itemHovered )
{ {
highlight = *vbegin; highlight.blocked = state == State::HasBlockingLock;
if( !highlight.blocked )
{
highlight.id = v.first;
highlight.begin = (*vbegin)->time;
highlight.end = (*next)->time;
highlight.thread = thread;
highlight.blocked = false;
}
else
{
auto b = vbegin;
while( b != tl.begin() )
{
if( (*b)->lockingThread != (*vbegin)->lockingThread )
{
break;
}
b--;
}
b++;
highlight.begin = (*b)->time;
auto e = next;
while( e != tl.end() )
{
if( (*e)->lockingThread != (*next)->lockingThread )
{
highlight.id = v.first;
highlight.end = (*e)->time;
highlight.thread = thread;
break;
}
e++;
}
}
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text( "Lock #%" PRIu64, v.first ); ImGui::Text( "Lock #%" PRIu64, v.first );
ImGui::Text( "%s", GetString( srcloc.function ) ); ImGui::Text( "%s", GetString( srcloc.function ) );
@ -1669,23 +1763,19 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
ImGui::Separator(); ImGui::Separator();
uint64_t markloc = 0; uint64_t markloc = 0;
if( (*vbegin)->thread == tid ) auto it = vbegin;
for(;;)
{ {
markloc = (*vbegin)->srcloc; if( (*it)->thread == thread )
}
else
{
auto it = vbegin;
--it;
for(;;)
{ {
if( (*it)->thread == tid ) if( ( (*it)->lockingThread == thread || IsThreadWaiting( (*it)->waitList, thread ) ) && (*it)->srcloc != 0 )
{ {
assert( (*it)->type == LockEvent::Type::Wait || (*it)->type == LockEvent::Type::Obtain );
markloc = (*it)->srcloc; markloc = (*it)->srcloc;
break; break;
} }
} }
if( it == tl.begin() ) break;
--it;
} }
if( markloc != 0 ) if( markloc != 0 )
{ {
@ -1695,6 +1785,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
ImGui::Text( "%s:%i", GetString( marklocdata.file ), marklocdata.line ); ImGui::Text( "%s:%i", GetString( marklocdata.file ), marklocdata.line );
ImGui::Separator(); ImGui::Separator();
} }
switch( state ) switch( state )
{ {
case State::HasLock: case State::HasLock:
@ -1703,32 +1794,23 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
case State::HasBlockingLock: case State::HasBlockingLock:
{ {
ImGui::Text( "Thread \"%s\" has lock. Other threads are blocked:", GetThreadString( tid ) ); ImGui::Text( "Thread \"%s\" has lock. Other threads are blocked:", GetThreadString( tid ) );
auto it = next; auto waitList = (*vbegin)->waitList;
do int t = 0;
while( waitList != 0 )
{ {
--it; if( waitList & 0x1 )
if( (*it)->type == LockEvent::Type::Wait )
{ {
ImGui::Text( "\"%s\"", GetThreadString( (*it)->thread ) ); ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[t] ) );
} }
waitList >>= 1;
t++;
} }
while( it != vbegin );
break; break;
} }
case State::WaitLock: case State::WaitLock:
{ {
ImGui::Text( "Thread \"%s\" is blocked by other thread:", GetThreadString( tid ) ); ImGui::Text( "Thread \"%s\" is blocked by other thread:", GetThreadString( tid ) );
auto it = vbegin; ImGui::Text( "\"%s\"", GetThreadString( lockmap.threadList[(*vbegin)->lockingThread] ) );
--it;
for(;;)
{
if( (*it)->type == LockEvent::Type::Obtain )
{
ImGui::Text( "\"%s\"", GetThreadString( (*it)->thread ) );
break;
}
--it;
}
break; break;
} }
default: default:
@ -1740,7 +1822,7 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
const auto cfilled = state == State::HasLock ? 0xFF228A22 : ( state == State::HasBlockingLock ? 0xFF228A8A : 0xFF2222BD ); const auto cfilled = state == State::HasLock ? 0xFF228A22 : ( state == State::HasBlockingLock ? 0xFF228A8A : 0xFF2222BD );
draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( px1, double( w + 10 ) ), offset + ty ), cfilled, 2.f ); draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( px1, double( w + 10 ) ), offset + ty ), cfilled, 2.f );
if( !itemHovered && m_lockHighlight == *vbegin ) if( m_lockHighlight.thread != thread && ( state == State::HasBlockingLock ) != m_lockHighlight.blocked && next != tl.end() && m_lockHighlight.id == v.first && m_lockHighlight.begin <= (*vbegin)->time && m_lockHighlight.end >= (*next)->time )
{ {
const auto t = uint8_t( ( sin( std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() ).count() * 0.01 ) * 0.5 + 0.5 ) * 255 ); const auto t = uint8_t( ( sin( std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() ).count() * 0.01 ) * 0.5 + 0.5 ) * 255 );
draw->AddRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( px1, double( w + 10 ) ), offset + ty ), 0x00FFFFFF | ( t << 24 ), 2.f, -1, 2.f ); draw->AddRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( px1, double( w + 10 ) ), offset + ty ), 0x00FFFFFF | ( t << 24 ), 2.f, -1, 2.f );
@ -2057,9 +2139,9 @@ void View::Write( FileWrite& f )
{ {
f.Write( &v.first, sizeof( v.first ) ); f.Write( &v.first, sizeof( v.first ) );
f.Write( &v.second.srcloc, sizeof( v.second.srcloc ) ); f.Write( &v.second.srcloc, sizeof( v.second.srcloc ) );
sz = v.second.threads.size(); sz = v.second.threadList.size();
f.Write( &sz, sizeof( sz ) ); f.Write( &sz, sizeof( sz ) );
for( auto& t : v.second.threads ) for( auto& t : v.second.threadList )
{ {
f.Write( &t, sizeof( t ) ); f.Write( &t, sizeof( t ) );
} }

View File

@ -48,7 +48,17 @@ private:
{ {
uint64_t srcloc; uint64_t srcloc;
Vector<LockEvent*> timeline; Vector<LockEvent*> timeline;
std::unordered_set<uint64_t> threads; std::unordered_map<uint64_t, uint8_t> threadMap;
std::vector<uint64_t> threadList;
};
struct LockHighlight
{
int64_t id;
uint64_t begin;
uint64_t end;
uint8_t thread;
bool blocked;
}; };
void Worker(); void Worker();
@ -85,8 +95,8 @@ private:
void InsertZone( Event* zone, Event* parent, Vector<Event*>& vec ); void InsertZone( Event* zone, Event* parent, Vector<Event*>& vec );
void InsertLockEvent( LockMap& lockmap, LockEvent* lev ); void InsertLockEvent( LockMap& lockmap, LockEvent* lev, uint64_t thread );
void UpdateLockCount( Vector<LockEvent*>& timeline, size_t pos ); void UpdateLockCount( LockMap& lockmap, size_t pos );
uint64_t GetFrameTime( size_t idx ) const; uint64_t GetFrameTime( size_t idx ) const;
uint64_t GetFrameBegin( size_t idx ) const; uint64_t GetFrameBegin( size_t idx ) const;
@ -104,7 +114,7 @@ private:
void DrawFrames(); void DrawFrames();
void DrawZones(); void DrawZones();
int DrawZoneLevel( const Vector<Event*>& vec, bool hover, double pxns, const ImVec2& wpos, int offset, int depth ); int DrawZoneLevel( const Vector<Event*>& vec, bool hover, double pxns, const ImVec2& wpos, int offset, int depth );
int DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int offset, const LockEvent*& highlight ); int DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos, int offset, LockHighlight& highlight );
void DrawZoneInfoWindow(); void DrawZoneInfoWindow();
uint32_t GetZoneColor( const Event& ev ); uint32_t GetZoneColor( const Event& ev );
@ -175,7 +185,7 @@ private:
const Event* m_zoneInfoWindow; const Event* m_zoneInfoWindow;
const Event* m_zoneHighlight; const Event* m_zoneHighlight;
const LockEvent* m_lockHighlight; LockHighlight m_lockHighlight;
}; };
} }