From 31dbfef97d86b8f425f2c0e9a70d67260fe133ac Mon Sep 17 00:00:00 2001 From: MaximeCoutantSonos Date: Mon, 8 Jun 2026 15:19:00 +0200 Subject: [PATCH 1/3] Added C shared lock to C-API --- public/client/TracyProfiler.cpp | 158 ++++++++++++++++++++++++++++++++ public/tracy/TracyC.h | 44 +++++++++ 2 files changed, 202 insertions(+) diff --git a/public/client/TracyProfiler.cpp b/public/client/TracyProfiler.cpp index 8bd8e182..8a050bd8 100644 --- a/public/client/TracyProfiler.cpp +++ b/public/client/TracyProfiler.cpp @@ -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( 0 ); + new(&lockdata->m_base.m_active) std::atomic( false ); +#endif + assert( lockdata->m_base.m_id != (std::numeric_limits::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(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(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( tracy::GetProfiler().IsConnected() ); diff --git a/public/tracy/TracyC.h b/public/tracy/TracyC.h index decbbab9..6c4e60cf 100644 --- a/public/tracy/TracyC.h +++ b/public/tracy/TracyC.h @@ -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 TracyCSharedLockAnnonce( 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 ); From 796050ac1ef4e626b51d99f7e1134b8e3ac30006 Mon Sep 17 00:00:00 2001 From: MaximeCoutantSonos Date: Mon, 8 Jun 2026 15:52:54 +0200 Subject: [PATCH 2/3] Added documentation for the shared lock C API --- manual/tracy.tex | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/manual/tracy.tex b/manual/tracy.tex index e1310ae9..72588f0a 100644 --- a/manual/tracy.tex +++ b/manual/tracy.tex @@ -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{TracyCSharedLockAnnonce(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} From 2f143491eb613d6c2f2c20823d5146f7d2376c95 Mon Sep 17 00:00:00 2001 From: MaximeCoutantSonos Date: Mon, 8 Jun 2026 16:07:06 +0200 Subject: [PATCH 3/3] Fixed typo in grammar --- manual/tracy.tex | 2 +- public/tracy/TracyC.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/tracy.tex b/manual/tracy.tex index 72588f0a..e1c57afb 100644 --- a/manual/tracy.tex +++ b/manual/tracy.tex @@ -2275,7 +2275,7 @@ You can optionally mark the location of where the lock is held by using the \tex Similarly, you can use the following macros to mark a shared lock using the C API: \begin{itemize} -\item \texttt{TracyCSharedLockAnnonce(lock\_ctx)} +\item \texttt{TracyCSharedLockAnnounce(lock\_ctx)} \item \texttt{TracyCSharedLockTerminate(lock\_ctx)} \item \texttt{TracyCSharedLockBeforeLock(lock\_ctx)} \item \texttt{TracyCSharedLockAfterLock(lock\_ctx)} diff --git a/public/tracy/TracyC.h b/public/tracy/TracyC.h index 6c4e60cf..1864c197 100644 --- a/public/tracy/TracyC.h +++ b/public/tracy/TracyC.h @@ -407,7 +407,7 @@ TRACY_API void ___tracy_custom_name_shared_lockable_ctx( struct __tracy_shared_l #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 TracyCSharedLockAnnonce( 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 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 );