TracyProfiler.hpp (20328B)
1 #ifndef __TRACYPROFILER_HPP__ 2 #define __TRACYPROFILER_HPP__ 3 4 #include <assert.h> 5 #include <atomic> 6 #include <stdint.h> 7 #include <string.h> 8 9 #include "tracy_concurrentqueue.h" 10 #include "TracyCallstack.hpp" 11 #include "TracySysTime.hpp" 12 #include "TracyFastVector.hpp" 13 #include "../common/TracyQueue.hpp" 14 #include "../common/TracyAlign.hpp" 15 #include "../common/TracyAlloc.hpp" 16 #include "../common/TracyMutex.hpp" 17 18 #if defined _WIN32 || defined __CYGWIN__ 19 # include <intrin.h> 20 #endif 21 #ifdef __APPLE__ 22 # include <TargetConditionals.h> 23 # include <mach/mach_time.h> 24 #endif 25 26 #if defined _WIN32 || defined __CYGWIN__ || ( ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) && !defined __ANDROID__ ) || __ARM_ARCH >= 6 27 # define TRACY_HW_TIMER 28 #endif 29 30 #if !defined TRACY_HW_TIMER || ( __ARM_ARCH >= 6 && !defined CLOCK_MONOTONIC_RAW ) 31 #include <chrono> 32 #endif 33 34 #ifndef TracyConcat 35 # define TracyConcat(x,y) TracyConcatIndirect(x,y) 36 #endif 37 #ifndef TracyConcatIndirect 38 # define TracyConcatIndirect(x,y) x##y 39 #endif 40 41 namespace tracy 42 { 43 44 class GpuCtx; 45 class Profiler; 46 class Socket; 47 class UdpBroadcast; 48 49 struct GpuCtxWrapper 50 { 51 GpuCtx* ptr; 52 }; 53 54 TRACY_API moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* GetToken(); 55 TRACY_API Profiler& GetProfiler(); 56 TRACY_API std::atomic<uint32_t>& GetLockCounter(); 57 TRACY_API std::atomic<uint8_t>& GetGpuCtxCounter(); 58 TRACY_API GpuCtxWrapper& GetGpuCtx(); 59 TRACY_API uint64_t GetThreadHandle(); 60 61 TRACY_API void InitRPMallocThread(); 62 63 struct SourceLocationData 64 { 65 const char* name; 66 const char* function; 67 const char* file; 68 uint32_t line; 69 uint32_t color; 70 }; 71 72 #ifdef TRACY_ON_DEMAND 73 struct LuaZoneState 74 { 75 uint32_t counter; 76 bool active; 77 }; 78 #endif 79 80 using Magic = moodycamel::ConcurrentQueueDefaultTraits::index_t; 81 82 83 typedef void(*ParameterCallback)( uint32_t idx, int32_t val ); 84 85 class Profiler 86 { 87 struct FrameImageQueueItem 88 { 89 void* image; 90 uint64_t frame; 91 uint16_t w; 92 uint16_t h; 93 uint8_t offset; 94 bool flip; 95 }; 96 97 public: 98 Profiler(); 99 ~Profiler(); 100 101 static tracy_force_inline int64_t GetTime() 102 { 103 #ifdef TRACY_HW_TIMER 104 # if TARGET_OS_IOS == 1 105 return mach_absolute_time(); 106 # elif __ARM_ARCH >= 6 107 # ifdef CLOCK_MONOTONIC_RAW 108 struct timespec ts; 109 clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); 110 return int64_t( ts.tv_sec ) * 1000000000ll + int64_t( ts.tv_nsec ); 111 # else 112 return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); 113 # endif 114 # elif defined _WIN32 || defined __CYGWIN__ 115 return int64_t( __rdtsc() ); 116 # elif defined __i386 || defined _M_IX86 117 uint32_t eax, edx; 118 asm volatile ( "rdtsc" : "=a" (eax), "=d" (edx) ); 119 return ( uint64_t( edx ) << 32 ) + uint64_t( eax ); 120 # elif defined __x86_64__ || defined _M_X64 121 uint64_t rax, rdx; 122 asm volatile ( "rdtsc" : "=a" (rax), "=d" (rdx) ); 123 return ( rdx << 32 ) + rax; 124 # endif 125 #else 126 return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); 127 #endif 128 } 129 130 tracy_force_inline uint32_t GetNextZoneId() 131 { 132 return m_zoneId.fetch_add( 1, std::memory_order_relaxed ); 133 } 134 135 static tracy_force_inline QueueItem* QueueSerial() 136 { 137 auto& p = GetProfiler(); 138 p.m_serialLock.lock(); 139 return p.m_serialQueue.prepare_next(); 140 } 141 142 static tracy_force_inline void QueueSerialFinish() 143 { 144 auto& p = GetProfiler(); 145 p.m_serialQueue.commit_next(); 146 p.m_serialLock.unlock(); 147 } 148 149 static tracy_force_inline void SendFrameMark( const char* name ) 150 { 151 if( !name ) GetProfiler().m_frameCount.fetch_add( 1, std::memory_order_relaxed ); 152 #ifdef TRACY_ON_DEMAND 153 if( !GetProfiler().IsConnected() ) return; 154 #endif 155 Magic magic; 156 auto token = GetToken(); 157 auto& tail = token->get_tail_index(); 158 auto item = token->enqueue_begin( magic ); 159 MemWrite( &item->hdr.type, QueueType::FrameMarkMsg ); 160 MemWrite( &item->frameMark.time, GetTime() ); 161 MemWrite( &item->frameMark.name, uint64_t( name ) ); 162 tail.store( magic + 1, std::memory_order_release ); 163 } 164 165 static tracy_force_inline void SendFrameMark( const char* name, QueueType type ) 166 { 167 assert( type == QueueType::FrameMarkMsgStart || type == QueueType::FrameMarkMsgEnd ); 168 #ifdef TRACY_ON_DEMAND 169 if( !GetProfiler().IsConnected() ) return; 170 #endif 171 auto item = QueueSerial(); 172 MemWrite( &item->hdr.type, type ); 173 MemWrite( &item->frameMark.time, GetTime() ); 174 MemWrite( &item->frameMark.name, uint64_t( name ) ); 175 QueueSerialFinish(); 176 } 177 178 static tracy_force_inline void SendFrameImage( const void* image, uint16_t w, uint16_t h, uint8_t offset, bool flip ) 179 { 180 auto& profiler = GetProfiler(); 181 #ifdef TRACY_ON_DEMAND 182 if( !profiler.IsConnected() ) return; 183 #endif 184 const auto sz = size_t( w ) * size_t( h ) * 4; 185 auto ptr = (char*)tracy_malloc( sz ); 186 memcpy( ptr, image, sz ); 187 188 profiler.m_fiLock.lock(); 189 auto fi = profiler.m_fiQueue.prepare_next(); 190 fi->image = ptr; 191 fi->frame = profiler.m_frameCount.load( std::memory_order_relaxed ) - offset; 192 fi->w = w; 193 fi->h = h; 194 fi->flip = flip; 195 profiler.m_fiQueue.commit_next(); 196 profiler.m_fiLock.unlock(); 197 } 198 199 static tracy_force_inline void PlotData( const char* name, int64_t val ) 200 { 201 #ifdef TRACY_ON_DEMAND 202 if( !GetProfiler().IsConnected() ) return; 203 #endif 204 Magic magic; 205 auto token = GetToken(); 206 auto& tail = token->get_tail_index(); 207 auto item = token->enqueue_begin( magic ); 208 MemWrite( &item->hdr.type, QueueType::PlotData ); 209 MemWrite( &item->plotData.name, (uint64_t)name ); 210 MemWrite( &item->plotData.time, GetTime() ); 211 MemWrite( &item->plotData.type, PlotDataType::Int ); 212 MemWrite( &item->plotData.data.i, val ); 213 tail.store( magic + 1, std::memory_order_release ); 214 } 215 216 static tracy_force_inline void PlotData( const char* name, float val ) 217 { 218 #ifdef TRACY_ON_DEMAND 219 if( !GetProfiler().IsConnected() ) return; 220 #endif 221 Magic magic; 222 auto token = GetToken(); 223 auto& tail = token->get_tail_index(); 224 auto item = token->enqueue_begin( magic ); 225 MemWrite( &item->hdr.type, QueueType::PlotData ); 226 MemWrite( &item->plotData.name, (uint64_t)name ); 227 MemWrite( &item->plotData.time, GetTime() ); 228 MemWrite( &item->plotData.type, PlotDataType::Float ); 229 MemWrite( &item->plotData.data.f, val ); 230 tail.store( magic + 1, std::memory_order_release ); 231 } 232 233 static tracy_force_inline void PlotData( const char* name, double val ) 234 { 235 #ifdef TRACY_ON_DEMAND 236 if( !GetProfiler().IsConnected() ) return; 237 #endif 238 Magic magic; 239 auto token = GetToken(); 240 auto& tail = token->get_tail_index(); 241 auto item = token->enqueue_begin( magic ); 242 MemWrite( &item->hdr.type, QueueType::PlotData ); 243 MemWrite( &item->plotData.name, (uint64_t)name ); 244 MemWrite( &item->plotData.time, GetTime() ); 245 MemWrite( &item->plotData.type, PlotDataType::Double ); 246 MemWrite( &item->plotData.data.d, val ); 247 tail.store( magic + 1, std::memory_order_release ); 248 } 249 250 static tracy_force_inline void ConfigurePlot( const char* name, PlotFormatType type ) 251 { 252 Magic magic; 253 auto token = GetToken(); 254 auto& tail = token->get_tail_index(); 255 auto item = token->enqueue_begin( magic ); 256 MemWrite( &item->hdr.type, QueueType::PlotConfig ); 257 MemWrite( &item->plotConfig.name, (uint64_t)name ); 258 MemWrite( &item->plotConfig.type, (uint8_t)type ); 259 260 #ifdef TRACY_ON_DEMAND 261 GetProfiler().DeferItem( *item ); 262 #endif 263 264 tail.store( magic + 1, std::memory_order_release ); 265 } 266 267 static tracy_force_inline void Message( const char* txt, size_t size, int callstack ) 268 { 269 #ifdef TRACY_ON_DEMAND 270 if( !GetProfiler().IsConnected() ) return; 271 #endif 272 Magic magic; 273 auto token = GetToken(); 274 auto ptr = (char*)tracy_malloc( size+1 ); 275 memcpy( ptr, txt, size ); 276 ptr[size] = '\0'; 277 auto& tail = token->get_tail_index(); 278 auto item = token->enqueue_begin( magic ); 279 MemWrite( &item->hdr.type, callstack == 0 ? QueueType::Message : QueueType::MessageCallstack ); 280 MemWrite( &item->message.time, GetTime() ); 281 MemWrite( &item->message.text, (uint64_t)ptr ); 282 tail.store( magic + 1, std::memory_order_release ); 283 284 if( callstack != 0 ) tracy::GetProfiler().SendCallstack( callstack ); 285 } 286 287 static tracy_force_inline void Message( const char* txt, int callstack ) 288 { 289 #ifdef TRACY_ON_DEMAND 290 if( !GetProfiler().IsConnected() ) return; 291 #endif 292 Magic magic; 293 auto token = GetToken(); 294 auto& tail = token->get_tail_index(); 295 auto item = token->enqueue_begin( magic ); 296 MemWrite( &item->hdr.type, callstack == 0 ? QueueType::MessageLiteral : QueueType::MessageLiteralCallstack ); 297 MemWrite( &item->message.time, GetTime() ); 298 MemWrite( &item->message.text, (uint64_t)txt ); 299 tail.store( magic + 1, std::memory_order_release ); 300 301 if( callstack != 0 ) tracy::GetProfiler().SendCallstack( callstack ); 302 } 303 304 static tracy_force_inline void MessageColor( const char* txt, size_t size, uint32_t color, int callstack ) 305 { 306 #ifdef TRACY_ON_DEMAND 307 if( !GetProfiler().IsConnected() ) return; 308 #endif 309 Magic magic; 310 auto token = GetToken(); 311 auto ptr = (char*)tracy_malloc( size+1 ); 312 memcpy( ptr, txt, size ); 313 ptr[size] = '\0'; 314 auto& tail = token->get_tail_index(); 315 auto item = token->enqueue_begin( magic ); 316 MemWrite( &item->hdr.type, callstack == 0 ? QueueType::MessageColor : QueueType::MessageColorCallstack ); 317 MemWrite( &item->messageColor.time, GetTime() ); 318 MemWrite( &item->messageColor.text, (uint64_t)ptr ); 319 MemWrite( &item->messageColor.r, uint8_t( ( color ) & 0xFF ) ); 320 MemWrite( &item->messageColor.g, uint8_t( ( color >> 8 ) & 0xFF ) ); 321 MemWrite( &item->messageColor.b, uint8_t( ( color >> 16 ) & 0xFF ) ); 322 tail.store( magic + 1, std::memory_order_release ); 323 324 if( callstack != 0 ) tracy::GetProfiler().SendCallstack( callstack ); 325 } 326 327 static tracy_force_inline void MessageColor( const char* txt, uint32_t color, int callstack ) 328 { 329 #ifdef TRACY_ON_DEMAND 330 if( !GetProfiler().IsConnected() ) return; 331 #endif 332 Magic magic; 333 auto token = GetToken(); 334 auto& tail = token->get_tail_index(); 335 auto item = token->enqueue_begin( magic ); 336 MemWrite( &item->hdr.type, callstack == 0 ? QueueType::MessageLiteralColor : QueueType::MessageLiteralColorCallstack ); 337 MemWrite( &item->messageColor.time, GetTime() ); 338 MemWrite( &item->messageColor.text, (uint64_t)txt ); 339 MemWrite( &item->messageColor.r, uint8_t( ( color ) & 0xFF ) ); 340 MemWrite( &item->messageColor.g, uint8_t( ( color >> 8 ) & 0xFF ) ); 341 MemWrite( &item->messageColor.b, uint8_t( ( color >> 16 ) & 0xFF ) ); 342 tail.store( magic + 1, std::memory_order_release ); 343 344 if( callstack != 0 ) tracy::GetProfiler().SendCallstack( callstack ); 345 } 346 347 static tracy_force_inline void MessageAppInfo( const char* txt, size_t size ) 348 { 349 Magic magic; 350 auto token = GetToken(); 351 auto ptr = (char*)tracy_malloc( size+1 ); 352 memcpy( ptr, txt, size ); 353 ptr[size] = '\0'; 354 auto& tail = token->get_tail_index(); 355 auto item = token->enqueue_begin( magic ); 356 MemWrite( &item->hdr.type, QueueType::MessageAppInfo ); 357 MemWrite( &item->message.time, GetTime() ); 358 MemWrite( &item->message.text, (uint64_t)ptr ); 359 360 #ifdef TRACY_ON_DEMAND 361 GetProfiler().DeferItem( *item ); 362 #endif 363 364 tail.store( magic + 1, std::memory_order_release ); 365 } 366 367 static tracy_force_inline void MemAlloc( const void* ptr, size_t size ) 368 { 369 #ifdef TRACY_ON_DEMAND 370 if( !GetProfiler().IsConnected() ) return; 371 #endif 372 const auto thread = GetThreadHandle(); 373 374 GetProfiler().m_serialLock.lock(); 375 SendMemAlloc( QueueType::MemAlloc, thread, ptr, size ); 376 GetProfiler().m_serialLock.unlock(); 377 } 378 379 static tracy_force_inline void MemFree( const void* ptr ) 380 { 381 #ifdef TRACY_ON_DEMAND 382 if( !GetProfiler().IsConnected() ) return; 383 #endif 384 const auto thread = GetThreadHandle(); 385 386 GetProfiler().m_serialLock.lock(); 387 SendMemFree( QueueType::MemFree, thread, ptr ); 388 GetProfiler().m_serialLock.unlock(); 389 } 390 391 static tracy_force_inline void MemAllocCallstack( const void* ptr, size_t size, int depth ) 392 { 393 #ifdef TRACY_HAS_CALLSTACK 394 auto& profiler = GetProfiler(); 395 # ifdef TRACY_ON_DEMAND 396 if( !profiler.IsConnected() ) return; 397 # endif 398 const auto thread = GetThreadHandle(); 399 400 rpmalloc_thread_initialize(); 401 auto callstack = Callstack( depth ); 402 403 profiler.m_serialLock.lock(); 404 SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size ); 405 SendCallstackMemory( callstack ); 406 profiler.m_serialLock.unlock(); 407 #else 408 MemAlloc( ptr, size ); 409 #endif 410 } 411 412 static tracy_force_inline void MemFreeCallstack( const void* ptr, int depth ) 413 { 414 #ifdef TRACY_HAS_CALLSTACK 415 auto& profiler = GetProfiler(); 416 # ifdef TRACY_ON_DEMAND 417 if( !profiler.IsConnected() ) return; 418 # endif 419 const auto thread = GetThreadHandle(); 420 421 rpmalloc_thread_initialize(); 422 auto callstack = Callstack( depth ); 423 424 profiler.m_serialLock.lock(); 425 SendMemFree( QueueType::MemFreeCallstack, thread, ptr ); 426 SendCallstackMemory( callstack ); 427 profiler.m_serialLock.unlock(); 428 #else 429 MemFree( ptr ); 430 #endif 431 } 432 433 static tracy_force_inline void SendCallstack( int depth ) 434 { 435 #ifdef TRACY_HAS_CALLSTACK 436 auto ptr = Callstack( depth ); 437 Magic magic; 438 auto token = GetToken(); 439 auto& tail = token->get_tail_index(); 440 auto item = token->enqueue_begin( magic ); 441 MemWrite( &item->hdr.type, QueueType::Callstack ); 442 MemWrite( &item->callstack.ptr, ptr ); 443 tail.store( magic + 1, std::memory_order_release ); 444 #endif 445 } 446 447 static void ParameterRegister( ParameterCallback cb ) { GetProfiler().m_paramCallback = cb; } 448 static void ParameterSetup( uint32_t idx, const char* name, bool isBool, int32_t val ); 449 450 void SendCallstack( int depth, const char* skipBefore ); 451 static void CutCallstack( void* callstack, const char* skipBefore ); 452 453 static bool ShouldExit(); 454 455 #ifdef TRACY_ON_DEMAND 456 tracy_force_inline bool IsConnected() const 457 { 458 return m_isConnected.load( std::memory_order_acquire ); 459 } 460 461 tracy_force_inline uint64_t ConnectionId() const 462 { 463 return m_connectionId.load( std::memory_order_acquire ); 464 } 465 466 tracy_force_inline void DeferItem( const QueueItem& item ) 467 { 468 m_deferredLock.lock(); 469 auto dst = m_deferredQueue.push_next(); 470 memcpy( dst, &item, sizeof( item ) ); 471 m_deferredLock.unlock(); 472 } 473 #endif 474 475 void RequestShutdown() { m_shutdown.store( true, std::memory_order_relaxed ); m_shutdownManual.store( true, std::memory_order_relaxed ); } 476 bool HasShutdownFinished() const { return m_shutdownFinished.load( std::memory_order_relaxed ); } 477 478 void SendString( uint64_t ptr, const char* str, QueueType type ); 479 480 private: 481 enum class DequeueStatus { DataDequeued, ConnectionLost, QueueEmpty }; 482 483 static void LaunchWorker( void* ptr ) { ((Profiler*)ptr)->Worker(); } 484 void Worker(); 485 486 static void LaunchCompressWorker( void* ptr ) { ((Profiler*)ptr)->CompressWorker(); } 487 void CompressWorker(); 488 489 void ClearQueues( tracy::moodycamel::ConsumerToken& token ); 490 void ClearSerial(); 491 DequeueStatus Dequeue( tracy::moodycamel::ConsumerToken& token ); 492 DequeueStatus DequeueContextSwitches( tracy::moodycamel::ConsumerToken& token, int64_t& timeStop ); 493 DequeueStatus DequeueSerial(); 494 bool AppendData( const void* data, size_t len ); 495 bool CommitData(); 496 bool NeedDataSize( size_t len ); 497 498 tracy_force_inline void AppendDataUnsafe( const void* data, size_t len ) 499 { 500 memcpy( m_buffer + m_bufferOffset, data, len ); 501 m_bufferOffset += int( len ); 502 } 503 504 bool SendData( const char* data, size_t len ); 505 void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type ); 506 void SendSourceLocation( uint64_t ptr ); 507 void SendSourceLocationPayload( uint64_t ptr ); 508 void SendCallstackPayload( uint64_t ptr ); 509 void SendCallstackAlloc( uint64_t ptr ); 510 void SendCallstackFrame( uint64_t ptr ); 511 512 bool HandleServerQuery(); 513 void HandleDisconnect(); 514 void HandleParameter( uint64_t payload ); 515 516 void CalibrateTimer(); 517 void CalibrateDelay(); 518 519 static tracy_force_inline void SendCallstackMemory( void* ptr ) 520 { 521 #ifdef TRACY_HAS_CALLSTACK 522 auto item = GetProfiler().m_serialQueue.prepare_next(); 523 MemWrite( &item->hdr.type, QueueType::CallstackMemory ); 524 MemWrite( &item->callstackMemory.ptr, (uint64_t)ptr ); 525 GetProfiler().m_serialQueue.commit_next(); 526 #endif 527 } 528 529 static tracy_force_inline void SendMemAlloc( QueueType type, const uint64_t thread, const void* ptr, size_t size ) 530 { 531 assert( type == QueueType::MemAlloc || type == QueueType::MemAllocCallstack ); 532 533 auto item = GetProfiler().m_serialQueue.prepare_next(); 534 MemWrite( &item->hdr.type, type ); 535 MemWrite( &item->memAlloc.time, GetTime() ); 536 MemWrite( &item->memAlloc.thread, thread ); 537 MemWrite( &item->memAlloc.ptr, (uint64_t)ptr ); 538 if( compile_time_condition<sizeof( size ) == 4>::value ) 539 { 540 memcpy( &item->memAlloc.size, &size, 4 ); 541 memset( &item->memAlloc.size + 4, 0, 2 ); 542 } 543 else 544 { 545 assert( sizeof( size ) == 8 ); 546 memcpy( &item->memAlloc.size, &size, 6 ); 547 } 548 GetProfiler().m_serialQueue.commit_next(); 549 } 550 551 static tracy_force_inline void SendMemFree( QueueType type, const uint64_t thread, const void* ptr ) 552 { 553 assert( type == QueueType::MemFree || type == QueueType::MemFreeCallstack ); 554 555 auto item = GetProfiler().m_serialQueue.prepare_next(); 556 MemWrite( &item->hdr.type, type ); 557 MemWrite( &item->memFree.time, GetTime() ); 558 MemWrite( &item->memFree.thread, thread ); 559 MemWrite( &item->memFree.ptr, (uint64_t)ptr ); 560 GetProfiler().m_serialQueue.commit_next(); 561 } 562 563 double m_timerMul; 564 uint64_t m_resolution; 565 uint64_t m_delay; 566 std::atomic<int64_t> m_timeBegin; 567 uint64_t m_mainThread; 568 uint64_t m_epoch; 569 std::atomic<bool> m_shutdown; 570 std::atomic<bool> m_shutdownManual; 571 std::atomic<bool> m_shutdownFinished; 572 Socket* m_sock; 573 UdpBroadcast* m_broadcast; 574 bool m_noExit; 575 std::atomic<uint32_t> m_zoneId; 576 577 uint64_t m_threadCtx; 578 int64_t m_refTimeThread; 579 int64_t m_refTimeSerial; 580 int64_t m_refTimeCtx; 581 int64_t m_refTimeGpu; 582 583 void* m_stream; // LZ4_stream_t* 584 char* m_buffer; 585 int m_bufferOffset; 586 int m_bufferStart; 587 588 QueueItem* m_itemBuf; 589 char* m_lz4Buf; 590 591 FastVector<QueueItem> m_serialQueue, m_serialDequeue; 592 TracyMutex m_serialLock; 593 594 FastVector<FrameImageQueueItem> m_fiQueue, m_fiDequeue; 595 TracyMutex m_fiLock; 596 597 std::atomic<uint64_t> m_frameCount; 598 #ifdef TRACY_ON_DEMAND 599 std::atomic<bool> m_isConnected; 600 std::atomic<uint64_t> m_connectionId; 601 602 TracyMutex m_deferredLock; 603 FastVector<QueueItem> m_deferredQueue; 604 #endif 605 606 #ifdef TRACY_HAS_SYSTIME 607 void ProcessSysTime(); 608 609 SysTime m_sysTime; 610 uint64_t m_sysTimeLast = 0; 611 #else 612 void ProcessSysTime() {} 613 #endif 614 615 ParameterCallback m_paramCallback; 616 }; 617 618 }; 619 620 #endif