Extract lock state handling to a separate context class.

This commit is contained in:
Bartosz Taudul 2019-09-21 14:55:14 +02:00
parent 4c736aecfa
commit a221f121ba

View File

@ -11,11 +11,10 @@
namespace tracy namespace tracy
{ {
template<class T> class LockableCtx
class Lockable
{ {
public: public:
tracy_force_inline Lockable( const SourceLocationData* srcloc ) tracy_force_inline LockableCtx( const SourceLocationData* srcloc )
: m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) ) : m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
, m_lockCount( 0 ) , m_lockCount( 0 )
@ -33,18 +32,16 @@ public:
MemWrite( &item->lockAnnounce.time, Profiler::GetTime() ); MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );
MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc ); MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
MemWrite( &item->lockAnnounce.type, LockType::Lockable ); MemWrite( &item->lockAnnounce.type, LockType::Lockable );
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item ); GetProfiler().DeferItem( *item );
#endif #endif
tail.store( magic + 1, std::memory_order_release ); tail.store( magic + 1, std::memory_order_release );
} }
Lockable( const Lockable& ) = delete; LockableCtx( const LockableCtx& ) = delete;
Lockable& operator=( const Lockable& ) = delete; LockableCtx& operator=( const LockableCtx& ) = delete;
~Lockable() tracy_force_inline ~LockableCtx()
{ {
Magic magic; Magic magic;
auto token = GetToken(); auto token = GetToken();
@ -54,15 +51,13 @@ public:
MemWrite( &item->lockTerminate.id, m_id ); MemWrite( &item->lockTerminate.id, m_id );
MemWrite( &item->lockTerminate.time, Profiler::GetTime() ); MemWrite( &item->lockTerminate.time, Profiler::GetTime() );
MemWrite( &item->lockTerminate.type, LockType::Lockable ); MemWrite( &item->lockTerminate.type, LockType::Lockable );
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item ); GetProfiler().DeferItem( *item );
#endif #endif
tail.store( magic + 1, std::memory_order_release ); tail.store( magic + 1, std::memory_order_release );
} }
tracy_force_inline void lock() tracy_force_inline bool BeforeLock()
{ {
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
bool queue = false; bool queue = false;
@ -74,40 +69,31 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed ); if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true; if( connected ) queue = true;
} }
if( !queue ) if( !queue ) return false;
{
m_lockable.lock();
return;
}
#endif #endif
const auto thread = GetThreadHandle();
{ auto item = Profiler::QueueSerial();
auto item = Profiler::QueueSerial(); MemWrite( &item->hdr.type, QueueType::LockWait );
MemWrite( &item->hdr.type, QueueType::LockWait ); MemWrite( &item->lockWait.thread, GetThreadHandle() );
MemWrite( &item->lockWait.thread, thread ); MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.id, m_id ); MemWrite( &item->lockWait.time, Profiler::GetTime() );
MemWrite( &item->lockWait.time, Profiler::GetTime() ); MemWrite( &item->lockWait.type, LockType::Lockable );
MemWrite( &item->lockWait.type, LockType::Lockable ); Profiler::QueueSerialFinish();
Profiler::QueueSerialFinish(); return true;
}
m_lockable.lock();
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, thread );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
} }
tracy_force_inline void unlock() tracy_force_inline void AfterLock()
{ {
m_lockable.unlock(); auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, GetThreadHandle() );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
tracy_force_inline void AfterUnlock()
{
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
m_lockCount.fetch_sub( 1, std::memory_order_relaxed ); m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !m_active.load( std::memory_order_relaxed ) ) return; if( !m_active.load( std::memory_order_relaxed ) ) return;
@ -126,12 +112,10 @@ public:
Profiler::QueueSerialFinish(); Profiler::QueueSerialFinish();
} }
tracy_force_inline bool try_lock() tracy_force_inline void AfterTryLock( bool acquired )
{ {
const auto ret = m_lockable.try_lock();
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
if( !ret ) return ret; if( !acquired ) return;
bool queue = false; bool queue = false;
const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed ); const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
@ -142,10 +126,10 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed ); if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true; if( connected ) queue = true;
} }
if( !queue ) return ret; if( !queue ) return;
#endif #endif
if( ret ) if( acquired )
{ {
auto item = Profiler::QueueSerial(); auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain ); MemWrite( &item->hdr.type, QueueType::LockObtain );
@ -154,8 +138,6 @@ public:
MemWrite( &item->lockObtain.time, Profiler::GetTime() ); MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish(); Profiler::QueueSerialFinish();
} }
return ret;
} }
tracy_force_inline void Mark( const SourceLocationData* srcloc ) tracy_force_inline void Mark( const SourceLocationData* srcloc )
@ -180,7 +162,6 @@ public:
} }
private: private:
T m_lockable;
uint32_t m_id; uint32_t m_id;
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
@ -189,12 +170,53 @@ private:
#endif #endif
}; };
template<class T> template<class T>
class SharedLockable class Lockable
{ {
public: public:
tracy_force_inline SharedLockable( const SourceLocationData* srcloc ) tracy_force_inline Lockable( const SourceLocationData* srcloc )
: m_ctx( srcloc )
{
}
Lockable( const Lockable& ) = delete;
Lockable& operator=( const Lockable& ) = delete;
tracy_force_inline void lock()
{
const auto runAfter = m_ctx.BeforeLock();
m_lockable.lock();
if( runAfter ) m_ctx.AfterLock();
}
tracy_force_inline void unlock()
{
m_lockable.unlock();
m_ctx.AfterUnlock();
}
tracy_force_inline bool try_lock()
{
const auto acquired = m_lockable.try_lock();
m_ctx.AfterTryLock( acquired );
return acquired;
}
tracy_force_inline void Mark( const SourceLocationData* srcloc )
{
m_ctx.Mark( srcloc );
}
private:
T m_lockable;
LockableCtx m_ctx;
};
class SharedLockableCtx
{
public:
tracy_force_inline SharedLockableCtx( const SourceLocationData* srcloc )
: m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) ) : m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
, m_lockCount( 0 ) , m_lockCount( 0 )
@ -220,10 +242,10 @@ public:
tail.store( magic + 1, std::memory_order_release ); tail.store( magic + 1, std::memory_order_release );
} }
SharedLockable( const SharedLockable& ) = delete; SharedLockableCtx( const SharedLockableCtx& ) = delete;
SharedLockable& operator=( const SharedLockable& ) = delete; SharedLockableCtx& operator=( const SharedLockableCtx& ) = delete;
~SharedLockable() tracy_force_inline ~SharedLockableCtx()
{ {
Magic magic; Magic magic;
auto token = GetToken(); auto token = GetToken();
@ -241,7 +263,7 @@ public:
tail.store( magic + 1, std::memory_order_release ); tail.store( magic + 1, std::memory_order_release );
} }
tracy_force_inline void lock() tracy_force_inline bool BeforeLock()
{ {
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
bool queue = false; bool queue = false;
@ -253,40 +275,31 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed ); if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true; if( connected ) queue = true;
} }
if( !queue ) if( !queue ) return false;
{
m_lockable.lock();
return;
}
#endif #endif
const auto thread = GetThreadHandle();
{ auto item = Profiler::QueueSerial();
auto item = Profiler::QueueSerial(); MemWrite( &item->hdr.type, QueueType::LockWait );
MemWrite( &item->hdr.type, QueueType::LockWait ); MemWrite( &item->lockWait.thread, GetThreadHandle() );
MemWrite( &item->lockWait.thread, thread ); MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.id, m_id ); MemWrite( &item->lockWait.time, Profiler::GetTime() );
MemWrite( &item->lockWait.time, Profiler::GetTime() ); MemWrite( &item->lockWait.type, LockType::SharedLockable );
MemWrite( &item->lockWait.type, LockType::SharedLockable ); Profiler::QueueSerialFinish();
Profiler::QueueSerialFinish(); return true;
}
m_lockable.lock();
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, thread );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
} }
tracy_force_inline void unlock() tracy_force_inline void AfterLock()
{ {
m_lockable.unlock(); auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, GetThreadHandle() );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
tracy_force_inline void AfterUnlock()
{
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
m_lockCount.fetch_sub( 1, std::memory_order_relaxed ); m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !m_active.load( std::memory_order_relaxed ) ) return; if( !m_active.load( std::memory_order_relaxed ) ) return;
@ -305,12 +318,10 @@ public:
Profiler::QueueSerialFinish(); Profiler::QueueSerialFinish();
} }
tracy_force_inline bool try_lock() tracy_force_inline void AfterTryLock( bool acquired )
{ {
const auto ret = m_lockable.try_lock();
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
if( !ret ) return ret; if( !acquired ) return;
bool queue = false; bool queue = false;
const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed ); const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
@ -321,10 +332,10 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed ); if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true; if( connected ) queue = true;
} }
if( !queue ) return ret; if( !queue ) return;
#endif #endif
if( ret ) if( acquired )
{ {
auto item = Profiler::QueueSerial(); auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain ); MemWrite( &item->hdr.type, QueueType::LockObtain );
@ -333,11 +344,9 @@ public:
MemWrite( &item->lockObtain.time, Profiler::GetTime() ); MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish(); Profiler::QueueSerialFinish();
} }
return ret;
} }
tracy_force_inline void lock_shared() tracy_force_inline bool BeforeLockShared()
{ {
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
bool queue = false; bool queue = false;
@ -349,40 +358,31 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed ); if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true; if( connected ) queue = true;
} }
if( !queue ) if( !queue ) return false;
{
m_lockable.lock_shared();
return;
}
#endif #endif
const auto thread = GetThreadHandle();
{ auto item = Profiler::QueueSerial();
auto item = Profiler::QueueSerial(); MemWrite( &item->hdr.type, QueueType::LockSharedWait );
MemWrite( &item->hdr.type, QueueType::LockSharedWait ); MemWrite( &item->lockWait.thread, GetThreadHandle() );
MemWrite( &item->lockWait.thread, thread ); MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.id, m_id ); MemWrite( &item->lockWait.time, Profiler::GetTime() );
MemWrite( &item->lockWait.time, Profiler::GetTime() ); MemWrite( &item->lockWait.type, LockType::SharedLockable );
MemWrite( &item->lockWait.type, LockType::SharedLockable ); Profiler::QueueSerialFinish();
Profiler::QueueSerialFinish(); return true;
}
m_lockable.lock_shared();
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
MemWrite( &item->lockObtain.thread, thread );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
} }
tracy_force_inline void unlock_shared() tracy_force_inline void AfterLockShared()
{ {
m_lockable.unlock_shared(); auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
MemWrite( &item->lockObtain.thread, GetThreadHandle() );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
tracy_force_inline void AfterUnlockShared()
{
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
m_lockCount.fetch_sub( 1, std::memory_order_relaxed ); m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !m_active.load( std::memory_order_relaxed ) ) return; if( !m_active.load( std::memory_order_relaxed ) ) return;
@ -401,12 +401,10 @@ public:
Profiler::QueueSerialFinish(); Profiler::QueueSerialFinish();
} }
tracy_force_inline bool try_lock_shared() tracy_force_inline void AfterTryLockShared( bool acquired )
{ {
const auto ret = m_lockable.try_lock_shared();
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
if( !ret ) return ret; if( !acquired ) return;
bool queue = false; bool queue = false;
const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed ); const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
@ -417,10 +415,10 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed ); if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true; if( connected ) queue = true;
} }
if( !queue ) return ret; if( !queue ) return;
#endif #endif
if( ret ) if( acquired )
{ {
auto item = Profiler::QueueSerial(); auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedObtain ); MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
@ -429,8 +427,6 @@ public:
MemWrite( &item->lockObtain.time, Profiler::GetTime() ); MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish(); Profiler::QueueSerialFinish();
} }
return ret;
} }
tracy_force_inline void Mark( const SourceLocationData* srcloc ) tracy_force_inline void Mark( const SourceLocationData* srcloc )
@ -455,7 +451,6 @@ public:
} }
private: private:
T m_lockable;
uint32_t m_id; uint32_t m_id;
#ifdef TRACY_ON_DEMAND #ifdef TRACY_ON_DEMAND
@ -464,6 +459,68 @@ private:
#endif #endif
}; };
template<class T>
class SharedLockable
{
public:
tracy_force_inline SharedLockable( const SourceLocationData* srcloc )
: m_ctx( srcloc )
{
}
SharedLockable( const SharedLockable& ) = delete;
SharedLockable& operator=( const SharedLockable& ) = delete;
tracy_force_inline void lock()
{
const auto runAfter = m_ctx.BeforeLock();
m_lockable.lock();
if( runAfter ) m_ctx.AfterLock();
}
tracy_force_inline void unlock()
{
m_lockable.unlock();
m_ctx.AfterUnlock();
}
tracy_force_inline bool try_lock()
{
const auto acquired = m_lockable.try_lock();
m_ctx.AfterTryLock( acquired );
return acquired;
}
tracy_force_inline void lock_shared()
{
const auto runAfter = m_ctx.BeforeLockShared();
m_lockable.lock_shared();
if( runAfter ) m_ctx.AfterLockShared();
}
tracy_force_inline void unlock_shared()
{
m_lockable.unlock_shared();
m_ctx.AfterUnlockShared();
}
tracy_force_inline bool try_lock_shared()
{
const auto acquired = m_lockable.try_lock_shared();
m_ctx.AfterTryLockShared( acquired );
return acquired;
}
tracy_force_inline void Mark( const SourceLocationData* srcloc )
{
m_ctx.Mark( srcloc );
}
private:
T m_lockable;
SharedLockableCtx m_ctx;
};
}; };