The open source OpenXR runtime
at main 973 lines 32 kB view raw
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#include <time.h> 9 10#include "tracy_concurrentqueue.h" 11#include "tracy_SPSCQueue.h" 12#include "TracyCallstack.hpp" 13#include "TracySysTime.hpp" 14#include "TracyFastVector.hpp" 15#include "../common/TracyQueue.hpp" 16#include "../common/TracyAlign.hpp" 17#include "../common/TracyAlloc.hpp" 18#include "../common/TracyMutex.hpp" 19#include "../common/TracyProtocol.hpp" 20 21#if defined _WIN32 22# include <intrin.h> 23#endif 24#ifdef __APPLE__ 25# include <TargetConditionals.h> 26# include <mach/mach_time.h> 27#endif 28 29#if ( defined _WIN32 || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) ) 30# define TRACY_HW_TIMER 31#endif 32 33#ifdef __linux__ 34# include <signal.h> 35#endif 36 37#if defined TRACY_TIMER_FALLBACK || !defined TRACY_HW_TIMER 38# include <chrono> 39#endif 40 41#ifndef TracyConcat 42# define TracyConcat(x,y) TracyConcatIndirect(x,y) 43#endif 44#ifndef TracyConcatIndirect 45# define TracyConcatIndirect(x,y) x##y 46#endif 47 48namespace tracy 49{ 50#if defined(TRACY_DELAYED_INIT) && defined(TRACY_MANUAL_LIFETIME) 51TRACY_API void StartupProfiler(); 52TRACY_API void ShutdownProfiler(); 53#endif 54 55class GpuCtx; 56class Profiler; 57class Socket; 58class UdpBroadcast; 59 60struct GpuCtxWrapper 61{ 62 GpuCtx* ptr; 63}; 64 65TRACY_API moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* GetToken(); 66TRACY_API Profiler& GetProfiler(); 67TRACY_API std::atomic<uint32_t>& GetLockCounter(); 68TRACY_API std::atomic<uint8_t>& GetGpuCtxCounter(); 69TRACY_API GpuCtxWrapper& GetGpuCtx(); 70TRACY_API uint32_t GetThreadHandle(); 71TRACY_API bool ProfilerAvailable(); 72TRACY_API bool ProfilerAllocatorAvailable(); 73TRACY_API int64_t GetFrequencyQpc(); 74 75#if defined TRACY_TIMER_FALLBACK && defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) 76TRACY_API bool HardwareSupportsInvariantTSC(); // check, if we need fallback scenario 77#else 78# if defined TRACY_HW_TIMER 79tracy_force_inline bool HardwareSupportsInvariantTSC() 80{ 81 return true; // this is checked at startup 82} 83# else 84tracy_force_inline bool HardwareSupportsInvariantTSC() 85{ 86 return false; 87} 88# endif 89#endif 90 91 92struct SourceLocationData 93{ 94 const char* name; 95 const char* function; 96 const char* file; 97 uint32_t line; 98 uint32_t color; 99}; 100 101#ifdef TRACY_ON_DEMAND 102struct LuaZoneState 103{ 104 uint32_t counter; 105 bool active; 106}; 107#endif 108 109 110#define TracyLfqPrepare( _type ) \ 111 moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \ 112 auto __token = GetToken(); \ 113 auto& __tail = __token->get_tail_index(); \ 114 auto item = __token->enqueue_begin( __magic ); \ 115 MemWrite( &item->hdr.type, _type ); 116 117#define TracyLfqCommit \ 118 __tail.store( __magic + 1, std::memory_order_release ); 119 120#define TracyLfqPrepareC( _type ) \ 121 tracy::moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \ 122 auto __token = tracy::GetToken(); \ 123 auto& __tail = __token->get_tail_index(); \ 124 auto item = __token->enqueue_begin( __magic ); \ 125 tracy::MemWrite( &item->hdr.type, _type ); 126 127#define TracyLfqCommitC \ 128 __tail.store( __magic + 1, std::memory_order_release ); 129 130 131#ifdef TRACY_FIBERS 132# define TracyQueuePrepare( _type ) \ 133 auto item = Profiler::QueueSerial(); \ 134 MemWrite( &item->hdr.type, _type ); 135# define TracyQueueCommit( _name ) \ 136 MemWrite( &item->_name.thread, GetThreadHandle() ); \ 137 Profiler::QueueSerialFinish(); 138# define TracyQueuePrepareC( _type ) \ 139 auto item = tracy::Profiler::QueueSerial(); \ 140 tracy::MemWrite( &item->hdr.type, _type ); 141# define TracyQueueCommitC( _name ) \ 142 tracy::MemWrite( &item->_name.thread, tracy::GetThreadHandle() ); \ 143 tracy::Profiler::QueueSerialFinish(); 144#else 145# define TracyQueuePrepare( _type ) TracyLfqPrepare( _type ) 146# define TracyQueueCommit( _name ) TracyLfqCommit 147# define TracyQueuePrepareC( _type ) TracyLfqPrepareC( _type ) 148# define TracyQueueCommitC( _name ) TracyLfqCommitC 149#endif 150 151 152typedef void(*ParameterCallback)( void* data, uint32_t idx, int32_t val ); 153typedef char*(*SourceContentsCallback)( void* data, const char* filename, size_t& size ); 154 155class Profiler 156{ 157 struct FrameImageQueueItem 158 { 159 void* image; 160 uint32_t frame; 161 uint16_t w; 162 uint16_t h; 163 bool flip; 164 }; 165 166 enum class SymbolQueueItemType 167 { 168 CallstackFrame, 169 SymbolQuery, 170 ExternalName, 171 KernelCode, 172 SourceCode 173 }; 174 175 struct SymbolQueueItem 176 { 177 SymbolQueueItemType type; 178 uint64_t ptr; 179 uint64_t extra; 180 uint32_t id; 181 182 SymbolQueueItem(SymbolQueueItemType type, uint64_t ptr) 183 : SymbolQueueItem(type, ptr, 0) {} 184 SymbolQueueItem(SymbolQueueItemType type, uint64_t ptr, uint64_t extra) 185 : SymbolQueueItem(type, ptr, extra, 0) {} 186 SymbolQueueItem(SymbolQueueItemType type, uint64_t ptr, uint64_t extra, uint32_t id) 187 : type{type}, ptr{ptr}, extra{extra}, id{id} {} 188 }; 189 190public: 191 Profiler(); 192 ~Profiler(); 193 194 void SpawnWorkerThreads(); 195 196 static tracy_force_inline int64_t GetTime() 197 { 198#ifdef TRACY_HW_TIMER 199# if defined TARGET_OS_IOS && TARGET_OS_IOS == 1 200 if( HardwareSupportsInvariantTSC() ) return mach_absolute_time(); 201# elif defined _WIN32 202# ifdef TRACY_TIMER_QPC 203 return GetTimeQpc(); 204# else 205 if( HardwareSupportsInvariantTSC() ) return int64_t( __rdtsc() ); 206# endif 207# elif defined __i386 || defined _M_IX86 208 if( HardwareSupportsInvariantTSC() ) 209 { 210 uint32_t eax, edx; 211 asm volatile ( "rdtsc" : "=a" (eax), "=d" (edx) ); 212 return ( uint64_t( edx ) << 32 ) + uint64_t( eax ); 213 } 214# elif defined __x86_64__ || defined _M_X64 215 if( HardwareSupportsInvariantTSC() ) 216 { 217 uint64_t rax, rdx; 218 asm volatile ( "rdtsc" : "=a" (rax), "=d" (rdx) ); 219 return (int64_t)(( rdx << 32 ) + rax); 220 } 221# else 222# error "TRACY_HW_TIMER detection logic needs fixing" 223# endif 224#endif 225 226#if !defined TRACY_HW_TIMER || defined TRACY_TIMER_FALLBACK 227# if defined __linux__ && defined CLOCK_MONOTONIC_RAW 228 struct timespec ts; 229 clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); 230 return int64_t( ts.tv_sec ) * 1000000000ll + int64_t( ts.tv_nsec ); 231# else 232 return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); 233# endif 234#endif 235 236#if !defined TRACY_TIMER_FALLBACK 237 return 0; // unreachable branch 238#endif 239 } 240 241 tracy_force_inline uint32_t GetNextZoneId() 242 { 243 return m_zoneId.fetch_add( 1, std::memory_order_relaxed ); 244 } 245 246 static tracy_force_inline QueueItem* QueueSerial() 247 { 248 auto& p = GetProfiler(); 249 p.m_serialLock.lock(); 250 return p.m_serialQueue.prepare_next(); 251 } 252 253 static tracy_force_inline QueueItem* QueueSerialCallstack( void* ptr ) 254 { 255 auto& p = GetProfiler(); 256 p.m_serialLock.lock(); 257 p.SendCallstackSerial( ptr ); 258 return p.m_serialQueue.prepare_next(); 259 } 260 261 static tracy_force_inline void QueueSerialFinish() 262 { 263 auto& p = GetProfiler(); 264 p.m_serialQueue.commit_next(); 265 p.m_serialLock.unlock(); 266 } 267 268 static tracy_force_inline void SendFrameMark( const char* name ) 269 { 270 if( !name ) GetProfiler().m_frameCount.fetch_add( 1, std::memory_order_relaxed ); 271#ifdef TRACY_ON_DEMAND 272 if( !GetProfiler().IsConnected() ) return; 273#endif 274 auto item = QueueSerial(); 275 MemWrite( &item->hdr.type, QueueType::FrameMarkMsg ); 276 MemWrite( &item->frameMark.time, GetTime() ); 277 MemWrite( &item->frameMark.name, uint64_t( name ) ); 278 QueueSerialFinish(); 279 } 280 281 static tracy_force_inline void SendFrameMark( const char* name, QueueType type ) 282 { 283 assert( type == QueueType::FrameMarkMsgStart || type == QueueType::FrameMarkMsgEnd ); 284#ifdef TRACY_ON_DEMAND 285 if( !GetProfiler().IsConnected() ) return; 286#endif 287 auto item = QueueSerial(); 288 MemWrite( &item->hdr.type, type ); 289 MemWrite( &item->frameMark.time, GetTime() ); 290 MemWrite( &item->frameMark.name, uint64_t( name ) ); 291 QueueSerialFinish(); 292 } 293 294 static tracy_force_inline void SendFrameImage( const void* image, uint16_t w, uint16_t h, uint8_t offset, bool flip ) 295 { 296#ifndef TRACY_NO_FRAME_IMAGE 297 auto& profiler = GetProfiler(); 298 assert( profiler.m_frameCount.load( std::memory_order_relaxed ) < std::numeric_limits<uint32_t>::max() ); 299# ifdef TRACY_ON_DEMAND 300 if( !profiler.IsConnected() ) return; 301# endif 302 const auto sz = size_t( w ) * size_t( h ) * 4; 303 auto ptr = (char*)tracy_malloc( sz ); 304 memcpy( ptr, image, sz ); 305 306 profiler.m_fiLock.lock(); 307 auto fi = profiler.m_fiQueue.prepare_next(); 308 fi->image = ptr; 309 fi->frame = uint32_t( profiler.m_frameCount.load( std::memory_order_relaxed ) - offset ); 310 fi->w = w; 311 fi->h = h; 312 fi->flip = flip; 313 profiler.m_fiQueue.commit_next(); 314 profiler.m_fiLock.unlock(); 315#endif 316 } 317 318 static tracy_force_inline void PlotData( const char* name, int64_t val ) 319 { 320#ifdef TRACY_ON_DEMAND 321 if( !GetProfiler().IsConnected() ) return; 322#endif 323 TracyLfqPrepare( QueueType::PlotDataInt ); 324 MemWrite( &item->plotDataInt.name, (uint64_t)name ); 325 MemWrite( &item->plotDataInt.time, GetTime() ); 326 MemWrite( &item->plotDataInt.val, val ); 327 TracyLfqCommit; 328 } 329 330 static tracy_force_inline void PlotData( const char* name, float val ) 331 { 332#ifdef TRACY_ON_DEMAND 333 if( !GetProfiler().IsConnected() ) return; 334#endif 335 TracyLfqPrepare( QueueType::PlotDataFloat ); 336 MemWrite( &item->plotDataFloat.name, (uint64_t)name ); 337 MemWrite( &item->plotDataFloat.time, GetTime() ); 338 MemWrite( &item->plotDataFloat.val, val ); 339 TracyLfqCommit; 340 } 341 342 static tracy_force_inline void PlotData( const char* name, double val ) 343 { 344#ifdef TRACY_ON_DEMAND 345 if( !GetProfiler().IsConnected() ) return; 346#endif 347 TracyLfqPrepare( QueueType::PlotDataDouble ); 348 MemWrite( &item->plotDataDouble.name, (uint64_t)name ); 349 MemWrite( &item->plotDataDouble.time, GetTime() ); 350 MemWrite( &item->plotDataDouble.val, val ); 351 TracyLfqCommit; 352 } 353 354 static tracy_force_inline void ConfigurePlot( const char* name, PlotFormatType type, bool step, bool fill, uint32_t color ) 355 { 356 TracyLfqPrepare( QueueType::PlotConfig ); 357 MemWrite( &item->plotConfig.name, (uint64_t)name ); 358 MemWrite( &item->plotConfig.type, (uint8_t)type ); 359 MemWrite( &item->plotConfig.step, (uint8_t)step ); 360 MemWrite( &item->plotConfig.fill, (uint8_t)fill ); 361 MemWrite( &item->plotConfig.color, color ); 362 363#ifdef TRACY_ON_DEMAND 364 GetProfiler().DeferItem( *item ); 365#endif 366 367 TracyLfqCommit; 368 } 369 370 static tracy_force_inline void Message( const char* txt, size_t size, int callstack ) 371 { 372 assert( size < std::numeric_limits<uint16_t>::max() ); 373#ifdef TRACY_ON_DEMAND 374 if( !GetProfiler().IsConnected() ) return; 375#endif 376 if( callstack != 0 ) 377 { 378 tracy::GetProfiler().SendCallstack( callstack ); 379 } 380 381 auto ptr = (char*)tracy_malloc( size ); 382 memcpy( ptr, txt, size ); 383 384 TracyQueuePrepare( callstack == 0 ? QueueType::Message : QueueType::MessageCallstack ); 385 MemWrite( &item->messageFat.time, GetTime() ); 386 MemWrite( &item->messageFat.text, (uint64_t)ptr ); 387 MemWrite( &item->messageFat.size, (uint16_t)size ); 388 TracyQueueCommit( messageFatThread ); 389 } 390 391 static tracy_force_inline void Message( const char* txt, int callstack ) 392 { 393#ifdef TRACY_ON_DEMAND 394 if( !GetProfiler().IsConnected() ) return; 395#endif 396 if( callstack != 0 ) 397 { 398 tracy::GetProfiler().SendCallstack( callstack ); 399 } 400 401 TracyQueuePrepare( callstack == 0 ? QueueType::MessageLiteral : QueueType::MessageLiteralCallstack ); 402 MemWrite( &item->messageLiteral.time, GetTime() ); 403 MemWrite( &item->messageLiteral.text, (uint64_t)txt ); 404 TracyQueueCommit( messageLiteralThread ); 405 } 406 407 static tracy_force_inline void MessageColor( const char* txt, size_t size, uint32_t color, int callstack ) 408 { 409 assert( size < std::numeric_limits<uint16_t>::max() ); 410#ifdef TRACY_ON_DEMAND 411 if( !GetProfiler().IsConnected() ) return; 412#endif 413 if( callstack != 0 ) 414 { 415 tracy::GetProfiler().SendCallstack( callstack ); 416 } 417 418 auto ptr = (char*)tracy_malloc( size ); 419 memcpy( ptr, txt, size ); 420 421 TracyQueuePrepare( callstack == 0 ? QueueType::MessageColor : QueueType::MessageColorCallstack ); 422 MemWrite( &item->messageColorFat.time, GetTime() ); 423 MemWrite( &item->messageColorFat.text, (uint64_t)ptr ); 424 MemWrite( &item->messageColorFat.b, uint8_t( ( color ) & 0xFF ) ); 425 MemWrite( &item->messageColorFat.g, uint8_t( ( color >> 8 ) & 0xFF ) ); 426 MemWrite( &item->messageColorFat.r, uint8_t( ( color >> 16 ) & 0xFF ) ); 427 MemWrite( &item->messageColorFat.size, (uint16_t)size ); 428 TracyQueueCommit( messageColorFatThread ); 429 } 430 431 static tracy_force_inline void MessageColor( const char* txt, uint32_t color, int callstack ) 432 { 433#ifdef TRACY_ON_DEMAND 434 if( !GetProfiler().IsConnected() ) return; 435#endif 436 if( callstack != 0 ) 437 { 438 tracy::GetProfiler().SendCallstack( callstack ); 439 } 440 441 TracyQueuePrepare( callstack == 0 ? QueueType::MessageLiteralColor : QueueType::MessageLiteralColorCallstack ); 442 MemWrite( &item->messageColorLiteral.time, GetTime() ); 443 MemWrite( &item->messageColorLiteral.text, (uint64_t)txt ); 444 MemWrite( &item->messageColorLiteral.b, uint8_t( ( color ) & 0xFF ) ); 445 MemWrite( &item->messageColorLiteral.g, uint8_t( ( color >> 8 ) & 0xFF ) ); 446 MemWrite( &item->messageColorLiteral.r, uint8_t( ( color >> 16 ) & 0xFF ) ); 447 TracyQueueCommit( messageColorLiteralThread ); 448 } 449 450 static tracy_force_inline void MessageAppInfo( const char* txt, size_t size ) 451 { 452 assert( size < std::numeric_limits<uint16_t>::max() ); 453 auto ptr = (char*)tracy_malloc( size ); 454 memcpy( ptr, txt, size ); 455 TracyLfqPrepare( QueueType::MessageAppInfo ); 456 MemWrite( &item->messageFat.time, GetTime() ); 457 MemWrite( &item->messageFat.text, (uint64_t)ptr ); 458 MemWrite( &item->messageFat.size, (uint16_t)size ); 459 460#ifdef TRACY_ON_DEMAND 461 GetProfiler().DeferItem( *item ); 462#endif 463 464 TracyLfqCommit; 465 } 466 467 static tracy_force_inline void MemAlloc( const void* ptr, size_t size, bool secure ) 468 { 469 if( secure && !ProfilerAvailable() ) return; 470#ifdef TRACY_ON_DEMAND 471 if( !GetProfiler().IsConnected() ) return; 472#endif 473 const auto thread = GetThreadHandle(); 474 475 GetProfiler().m_serialLock.lock(); 476 SendMemAlloc( QueueType::MemAlloc, thread, ptr, size ); 477 GetProfiler().m_serialLock.unlock(); 478 } 479 480 static tracy_force_inline void MemFree( const void* ptr, bool secure ) 481 { 482 if( secure && !ProfilerAvailable() ) return; 483#ifdef TRACY_ON_DEMAND 484 if( !GetProfiler().IsConnected() ) return; 485#endif 486 const auto thread = GetThreadHandle(); 487 488 GetProfiler().m_serialLock.lock(); 489 SendMemFree( QueueType::MemFree, thread, ptr ); 490 GetProfiler().m_serialLock.unlock(); 491 } 492 493 static tracy_force_inline void MemAllocCallstack( const void* ptr, size_t size, int depth, bool secure ) 494 { 495 if( secure && !ProfilerAvailable() ) return; 496#ifdef TRACY_HAS_CALLSTACK 497 auto& profiler = GetProfiler(); 498# ifdef TRACY_ON_DEMAND 499 if( !profiler.IsConnected() ) return; 500# endif 501 const auto thread = GetThreadHandle(); 502 503 auto callstack = Callstack( depth ); 504 505 profiler.m_serialLock.lock(); 506 SendCallstackSerial( callstack ); 507 SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size ); 508 profiler.m_serialLock.unlock(); 509#else 510 static_cast<void>(depth); // unused 511 MemAlloc( ptr, size, secure ); 512#endif 513 } 514 515 static tracy_force_inline void MemFreeCallstack( const void* ptr, int depth, bool secure ) 516 { 517 if( secure && !ProfilerAvailable() ) return; 518 if( !ProfilerAllocatorAvailable() ) 519 { 520 MemFree( ptr, secure ); 521 return; 522 } 523#ifdef TRACY_HAS_CALLSTACK 524 auto& profiler = GetProfiler(); 525# ifdef TRACY_ON_DEMAND 526 if( !profiler.IsConnected() ) return; 527# endif 528 const auto thread = GetThreadHandle(); 529 530 auto callstack = Callstack( depth ); 531 532 profiler.m_serialLock.lock(); 533 SendCallstackSerial( callstack ); 534 SendMemFree( QueueType::MemFreeCallstack, thread, ptr ); 535 profiler.m_serialLock.unlock(); 536#else 537 static_cast<void>(depth); // unused 538 MemFree( ptr, secure ); 539#endif 540 } 541 542 static tracy_force_inline void MemAllocNamed( const void* ptr, size_t size, bool secure, const char* name ) 543 { 544 if( secure && !ProfilerAvailable() ) return; 545#ifdef TRACY_ON_DEMAND 546 if( !GetProfiler().IsConnected() ) return; 547#endif 548 const auto thread = GetThreadHandle(); 549 550 GetProfiler().m_serialLock.lock(); 551 SendMemName( name ); 552 SendMemAlloc( QueueType::MemAllocNamed, thread, ptr, size ); 553 GetProfiler().m_serialLock.unlock(); 554 } 555 556 static tracy_force_inline void MemFreeNamed( const void* ptr, bool secure, const char* name ) 557 { 558 if( secure && !ProfilerAvailable() ) return; 559#ifdef TRACY_ON_DEMAND 560 if( !GetProfiler().IsConnected() ) return; 561#endif 562 const auto thread = GetThreadHandle(); 563 564 GetProfiler().m_serialLock.lock(); 565 SendMemName( name ); 566 SendMemFree( QueueType::MemFreeNamed, thread, ptr ); 567 GetProfiler().m_serialLock.unlock(); 568 } 569 570 static tracy_force_inline void MemAllocCallstackNamed( const void* ptr, size_t size, int depth, bool secure, const char* name ) 571 { 572 if( secure && !ProfilerAvailable() ) return; 573#ifdef TRACY_HAS_CALLSTACK 574 auto& profiler = GetProfiler(); 575# ifdef TRACY_ON_DEMAND 576 if( !profiler.IsConnected() ) return; 577# endif 578 const auto thread = GetThreadHandle(); 579 580 auto callstack = Callstack( depth ); 581 582 profiler.m_serialLock.lock(); 583 SendCallstackSerial( callstack ); 584 SendMemName( name ); 585 SendMemAlloc( QueueType::MemAllocCallstackNamed, thread, ptr, size ); 586 profiler.m_serialLock.unlock(); 587#else 588 static_cast<void>(depth); // unused 589 static_cast<void>(name); // unused 590 MemAlloc( ptr, size, secure ); 591#endif 592 } 593 594 static tracy_force_inline void MemFreeCallstackNamed( const void* ptr, int depth, bool secure, const char* name ) 595 { 596 if( secure && !ProfilerAvailable() ) return; 597#ifdef TRACY_HAS_CALLSTACK 598 auto& profiler = GetProfiler(); 599# ifdef TRACY_ON_DEMAND 600 if( !profiler.IsConnected() ) return; 601# endif 602 const auto thread = GetThreadHandle(); 603 604 auto callstack = Callstack( depth ); 605 606 profiler.m_serialLock.lock(); 607 SendCallstackSerial( callstack ); 608 SendMemName( name ); 609 SendMemFree( QueueType::MemFreeCallstackNamed, thread, ptr ); 610 profiler.m_serialLock.unlock(); 611#else 612 static_cast<void>(depth); // unused 613 static_cast<void>(name); // unused 614 MemFree( ptr, secure ); 615#endif 616 } 617 618 static tracy_force_inline void SendCallstack( int depth ) 619 { 620#ifdef TRACY_HAS_CALLSTACK 621 auto ptr = Callstack( depth ); 622 TracyQueuePrepare( QueueType::Callstack ); 623 MemWrite( &item->callstackFat.ptr, (uint64_t)ptr ); 624 TracyQueueCommit( callstackFatThread ); 625#else 626 static_cast<void>(depth); // unused 627#endif 628 } 629 630 static tracy_force_inline void ParameterRegister( ParameterCallback cb, void* data ) 631 { 632 auto& profiler = GetProfiler(); 633 profiler.m_paramCallback = cb; 634 profiler.m_paramCallbackData = data; 635 } 636 637 static tracy_force_inline void ParameterSetup( uint32_t idx, const char* name, bool isBool, int32_t val ) 638 { 639 TracyLfqPrepare( QueueType::ParamSetup ); 640 tracy::MemWrite( &item->paramSetup.idx, idx ); 641 tracy::MemWrite( &item->paramSetup.name, (uint64_t)name ); 642 tracy::MemWrite( &item->paramSetup.isBool, (uint8_t)isBool ); 643 tracy::MemWrite( &item->paramSetup.val, val ); 644 645#ifdef TRACY_ON_DEMAND 646 GetProfiler().DeferItem( *item ); 647#endif 648 649 TracyLfqCommit; 650 } 651 652 static tracy_force_inline void SourceCallbackRegister( SourceContentsCallback cb, void* data ) 653 { 654 auto& profiler = GetProfiler(); 655 profiler.m_sourceCallback = cb; 656 profiler.m_sourceCallbackData = data; 657 } 658 659#ifdef TRACY_FIBERS 660 static tracy_force_inline void EnterFiber( const char* fiber ) 661 { 662 TracyQueuePrepare( QueueType::FiberEnter ); 663 MemWrite( &item->fiberEnter.time, GetTime() ); 664 MemWrite( &item->fiberEnter.fiber, (uint64_t)fiber ); 665 TracyQueueCommit( fiberEnter ); 666 } 667 668 static tracy_force_inline void LeaveFiber() 669 { 670 TracyQueuePrepare( QueueType::FiberLeave ); 671 MemWrite( &item->fiberLeave.time, GetTime() ); 672 TracyQueueCommit( fiberLeave ); 673 } 674#endif 675 676 void SendCallstack( int depth, const char* skipBefore ); 677 static void CutCallstack( void* callstack, const char* skipBefore ); 678 679 static bool ShouldExit(); 680 681 tracy_force_inline bool IsConnected() const 682 { 683 return m_isConnected.load( std::memory_order_acquire ); 684 } 685 686#ifdef TRACY_ON_DEMAND 687 tracy_force_inline uint64_t ConnectionId() const 688 { 689 return m_connectionId.load( std::memory_order_acquire ); 690 } 691 692 tracy_force_inline void DeferItem( const QueueItem& item ) 693 { 694 m_deferredLock.lock(); 695 auto dst = m_deferredQueue.push_next(); 696 memcpy( dst, &item, sizeof( item ) ); 697 m_deferredLock.unlock(); 698 } 699#endif 700 701 void RequestShutdown() { m_shutdown.store( true, std::memory_order_relaxed ); m_shutdownManual.store( true, std::memory_order_relaxed ); } 702 bool HasShutdownFinished() const { return m_shutdownFinished.load( std::memory_order_relaxed ); } 703 704 void SendString( uint64_t str, const char* ptr, QueueType type ) { SendString( str, ptr, strlen( ptr ), type ); } 705 void SendString( uint64_t str, const char* ptr, size_t len, QueueType type ); 706 void SendSingleString( const char* ptr ) { SendSingleString( ptr, strlen( ptr ) ); } 707 void SendSingleString( const char* ptr, size_t len ); 708 void SendSecondString( const char* ptr ) { SendSecondString( ptr, strlen( ptr ) ); } 709 void SendSecondString( const char* ptr, size_t len ); 710 711 712 // Allocated source location data layout: 713 // 2b payload size 714 // 4b color 715 // 4b source line 716 // fsz function name 717 // 1b null terminator 718 // ssz source file name 719 // 1b null terminator 720 // nsz zone name (optional) 721 722 static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, const char* function ) 723 { 724 return AllocSourceLocation( line, source, function, nullptr, 0 ); 725 } 726 727 static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, const char* function, const char* name, size_t nameSz ) 728 { 729 return AllocSourceLocation( line, source, strlen(source), function, strlen(function), name, nameSz ); 730 } 731 732 static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz ) 733 { 734 return AllocSourceLocation( line, source, sourceSz, function, functionSz, nullptr, 0 ); 735 } 736 737 static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz ) 738 { 739 const auto sz32 = uint32_t( 2 + 4 + 4 + functionSz + 1 + sourceSz + 1 + nameSz ); 740 assert( sz32 <= std::numeric_limits<uint16_t>::max() ); 741 const auto sz = uint16_t( sz32 ); 742 auto ptr = (char*)tracy_malloc( sz ); 743 memcpy( ptr, &sz, 2 ); 744 memset( ptr + 2, 0, 4 ); 745 memcpy( ptr + 6, &line, 4 ); 746 memcpy( ptr + 10, function, functionSz ); 747 ptr[10 + functionSz] = '\0'; 748 memcpy( ptr + 10 + functionSz + 1, source, sourceSz ); 749 ptr[10 + functionSz + 1 + sourceSz] = '\0'; 750 if( nameSz != 0 ) 751 { 752 memcpy( ptr + 10 + functionSz + 1 + sourceSz + 1, name, nameSz ); 753 } 754 return uint64_t( ptr ); 755 } 756 757private: 758 enum class DequeueStatus { DataDequeued, ConnectionLost, QueueEmpty }; 759 enum class ThreadCtxStatus { Same, Changed, ConnectionLost }; 760 761 static void LaunchWorker( void* ptr ) { ((Profiler*)ptr)->Worker(); } 762 void Worker(); 763 764#ifndef TRACY_NO_FRAME_IMAGE 765 static void LaunchCompressWorker( void* ptr ) { ((Profiler*)ptr)->CompressWorker(); } 766 void CompressWorker(); 767#endif 768 769#ifdef TRACY_HAS_CALLSTACK 770 static void LaunchSymbolWorker( void* ptr ) { ((Profiler*)ptr)->SymbolWorker(); } 771 void SymbolWorker(); 772 void HandleSymbolQueueItem( const SymbolQueueItem& si ); 773#endif 774 775 void ClearQueues( tracy::moodycamel::ConsumerToken& token ); 776 void ClearSerial(); 777 DequeueStatus Dequeue( tracy::moodycamel::ConsumerToken& token ); 778 DequeueStatus DequeueContextSwitches( tracy::moodycamel::ConsumerToken& token, int64_t& timeStop ); 779 DequeueStatus DequeueSerial(); 780 ThreadCtxStatus ThreadCtxCheck( uint32_t threadId ); 781 bool CommitData(); 782 783 tracy_force_inline bool AppendData( const void* data, size_t len ) 784 { 785 const auto ret = NeedDataSize( len ); 786 AppendDataUnsafe( data, len ); 787 return ret; 788 } 789 790 tracy_force_inline bool NeedDataSize( size_t len ) 791 { 792 assert( len <= TargetFrameSize ); 793 bool ret = true; 794 if( m_bufferOffset - m_bufferStart + (int)len > TargetFrameSize ) 795 { 796 ret = CommitData(); 797 } 798 return ret; 799 } 800 801 tracy_force_inline void AppendDataUnsafe( const void* data, size_t len ) 802 { 803 memcpy( m_buffer + m_bufferOffset, data, len ); 804 m_bufferOffset += int( len ); 805 } 806 807 bool SendData( const char* data, size_t len ); 808 void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type ); 809 void SendSourceLocation( uint64_t ptr ); 810 void SendSourceLocationPayload( uint64_t ptr ); 811 void SendCallstackPayload( uint64_t ptr ); 812 void SendCallstackPayload64( uint64_t ptr ); 813 void SendCallstackAlloc( uint64_t ptr ); 814 815 void QueueCallstackFrame( uint64_t ptr ); 816 void QueueSymbolQuery( uint64_t symbol ); 817 void QueueExternalName( uint64_t ptr ); 818 void QueueKernelCode( uint64_t symbol, uint32_t size ); 819 void QueueSourceCodeQuery( uint32_t id ); 820 821 bool HandleServerQuery(); 822 void HandleDisconnect(); 823 void HandleParameter( uint64_t payload ); 824 void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size ); 825 void HandleSourceCodeQuery( char* data, char* image, uint32_t id ); 826 827 void AckServerQuery(); 828 void AckSymbolCodeNotAvailable(); 829 830 void CalibrateTimer(); 831 void CalibrateDelay(); 832 void ReportTopology(); 833 834 static tracy_force_inline void SendCallstackSerial( void* ptr ) 835 { 836#ifdef TRACY_HAS_CALLSTACK 837 auto item = GetProfiler().m_serialQueue.prepare_next(); 838 MemWrite( &item->hdr.type, QueueType::CallstackSerial ); 839 MemWrite( &item->callstackFat.ptr, (uint64_t)ptr ); 840 GetProfiler().m_serialQueue.commit_next(); 841#else 842 static_cast<void>(ptr); // unused 843#endif 844 } 845 846 static tracy_force_inline void SendMemAlloc( QueueType type, const uint32_t thread, const void* ptr, size_t size ) 847 { 848 assert( type == QueueType::MemAlloc || type == QueueType::MemAllocCallstack || type == QueueType::MemAllocNamed || type == QueueType::MemAllocCallstackNamed ); 849 850 auto item = GetProfiler().m_serialQueue.prepare_next(); 851 MemWrite( &item->hdr.type, type ); 852 MemWrite( &item->memAlloc.time, GetTime() ); 853 MemWrite( &item->memAlloc.thread, thread ); 854 MemWrite( &item->memAlloc.ptr, (uint64_t)ptr ); 855 if( compile_time_condition<sizeof( size ) == 4>::value ) 856 { 857 memcpy( &item->memAlloc.size, &size, 4 ); 858 memset( &item->memAlloc.size + 4, 0, 2 ); 859 } 860 else 861 { 862 assert( sizeof( size ) == 8 ); 863 memcpy( &item->memAlloc.size, &size, 4 ); 864 memcpy( ((char*)&item->memAlloc.size)+4, ((char*)&size)+4, 2 ); 865 } 866 GetProfiler().m_serialQueue.commit_next(); 867 } 868 869 static tracy_force_inline void SendMemFree( QueueType type, const uint32_t thread, const void* ptr ) 870 { 871 assert( type == QueueType::MemFree || type == QueueType::MemFreeCallstack || type == QueueType::MemFreeNamed || type == QueueType::MemFreeCallstackNamed ); 872 873 auto item = GetProfiler().m_serialQueue.prepare_next(); 874 MemWrite( &item->hdr.type, type ); 875 MemWrite( &item->memFree.time, GetTime() ); 876 MemWrite( &item->memFree.thread, thread ); 877 MemWrite( &item->memFree.ptr, (uint64_t)ptr ); 878 GetProfiler().m_serialQueue.commit_next(); 879 } 880 881 static tracy_force_inline void SendMemName( const char* name ) 882 { 883 assert( name ); 884 auto item = GetProfiler().m_serialQueue.prepare_next(); 885 MemWrite( &item->hdr.type, QueueType::MemNamePayload ); 886 MemWrite( &item->memName.name, (uint64_t)name ); 887 GetProfiler().m_serialQueue.commit_next(); 888 } 889 890#if defined _WIN32 && defined TRACY_TIMER_QPC 891 static int64_t GetTimeQpc(); 892#endif 893 894 double m_timerMul; 895 uint64_t m_resolution; 896 uint64_t m_delay; 897 std::atomic<int64_t> m_timeBegin; 898 uint32_t m_mainThread; 899 uint64_t m_epoch, m_exectime; 900 std::atomic<bool> m_shutdown; 901 std::atomic<bool> m_shutdownManual; 902 std::atomic<bool> m_shutdownFinished; 903 Socket* m_sock; 904 UdpBroadcast* m_broadcast; 905 bool m_noExit; 906 uint32_t m_userPort; 907 std::atomic<uint32_t> m_zoneId; 908 int64_t m_samplingPeriod; 909 910 uint32_t m_threadCtx; 911 int64_t m_refTimeThread; 912 int64_t m_refTimeSerial; 913 int64_t m_refTimeCtx; 914 int64_t m_refTimeGpu; 915 916 void* m_stream; // LZ4_stream_t* 917 char* m_buffer; 918 int m_bufferOffset; 919 int m_bufferStart; 920 921 char* m_lz4Buf; 922 923 FastVector<QueueItem> m_serialQueue, m_serialDequeue; 924 TracyMutex m_serialLock; 925 926#ifndef TRACY_NO_FRAME_IMAGE 927 FastVector<FrameImageQueueItem> m_fiQueue, m_fiDequeue; 928 TracyMutex m_fiLock; 929#endif 930 931 SPSCQueue<SymbolQueueItem> m_symbolQueue; 932 933 std::atomic<uint64_t> m_frameCount; 934 std::atomic<bool> m_isConnected; 935#ifdef TRACY_ON_DEMAND 936 std::atomic<uint64_t> m_connectionId; 937 938 TracyMutex m_deferredLock; 939 FastVector<QueueItem> m_deferredQueue; 940#endif 941 942#ifdef TRACY_HAS_SYSTIME 943 void ProcessSysTime(); 944 945 SysTime m_sysTime; 946 uint64_t m_sysTimeLast = 0; 947#else 948 void ProcessSysTime() {} 949#endif 950 951 ParameterCallback m_paramCallback; 952 void* m_paramCallbackData; 953 SourceContentsCallback m_sourceCallback; 954 void* m_sourceCallbackData; 955 956 char* m_queryImage; 957 char* m_queryData; 958 char* m_queryDataPtr; 959 960#if defined _WIN32 961 void* m_exceptionHandler; 962#endif 963#ifdef __linux__ 964 struct { 965 struct sigaction pwr, ill, fpe, segv, pipe, bus, abrt; 966 } m_prevSignal; 967#endif 968 bool m_crashHandlerInstalled; 969}; 970 971} 972 973#endif