Merge pull request #1395 from MaximeCoutantSonos/master

Add support for Shared Locks in the C API
This commit is contained in:
Bartosz Taudul
2026-06-08 17:34:17 +02:00
committed by GitHub
3 changed files with 227 additions and 0 deletions

View File

@@ -2273,6 +2273,31 @@ TracyCLockAfterUnlock(tracy_lock_ctx);
You can optionally mark the location of where the lock is held by using the \texttt{TracyCLockMark} macro, this should be done after acquiring the lock.
Similarly, you can use the following macros to mark a shared lock using the C API:
\begin{itemize}
\item \texttt{TracyCSharedLockAnnounce(lock\_ctx)}
\item \texttt{TracyCSharedLockTerminate(lock\_ctx)}
\item \texttt{TracyCSharedLockBeforeLock(lock\_ctx)}
\item \texttt{TracyCSharedLockAfterLock(lock\_ctx)}
\item \texttt{TracyCSharedLockAfterUnlock(lock\_ctx)}
\item \texttt{TracyCSharedLockAfterTryLock(lock\_ctx, acquired)}
\item \texttt{TracyCSharedLockBeforeSharedLock(lock\_ctx)}
\item \texttt{TracyCSharedLockAfterSharedLock(lock\_ctx)}
\item \texttt{TracyCSharedLockAfterSharedUnlock(lock\_ctx)}
\item \texttt{TracyCSharedLockAfterTrySharedLock(lock\_ctx, acquired)}
\item \texttt{TracyCSharedLockMark(lock\_ctx)}
\item \texttt{TracyCSharedLockCustomName(lock\_ctx, name, size)}
\end{itemize}
A shared lock context has to be defined next to the shared lock that it will be marking:
\begin{lstlisting}
TracyCSharedLockCtx tracy_shared_lock_ctx;
HANDLE shared_lock;
\end{lstlisting}
The same rules apply to shared locks as to regular locks, but you need to use the shared lock macros instead.
Lock implementations in classes \texttt{Lockable} and \texttt{SharedLockable} show how to properly perform context handling.
\subsubsection{Memory profiling}
\label{cmemoryprofiling}

View File

