mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-22 14:44:34 +00:00
commit
4e349dd283
@ -2010,6 +2010,55 @@ However, the validation comes with a performance cost, which you may not want to
|
||||
|
||||
There is no explicit support for transient zones (section~\ref{transientzones}) in the C API macros. However, this functionality can be implemented by following instructions outlined in section~\ref{capibindings}.
|
||||
|
||||
\subsubsection{Lock markup}
|
||||
|
||||
Marking locks in the C API is done with the following macros:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{TracyCLockAnnounce(lock\_ctx)}
|
||||
\item \texttt{TracyCLockTerminate(lock\_ctx)}
|
||||
\item \texttt{TracyCLockBeforeLock(lock\_ctx)}
|
||||
\item \texttt{TracyCLockAfterLock(lock\_ctx)}
|
||||
\item \texttt{TracyCLockAfterUnlock(lock\_ctx)}
|
||||
\item \texttt{TracyCLockAfterTryLock(lock\_ctx, acquired)}
|
||||
\item \texttt{TracyCLockMark(lock\_ctx)}
|
||||
\item \texttt{TracyCLockCustomName(lock\_ctx, name, size)}
|
||||
\end{itemize}
|
||||
|
||||
Additionally a lock context has to be defined next to the lock that it will be marking:
|
||||
|
||||
\begin{lstlisting}
|
||||
TracyCLockCtx tracy_lock_ctx;
|
||||
HANDLE lock;
|
||||
\end{lstlisting}
|
||||
|
||||
To initialize the lock context use \texttt{TracyCLockAnnounce}, this should be done when the lock you are marking is initialized/created. When the lock is destroyed use \texttt{TracyCLockTerminate}, this will free the lock context. You can use the \texttt{TracyCLockCustomName} macro to name a lock.
|
||||
|
||||
You must markup both before and after acquiring a lock:
|
||||
|
||||
\begin{lstlisting}
|
||||
TracyCLockBeforeLock(tracy_lock_ctx);
|
||||
WaitForSingleObject(lock, INFINITE);
|
||||
TracyCLockAfterLock(tracy_lock_ctx);
|
||||
\end{lstlisting}
|
||||
|
||||
If acquiring the lock may fail, you should instead use the \texttt{TracyCLockAfterTryLock} macro:
|
||||
|
||||
\begin{lstlisting}
|
||||
TracyCLockBeforeLock(tracy_lock_ctx);
|
||||
int acquired = WaitForSingleObject(lock, 200) == WAIT_OBJECT_0;
|
||||
TracyCLockAfterTryLock(tracy_lock_ctx, acquired);
|
||||
\end{lstlisting}
|
||||
|
||||
After you release the lock use the \texttt{TracyCLockAfterUnlock} macro:
|
||||
|
||||
\begin{lstlisting}
|
||||
ReleaseMutex(lock);
|
||||
TracyCLockAfterUnlock(tracy_lock_ctx);
|
||||
\end{lstlisting}
|
||||
|
||||
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.
|
||||
|
||||
\subsubsection{Memory profiling}
|
||||
|
||||
Use the following macros in your implementations of \texttt{malloc} and \texttt{free}:
|
||||
|
@ -4505,6 +4505,175 @@ TRACY_API void ___tracy_emit_gpu_time_sync_serial( const struct ___tracy_gpu_tim
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
}
|
||||
|
||||
struct __tracy_lockable_context_data
|
||||
{
|
||||
uint32_t m_id;
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
std::atomic<uint32_t> m_lockCount;
|
||||
std::atomic<bool> m_active;
|
||||
#endif
|
||||
};
|
||||
|
||||
TRACY_API struct __tracy_lockable_context_data* ___tracy_announce_lockable_ctx( const struct ___tracy_source_location_data* srcloc )
|
||||
{
|
||||
struct __tracy_lockable_context_data *lockdata = (__tracy_lockable_context_data*)tracy::tracy_malloc( sizeof( __tracy_lockable_context_data ) );
|
||||
lockdata->m_id =tracy:: GetLockCounter().fetch_add( 1, std::memory_order_relaxed );
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
new(&lockdata->m_lockCount) std::atomic<uint32_t>( 0 );
|
||||
new(&lockdata->m_active) std::atomic<bool>( false );
|
||||
#endif
|
||||
assert( lockdata->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_id );
|
||||
tracy::MemWrite( &item->lockAnnounce.time, tracy::Profiler::GetTime() );
|
||||
tracy::MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
|
||||
tracy::MemWrite( &item->lockAnnounce.type, tracy::LockType::Lockable );
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
tracy::GetProfiler().DeferItem( *item );
|
||||
#endif
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
|
||||
return lockdata;
|
||||
}
|
||||
|
||||
TRACY_API void ___tracy_terminate_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
|
||||
{
|
||||
auto item = tracy::Profiler::QueueSerial();
|
||||
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockTerminate );
|
||||
tracy::MemWrite( &item->lockTerminate.id, lockdata->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_lockCount.~atomic();
|
||||
lockdata->m_active.~atomic();
|
||||
#endif
|
||||
tracy::tracy_free((void*)lockdata);
|
||||
}
|
||||
|
||||
TRACY_API int ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
|
||||
{
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
bool queue = false;
|
||||
const auto locks = lockdata->m_lockCount.fetch_add( 1, std::memory_order_relaxed );
|
||||
const auto active = lockdata->m_active.load( std::memory_order_relaxed );
|
||||
if( locks == 0 || active )
|
||||
{
|
||||
const bool connected = tracy::GetProfiler().IsConnected();
|
||||
if( active != connected ) lockdata->m_active.store( connected, std::memory_order_relaxed );
|
||||
if( connected ) queue = true;
|
||||
}
|
||||
if( !queue ) return false;
|
||||
#endif
|
||||
|
||||
auto item = tracy::Profiler::QueueSerial();
|
||||
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockWait );
|
||||
tracy::MemWrite( &item->lockWait.thread, tracy::GetThreadHandle() );
|
||||
tracy::MemWrite( &item->lockWait.id, lockdata->m_id );
|
||||
tracy::MemWrite( &item->lockWait.time, tracy::Profiler::GetTime() );
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
return true;
|
||||
}
|
||||
|
||||
TRACY_API void ___tracy_after_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
|
||||
{
|
||||
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_id );
|
||||
tracy::MemWrite( &item->lockObtain.time, tracy::Profiler::GetTime() );
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
}
|
||||
|
||||
TRACY_API void ___tracy_after_unlock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
|
||||
{
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
lockdata->m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
|
||||
if( !lockdata->m_active.load( std::memory_order_relaxed ) ) return;
|
||||
if( !tracy::GetProfiler().IsConnected() )
|
||||
{
|
||||
lockdata->m_active.store( false, std::memory_order_relaxed );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto item = tracy::Profiler::QueueSerial();
|
||||
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockRelease );
|
||||
tracy::MemWrite( &item->lockRelease.id, lockdata->m_id );
|
||||
tracy::MemWrite( &item->lockRelease.time, tracy::Profiler::GetTime() );
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
}
|
||||
|
||||
TRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata, int acquired )
|
||||
{
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
if( !acquired ) return;
|
||||
|
||||
bool queue = false;
|
||||
const auto locks = lockdata->m_lockCount.fetch_add( 1, std::memory_order_relaxed );
|
||||
const auto active = lockdata->m_active.load( std::memory_order_relaxed );
|
||||
if( locks == 0 || active )
|
||||
{
|
||||
const bool connected = tracy::GetProfiler().IsConnected();
|
||||
if( active != connected ) lockdata->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_id );
|
||||
tracy::MemWrite( &item->lockObtain.time, tracy::Profiler::GetTime() );
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
}
|
||||
}
|
||||
|
||||
TRACY_API void ___tracy_mark_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const struct ___tracy_source_location_data* srcloc )
|
||||
{
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
const auto active = lockdata->m_active.load( std::memory_order_relaxed );
|
||||
if( !active ) return;
|
||||
const auto connected = tracy::GetProfiler().IsConnected();
|
||||
if( !connected )
|
||||
{
|
||||
if( active ) lockdata->m_active.store( false, std::memory_order_relaxed );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto item = tracy::Profiler::QueueSerial();
|
||||
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockMark );
|
||||
tracy::MemWrite( &item->lockMark.thread, tracy::GetThreadHandle() );
|
||||
tracy::MemWrite( &item->lockMark.id, lockdata->m_id );
|
||||
tracy::MemWrite( &item->lockMark.srcloc, (uint64_t)srcloc );
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
}
|
||||
|
||||
TRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const char* name, size_t nameSz )
|
||||
{
|
||||
assert( nameSz < (std::numeric_limits<uint16_t>::max)() );
|
||||
auto ptr = (char*)tracy::tracy_malloc( nameSz );
|
||||
memcpy( ptr, name, nameSz );
|
||||
auto item = tracy::Profiler::QueueSerial();
|
||||
tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockName );
|
||||
tracy::MemWrite( &item->lockNameFat.id, lockdata->m_id );
|
||||
tracy::MemWrite( &item->lockNameFat.name, (uint64_t)ptr );
|
||||
tracy::MemWrite( &item->lockNameFat.size, (uint16_t)nameSz );
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
tracy::GetProfiler().DeferItem( *item );
|
||||
#endif
|
||||
tracy::Profiler::QueueSerialFinish();
|
||||
}
|
||||
|
||||
TRACY_API int ___tracy_connected( void )
|
||||
{
|
||||
return tracy::GetProfiler().IsConnected();
|
||||
|
@ -39,6 +39,8 @@ TRACY_API void ___tracy_set_thread_name( const char* name );
|
||||
|
||||
typedef const void* TracyCZoneCtx;
|
||||
|
||||
typedef const void* TracyCLockCtx;
|
||||
|
||||
#define TracyCZone(c,x)
|
||||
#define TracyCZoneN(c,x,y)
|
||||
#define TracyCZoneC(c,x,y)
|
||||
@ -96,6 +98,16 @@ typedef const void* TracyCZoneCtx;
|
||||
#define TracyCMessageCS(x,y,z,w)
|
||||
#define TracyCMessageLCS(x,y,z)
|
||||
|
||||
#define TracyCLockCtx(l)
|
||||
#define TracyCLockAnnounce(l)
|
||||
#define TracyCLockTerminate(l)
|
||||
#define TracyCLockBeforeLock(l)
|
||||
#define TracyCLockAfterLock(l)
|
||||
#define TracyCLockAfterUnlock(l)
|
||||
#define TracyCLockAfterTryLock(l,x)
|
||||
#define TracyCLockMark(l)
|
||||
#define TracyCLockCustomName(l,x,y)
|
||||
|
||||
#define TracyCIsConnected 0
|
||||
#define TracyCIsStarted 0
|
||||
|
||||
@ -178,10 +190,13 @@ struct ___tracy_gpu_time_sync_data {
|
||||
uint8_t context;
|
||||
};
|
||||
|
||||
struct __tracy_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;
|
||||
|
||||
#ifdef TRACY_MANUAL_LIFETIME
|
||||
TRACY_API void ___tracy_startup_profiler(void);
|
||||
@ -364,6 +379,25 @@ TRACY_API void ___tracy_emit_message_appinfo( const char* txt, size_t size );
|
||||
# define TracyCMessageLCS( txt, color, depth ) TracyCMessageLC( txt, color )
|
||||
#endif
|
||||
|
||||
|
||||
TRACY_API struct __tracy_lockable_context_data* ___tracy_announce_lockable_ctx( const struct ___tracy_source_location_data* srcloc );
|
||||
TRACY_API void ___tracy_terminate_lockable_ctx( struct __tracy_lockable_context_data* lockdata );
|
||||
TRACY_API int ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata );
|
||||
TRACY_API void ___tracy_after_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata );
|
||||
TRACY_API void ___tracy_after_unlock_lockable_ctx( struct __tracy_lockable_context_data* lockdata );
|
||||
TRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata, int acquired );
|
||||
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 );
|
||||
|
||||
#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 );
|
||||
#define TracyCLockAfterLock( lock ) ___tracy_after_lock_lockable_ctx( lock );
|
||||
#define TracyCLockAfterUnlock( lock ) ___tracy_after_unlock_lockable_ctx( lock );
|
||||
#define TracyCLockAfterTryLock( lock, acquired ) ___tracy_after_try_lock_lockable_ctx( lock, acquired );
|
||||
#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 TracyCIsConnected ___tracy_connected()
|
||||
|
||||
#ifdef TRACY_FIBERS
|
||||
|
Loading…
Reference in New Issue
Block a user