1 #ifndef __TRACYPROFILER_HPP__
2 #define __TRACYPROFILER_HPP__
14 #include "../common/TracyQueue.hpp"
15 #include "../common/TracyAlign.hpp"
16 #include "../common/TracyAlloc.hpp"
17 #include "../common/TracyMutex.hpp"
18 #include "../common/TracyProtocol.hpp"
20 #if defined _WIN32 || defined __CYGWIN__
24 # include <TargetConditionals.h>
25 # include <mach/mach_time.h>
28 #if !defined TRACY_TIMER_FALLBACK && ( defined _WIN32 || defined __CYGWIN__ || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) )
29 # define TRACY_HW_TIMER
32 #if !defined TRACY_HW_TIMER
37 # define TracyConcat(x,y) TracyConcatIndirect(x,y)
39 #ifndef TracyConcatIndirect
40 # define TracyConcatIndirect(x,y) x##y
45 #if defined(TRACY_DELAYED_INIT) && defined(TRACY_MANUAL_LIFETIME)
81 #ifdef TRACY_ON_DEMAND
90 #define TracyLfqPrepare( _type ) \
91 moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \
92 auto __token = GetToken(); \
93 auto& __tail = __token->get_tail_index(); \
94 auto item = __token->enqueue_begin( __magic ); \
95 MemWrite( &item->hdr.type, _type );
97 #define TracyLfqCommit \
98 __tail.store( __magic + 1, std::memory_order_release );
100 #define TracyLfqPrepareC( _type ) \
101 tracy::moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \
102 auto __token = tracy::GetToken(); \
103 auto& __tail = __token->get_tail_index(); \
104 auto item = __token->enqueue_begin( __magic ); \
105 tracy::MemWrite( &item->hdr.type, _type );
107 #define TracyLfqCommitC \
108 __tail.store( __magic + 1, std::memory_order_release );
133 #ifdef TRACY_HW_TIMER
134 # if defined TARGET_OS_IOS && TARGET_OS_IOS == 1
135 return mach_absolute_time();
136 # elif defined _WIN32 || defined __CYGWIN__
137 # ifdef TRACY_TIMER_QPC
142 # elif defined __i386 || defined _M_IX86
144 asm volatile (
"rdtsc" :
"=a" (eax),
"=d" (edx) );
146 # elif defined __x86_64__ || defined _M_X64
148 asm volatile (
"rdtsc" :
"=a" (rax),
"=d" (rdx) );
149 return (
int64_t)(( rdx << 32 ) + rax);
151 # error "TRACY_HW_TIMER detection logic needs fixing"
154 # if defined __linux__ && defined CLOCK_MONOTONIC_RAW
156 clock_gettime( CLOCK_MONOTONIC_RAW, &ts );
157 return int64_t( ts.tv_sec ) * 1000000000ll +
int64_t( ts.tv_nsec );
159 return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).
count();
166 return m_zoneId.fetch_add( 1, std::memory_order_relaxed );
172 p.m_serialLock.lock();
173 return p.m_serialQueue.prepare_next();
179 p.m_serialLock.lock();
180 p.SendCallstackSerial( ptr );
181 return p.m_serialQueue.prepare_next();
187 p.m_serialQueue.commit_next();
188 p.m_serialLock.unlock();
194 #ifdef TRACY_ON_DEMAND
205 assert( type == QueueType::FrameMarkMsgStart || type == QueueType::FrameMarkMsgEnd );
206 #ifdef TRACY_ON_DEMAND
220 #ifdef TRACY_ON_DEMAND
221 if( !profiler.IsConnected() )
return;
223 const auto sz = size_t( w ) * size_t( h ) * 4;
225 memcpy( ptr, image, sz );
227 profiler.m_fiLock.lock();
228 auto fi = profiler.m_fiQueue.prepare_next();
230 fi->frame =
uint32_t( profiler.m_frameCount.load( std::memory_order_relaxed ) -
offset );
234 profiler.m_fiQueue.commit_next();
235 profiler.m_fiLock.unlock();
240 #ifdef TRACY_ON_DEMAND
246 MemWrite( &item->plotData.type, PlotDataType::Int );
247 MemWrite( &item->plotData.data.i, val );
253 #ifdef TRACY_ON_DEMAND
259 MemWrite( &item->plotData.type, PlotDataType::Float );
260 MemWrite( &item->plotData.data.f, val );
266 #ifdef TRACY_ON_DEMAND
272 MemWrite( &item->plotData.type, PlotDataType::Double );
273 MemWrite( &item->plotData.data.d, val );
283 #ifdef TRACY_ON_DEMAND
293 #ifdef TRACY_ON_DEMAND
302 TracyLfqPrepare( callstack == 0 ? QueueType::Message : QueueType::MessageCallstack );
304 memcpy( ptr, txt, size );
313 #ifdef TRACY_ON_DEMAND
322 TracyLfqPrepare( callstack == 0 ? QueueType::MessageLiteral : QueueType::MessageLiteralCallstack );
331 #ifdef TRACY_ON_DEMAND
340 TracyLfqPrepare( callstack == 0 ? QueueType::MessageColor : QueueType::MessageColorCallstack );
342 memcpy( ptr, txt, size );
346 MemWrite( &item->messageColorFat.g,
uint8_t( ( color >> 8 ) & 0xFF ) );
347 MemWrite( &item->messageColorFat.b,
uint8_t( ( color >> 16 ) & 0xFF ) );
354 #ifdef TRACY_ON_DEMAND
363 TracyLfqPrepare( callstack == 0 ? QueueType::MessageLiteralColor : QueueType::MessageLiteralColorCallstack );
367 MemWrite( &item->messageColorLiteral.g,
uint8_t( ( color >> 8 ) & 0xFF ) );
368 MemWrite( &item->messageColorLiteral.b,
uint8_t( ( color >> 16 ) & 0xFF ) );
377 memcpy( ptr, txt, size );
383 #ifdef TRACY_ON_DEMAND
393 #ifdef TRACY_ON_DEMAND
406 #ifdef TRACY_ON_DEMAND
419 #ifdef TRACY_HAS_CALLSTACK
421 # ifdef TRACY_ON_DEMAND
422 if( !profiler.IsConnected() )
return;
427 auto callstack = Callstack( depth );
429 profiler.m_serialLock.lock();
431 SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size );
432 profiler.m_serialLock.unlock();
441 #ifdef TRACY_HAS_CALLSTACK
443 # ifdef TRACY_ON_DEMAND
444 if( !profiler.IsConnected() )
return;
449 auto callstack = Callstack( depth );
451 profiler.m_serialLock.lock();
453 SendMemFree( QueueType::MemFreeCallstack, thread, ptr );
454 profiler.m_serialLock.unlock();
463 #ifdef TRACY_ON_DEMAND
470 SendMemAlloc( QueueType::MemAllocNamed, thread, ptr, size );
477 #ifdef TRACY_ON_DEMAND
484 SendMemFree( QueueType::MemFreeNamed, thread, ptr );
491 #ifdef TRACY_HAS_CALLSTACK
493 # ifdef TRACY_ON_DEMAND
494 if( !profiler.IsConnected() )
return;
499 auto callstack = Callstack( depth );
501 profiler.m_serialLock.lock();
504 SendMemAlloc( QueueType::MemAllocCallstackNamed, thread, ptr, size );
505 profiler.m_serialLock.unlock();
514 #ifdef TRACY_HAS_CALLSTACK
516 # ifdef TRACY_ON_DEMAND
517 if( !profiler.IsConnected() )
return;
522 auto callstack = Callstack( depth );
524 profiler.m_serialLock.lock();
527 SendMemFree( QueueType::MemFreeCallstackNamed, thread, ptr );
528 profiler.m_serialLock.unlock();
536 #ifdef TRACY_HAS_CALLSTACK
537 auto ptr = Callstack( depth );
553 #ifdef TRACY_ON_DEMAND
561 static void CutCallstack(
void* callstack,
const char* skipBefore );
580 #ifdef TRACY_ON_DEMAND
583 return m_connectionId.load( std::memory_order_acquire );
588 m_deferredLock.lock();
589 auto dst = m_deferredQueue.push_next();
590 memcpy(
dst, &item,
sizeof( item ) );
591 m_deferredLock.unlock();
623 return AllocSourceLocation( line, source, strlen(source),
function, strlen(
function), name, nameSz );
633 const auto sz32 =
uint32_t( 2 + 4 + 4 + functionSz + 1 + sourceSz + 1 + nameSz );
637 memcpy( ptr, &sz, 2 );
638 memset( ptr + 2, 0, 4 );
639 memcpy( ptr + 6, &line, 4 );
640 memcpy( ptr + 10,
function, functionSz );
641 ptr[10 + functionSz] =
'\0';
642 memcpy( ptr + 10 + functionSz + 1, source, sourceSz );
643 ptr[10 + functionSz + 1 + sourceSz] =
'\0';
646 memcpy( ptr + 10 + functionSz + 1 + sourceSz + 1, name, nameSz );
717 #ifdef TRACY_HAS_CALLSTACK
719 MemWrite( &item->hdr.type, QueueType::CallstackSerial );
727 assert( type ==
QueueType::MemAlloc || type == QueueType::MemAllocCallstack || type == QueueType::MemAllocNamed || type == QueueType::MemAllocCallstackNamed );
732 MemWrite( &item->memAlloc.thread, thread );
734 if( compile_time_condition<
sizeof( size ) == 4>::
value )
736 memcpy( &item->memAlloc.size, &size, 4 );
737 memset( &item->memAlloc.size + 4, 0, 2 );
741 assert(
sizeof( size ) == 8 );
742 memcpy( &item->memAlloc.size, &size, 4 );
743 memcpy( ((
char*)&item->memAlloc.size)+4, ((
char*)&size)+4, 2 );
750 assert( type ==
QueueType::MemFree || type == QueueType::MemFreeCallstack || type == QueueType::MemFreeNamed || type == QueueType::MemFreeCallstackNamed );
755 MemWrite( &item->memFree.thread, thread );
764 MemWrite( &item->hdr.type, QueueType::MemNamePayload );
769 #if ( defined _WIN32 || defined __CYGWIN__ ) && defined TRACY_TIMER_QPC
810 #ifdef TRACY_ON_DEMAND
811 std::atomic<uint64_t> m_connectionId;
813 TracyMutex m_deferredLock;
817 #ifdef TRACY_HAS_SYSTIME