@@ -5167,6 +5167,164 @@ TRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_contex
tracy::Profiler::QueueSerialFinish();
}
struct __tracy_shared_lockable_context_data {
struct __tracy_lockable_context_data m_base;
};
TRACY_API struct __tracy_shared_lockable_context_data* ___tracy_announce_shared_lockable_ctx( const struct ___tracy_source_location_data* srcloc )
{
struct __tracy_shared_lockable_context_data *lockdata = (__tracy_shared_lockable_context_data*)tracy::tracy_malloc( sizeof( __tracy_shared_lockable_context_data ) );
lockdata->m_base.m_id = tracy::GetLockCounter().fetch_add( 1, std::memory_order_relaxed );
#ifdef TRACY_ON_DEMAND
new(&lockdata->m_base.m_lockCount) std::atomic<uint32_t>( 0 );
new(&lockdata->m_base.m_active) std::atomic<bool>( false );
#endif
assert( lockdata->m_base.m_id != (std::numeric_limits<uint32_t>::max)() );
auto item = tracy::Profiler::QueueSerial();
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockAnnounce );
tracy::MemWrite( &item->lockAnnounce.id, lockdata->m_base.m_id );
tracy::MemWrite( &item->lockAnnounce.time, tracy::Profiler::GetTime() );
tracy::MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
tracy::MemWrite( &item->lockAnnounce.type, tracy::LockType::SharedLockable );
#ifdef TRACY_ON_DEMAND
tracy::GetProfiler().DeferItem( *item );
#endif
tracy::Profiler::QueueSerialFinish();
return lockdata;
}
TRACY_API void ___tracy_terminate_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
auto item = tracy::Profiler::QueueSerial();
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockTerminate );
tracy::MemWrite( &item->lockTerminate.id, lockdata->m_base.m_id );
tracy::MemWrite( &item->lockTerminate.time, tracy::Profiler::GetTime() );
#ifdef TRACY_ON_DEMAND
tracy::GetProfiler().DeferItem( *item );
#endif
tracy::Profiler::QueueSerialFinish();
#ifdef TRACY_ON_DEMAND
lockdata->m_base.m_lockCount.~atomic();
lockdata->m_base.m_active.~atomic();
#endif
tracy::tracy_free((void*)lockdata);
}
TRACY_API int32_t ___tracy_before_lock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
return ___tracy_before_lock_lockable_ctx( &lockdata->m_base );
}
TRACY_API void ___tracy_after_lock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
___tracy_after_lock_lockable_ctx( &lockdata->m_base );
}
TRACY_API void ___tracy_after_unlock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
___tracy_after_unlock_lockable_ctx( &lockdata->m_base );
}
TRACY_API void ___tracy_after_try_lock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, int32_t acquired )
{
___tracy_after_try_lock_lockable_ctx( &lockdata->m_base, acquired );
}
TRACY_API int32_t ___tracy_before_lock_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
#ifdef TRACY_ON_DEMAND
bool queue = false;
const auto locks = lockdata->m_base.m_lockCount.fetch_add( 1, std::memory_order_relaxed );
const auto active = lockdata->m_base.m_active.load( std::memory_order_relaxed );
if( locks == 0 || active )
{
const bool connected = tracy::GetProfiler().IsConnected();
if( active != connected ) lockdata->m_base.m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return static_cast<int32_t>(false);
#endif
auto item = tracy::Profiler::QueueSerial();
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockSharedWait );
tracy::MemWrite( &item->lockWait.thread, tracy::GetThreadHandle() );
tracy::MemWrite( &item->lockWait.id, lockdata->m_base.m_id );
tracy::MemWrite( &item->lockWait.time, tracy::Profiler::GetTime() );
tracy::Profiler::QueueSerialFinish();
return static_cast<int32_t>(true);
}
TRACY_API void ___tracy_after_locked_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
auto item = tracy::Profiler::QueueSerial();
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockSharedObtain );
tracy::MemWrite( &item->lockObtain.thread, tracy::GetThreadHandle() );
tracy::MemWrite( &item->lockObtain.id, lockdata->m_base.m_id );
tracy::MemWrite( &item->lockObtain.time, tracy::Profiler::GetTime() );
tracy::Profiler::QueueSerialFinish();
}
TRACY_API void ___tracy_after_unlock_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata )
{
#ifdef TRACY_ON_DEMAND
lockdata->m_base.m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !lockdata->m_base.m_active.load( std::memory_order_relaxed ) ) return;
if( !tracy::GetProfiler().IsConnected() )
{
lockdata->m_base.m_active.store( false, std::memory_order_relaxed );
return;
}
#endif
auto item = tracy::Profiler::QueueSerial();
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockSharedRelease );
tracy::MemWrite( &item->lockReleaseShared.thread, tracy::GetThreadHandle() );
tracy::MemWrite( &item->lockReleaseShared.id, lockdata->m_base.m_id );
tracy::MemWrite( &item->lockReleaseShared.time, tracy::Profiler::GetTime() );
tracy::Profiler::QueueSerialFinish();
}
TRACY_API void ___tracy_after_try_lock_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, int32_t acquired )
{
#ifdef TRACY_ON_DEMAND
if( !acquired ) return;
bool queue = false;
const auto locks = lockdata->m_base.m_lockCount.fetch_add( 1, std::memory_order_relaxed );
const auto active = lockdata->m_base.m_active.load( std::memory_order_relaxed );
if( locks == 0 || active )
{
const bool connected = tracy::GetProfiler().IsConnected();
if( active != connected ) lockdata->m_base.m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return;
#endif
if( acquired )
{
auto item = tracy::Profiler::QueueSerial();
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockObtain );
tracy::MemWrite( &item->lockObtain.thread, tracy::GetThreadHandle() );
tracy::MemWrite( &item->lockObtain.id, lockdata->m_base.m_id );
tracy::MemWrite( &item->lockObtain.time, tracy::Profiler::GetTime() );
tracy::Profiler::QueueSerialFinish();
}
}
TRACY_API void ___tracy_mark_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, const struct ___tracy_source_location_data* srcloc )
{
___tracy_mark_lockable_ctx( &lockdata->m_base, srcloc );
}
TRACY_API void ___tracy_custom_name_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, const char* name, size_t nameSz )
{
___tracy_custom_name_lockable_ctx( &lockdata->m_base, name, nameSz );
}
TRACY_API int32_t ___tracy_connected( void )
{
return static_cast<int32_t>( tracy::GetProfiler().IsConnected() );

View File

@@ -49,6 +49,7 @@ TRACY_API void ___tracy_set_thread_name( const char* name );
typedef const void* TracyCZoneCtx;
typedef const void* TracyCLockCtx;
typedef const void* TracyCSharedLockCtx;
#define TracyCZone(c,x)
#define TracyCZoneN(c,x,y)
@@ -121,6 +122,20 @@ typedef const void* TracyCLockCtx;
#define TracyCLockMark(l)
#define TracyCLockCustomName(l,x,y)
#define TracyCSharedLockCtx(l)
#define TracyCSharedLockAnnonce(l)
#define TracyCSharedLockTerminate(l)
#define TracyCSharedLockBeforeLock(l)
#define TracyCSharedLockAfterLock(l)
#define TracyCSharedLockAfterUnlock(l)
#define TracyCSharedLockAfterTryLock(l,x)
#define TracyCSharedLockBeforeSharedLock(l)
#define TracyCSharedLockAfterSharedLock(l)
#define TracyCSharedLockAfterSharedUnlock(l)
#define TracyCSharedLockAfterTrySharedLock(l,x)
#define TracyCSharedLockMark(l)
#define TracyCSharedLockCustomName(l,x,y)
#define TracyCIsConnected 0
#define TracyCIsStarted 0
@@ -207,12 +222,14 @@ struct ___tracy_gpu_time_sync_data {
};
struct __tracy_lockable_context_data;
struct __tracy_shared_lockable_context_data;
// Some containers don't support storing const types.
// This struct, as visible to user, is immutable, so treat it as if const was declared here.
typedef /*const*/ struct ___tracy_c_zone_context TracyCZoneCtx;
typedef struct __tracy_lockable_context_data* TracyCLockCtx;
typedef struct __tracy_shared_lockable_context_data* TracyCSharedLockCtx;
#ifdef TRACY_MANUAL_LIFETIME
TRACY_API void ___tracy_startup_profiler(void);
@@ -367,6 +384,20 @@ TRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_con
TRACY_API void ___tracy_mark_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const struct ___tracy_source_location_data* srcloc );
TRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const char* name, size_t nameSz );
TRACY_API struct __tracy_shared_lockable_context_data* ___tracy_announce_shared_lockable_ctx( const struct ___tracy_source_location_data* srcloc );
TRACY_API void ___tracy_terminate_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API int32_t ___tracy_before_lock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API void ___tracy_after_lock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API void ___tracy_after_unlock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API void ___tracy_after_try_lock_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, int32_t acquired );
TRACY_API int32_t ___tracy_before_lock_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API void ___tracy_after_locked_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API void ___tracy_after_unlock_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata );
TRACY_API void ___tracy_after_try_lock_shared_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, int32_t acquired );
TRACY_API void ___tracy_mark_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, const struct ___tracy_source_location_data* srcloc );
TRACY_API void ___tracy_custom_name_shared_lockable_ctx( struct __tracy_shared_lockable_context_data* lockdata, const char* name, size_t nameSz );
#define TracyCLockAnnounce( lock ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__, TracyFile, (uint32_t)TracyLine, 0 }; lock = ___tracy_announce_lockable_ctx( &TracyConcat(__tracy_source_location,TracyLine) );
#define TracyCLockTerminate( lock ) ___tracy_terminate_lockable_ctx( lock );
#define TracyCLockBeforeLock( lock ) ___tracy_before_lock_lockable_ctx( lock );
@@ -376,6 +407,19 @@ TRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_contex
#define TracyCLockMark( lock ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__, TracyFile, (uint32_t)TracyLine, 0 }; ___tracy_mark_lockable_ctx( lock, &TracyConcat(__tracy_source_location,TracyLine) );
#define TracyCLockCustomName( lock, name, nameSz ) ___tracy_custom_name_lockable_ctx( lock, name, nameSz );
#define TracyCSharedLockAnnounce( lock ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__, TracyFile, (uint32_t)TracyLine, 0 }; lock = ___tracy_announce_shared_lockable_ctx( &TracyConcat(__tracy_source_location,TracyLine) );
#define TracyCSharedLockTerminate( lock ) ___tracy_terminate_shared_lockable_ctx( lock );
#define TracyCSharedLockBeforeLock( lock ) ___tracy_before_lock_shared_lockable_ctx( lock );
#define TracyCSharedLockAfterLock( lock ) ___tracy_after_lock_shared_lockable_ctx( lock );
#define TracyCSharedLockAfterUnlock( lock ) ___tracy_after_unlock_shared_lockable_ctx( lock );
#define TracyCSharedLockAfterTryLock( lock, acquired ) ___tracy_after_try_lock_shared_lockable_ctx( lock, acquired );
#define TracyCSharedLockBeforeSharedLock( lock ) ___tracy_before_lock_shared_shared_lockable_ctx( lock );
#define TracyCSharedLockAfterSharedLock( lock ) ___tracy_after_locked_shared_shared_lockable_ctx( lock );
#define TracyCSharedLockAfterSharedUnlock( lock ) ___tracy_after_unlock_shared_shared_lockable_ctx( lock );
#define TracyCSharedLockAfterTrySharedLock( lock, acquired ) ___tracy_after_try_lock_shared_shared_lockable_ctx( lock, acquired );
#define TracyCSharedLockMark( lock ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__, TracyFile, (uint32_t)TracyLine, 0 }; ___tracy_mark_shared_lockable_ctx( lock, &TracyConcat(__tracy_source_location,TracyLine) );
#define TracyCSharedLockCustomName( lock, name, nameSz ) ___tracy_custom_name_shared_lockable_ctx( lock, name, nameSz );
#define TracyCIsConnected ___tracy_connected()
TRACY_API int ___tracy_begin_sampling_profiling( void );