2017-09-10 15:43:56 +00:00
# ifndef __TRACYPROFILER_HPP__
# define __TRACYPROFILER_HPP__
# include <atomic>
2017-09-25 22:42:09 +00:00
# include <chrono>
2017-09-10 18:08:42 +00:00
# include <stdint.h>
2017-10-14 15:20:37 +00:00
# include <string.h>
2017-09-10 15:43:56 +00:00
2017-10-03 12:19:32 +00:00
# include "concurrentqueue.h"
2018-06-19 16:51:21 +00:00
# include "TracyCallstack.hpp"
2018-04-01 17:53:05 +00:00
# include "TracyFastVector.hpp"
2017-09-17 11:10:42 +00:00
# include "../common/tracy_lz4.hpp"
2018-04-01 17:53:05 +00:00
# include "../common/tracy_benaphore.h"
2017-09-13 20:56:08 +00:00
# include "../common/TracyQueue.hpp"
2018-03-31 12:03:55 +00:00
# include "../common/TracyAlign.hpp"
2017-10-18 17:08:19 +00:00
# include "../common/TracyAlloc.hpp"
2017-11-11 18:44:09 +00:00
# include "../common/TracySystem.hpp"
2017-09-10 18:09:14 +00:00
2017-09-25 22:42:09 +00:00
# if defined _MSC_VER || defined __CYGWIN__
# include <intrin.h>
# endif
2018-04-27 14:58:45 +00:00
# if defined _MSC_VER || defined __CYGWIN__ || ( ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) && !defined __ANDROID__ ) || __ARM_ARCH >= 6
2018-04-26 14:03:31 +00:00
# define TRACY_HW_TIMER
2018-04-27 17:40:47 +00:00
# if defined _MSC_VER || defined __CYGWIN__
// Enable optimization for MSVC __rdtscp() intrin, saving one LHS of a cpu value on the stack.
// This comes at the cost of an unaligned memory write.
# define TRACY_RDTSCP_OPT
# endif
2018-04-26 14:03:31 +00:00
# endif
2017-09-10 15:43:56 +00:00
namespace tracy
{
2017-09-14 17:07:56 +00:00
class Socket ;
2017-09-26 00:28:14 +00:00
struct SourceLocation
{
2017-11-14 22:06:45 +00:00
const char * name ;
2017-09-26 00:28:14 +00:00
const char * function ;
const char * file ;
uint32_t line ;
2017-09-26 16:54:48 +00:00
uint32_t color ;
2017-09-26 00:28:14 +00:00
} ;
2017-10-10 23:44:35 +00:00
struct ProducerWrapper
{
moodycamel : : ConcurrentQueue < QueueItem > : : ExplicitProducer * ptr ;
} ;
extern thread_local ProducerWrapper s_token ;
2017-10-03 12:19:32 +00:00
2017-11-14 22:29:48 +00:00
class GpuCtx ;
struct GpuCtxWrapper
{
GpuCtx * ptr ;
} ;
2018-06-17 16:14:37 +00:00
class VkCtx ;
struct VkCtxWrapper
{
VkCtx * ptr ;
} ;
2017-10-03 12:50:55 +00:00
using Magic = moodycamel : : ConcurrentQueueDefaultTraits : : index_t ;
2018-04-27 14:58:45 +00:00
# if __ARM_ARCH >= 6
extern int64_t ( * GetTimeImpl ) ( ) ;
# endif
2018-04-01 17:53:05 +00:00
class Profiler ;
extern Profiler s_profiler ;
2017-09-10 15:43:56 +00:00
class Profiler
{
public :
Profiler ( ) ;
~ Profiler ( ) ;
2018-04-26 13:30:53 +00:00
static tracy_force_inline int64_t GetTime ( uint32_t & cpu )
2017-09-25 22:42:09 +00:00
{
2018-04-26 13:30:53 +00:00
# ifdef TRACY_HW_TIMER
2018-04-27 14:58:45 +00:00
# if __ARM_ARCH >= 6
2018-04-26 15:17:37 +00:00
cpu = 0xFFFFFFFF ;
2018-04-27 14:58:45 +00:00
return GetTimeImpl ( ) ;
2018-04-26 14:03:31 +00:00
# elif defined _MSC_VER || defined __CYGWIN__
2017-10-10 21:21:30 +00:00
const auto t = int64_t ( __rdtscp ( & cpu ) ) ;
2017-10-01 17:11:01 +00:00
return t ;
2018-04-26 13:30:53 +00:00
# elif defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
2017-10-29 12:15:43 +00:00
uint32_t eax , edx ;
2017-10-10 21:21:30 +00:00
asm volatile ( " rdtscp " : " =a " ( eax ) , " =d " ( edx ) , " =c " ( cpu ) : : ) ;
2017-10-29 12:15:43 +00:00
return ( uint64_t ( edx ) < < 32 ) + uint64_t ( eax ) ;
2018-04-26 13:30:53 +00:00
# endif
# else
cpu = 0xFFFFFFFF ;
return std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : high_resolution_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
2017-10-03 13:35:43 +00:00
# endif
}
2018-04-26 13:30:53 +00:00
static tracy_force_inline int64_t GetTime ( )
2017-10-29 15:12:16 +00:00
{
2018-04-26 13:30:53 +00:00
# ifdef TRACY_HW_TIMER
2018-04-27 14:58:45 +00:00
# if __ARM_ARCH >= 6
return GetTimeImpl ( ) ;
2018-04-26 14:03:31 +00:00
# elif defined _MSC_VER || defined __CYGWIN__
2018-04-26 14:12:52 +00:00
unsigned int dontcare ;
2017-10-29 15:12:16 +00:00
const auto t = int64_t ( __rdtscp ( & dontcare ) ) ;
return t ;
2018-04-26 13:30:53 +00:00
# elif defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
2017-10-29 15:12:16 +00:00
uint32_t eax , edx ;
2017-10-29 15:20:07 +00:00
asm volatile ( " rdtscp " : " =a " ( eax ) , " =d " ( edx ) : : " %ecx " ) ;
2017-10-29 15:12:16 +00:00
return ( uint64_t ( edx ) < < 32 ) + uint64_t ( eax ) ;
2018-04-26 13:30:53 +00:00
# endif
2017-10-29 15:12:16 +00:00
# else
return std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : high_resolution_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
# endif
}
2017-10-03 13:10:25 +00:00
static tracy_force_inline void FrameMark ( )
2017-10-03 12:19:32 +00:00
{
2017-10-03 12:50:55 +00:00
Magic magic ;
2017-10-10 23:44:35 +00:00
auto & token = s_token . ptr ;
2017-10-10 23:27:22 +00:00
auto & tail = token - > get_tail_index ( ) ;
2017-10-10 23:04:21 +00:00
auto item = token - > enqueue_begin < moodycamel : : CanAlloc > ( magic ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > hdr . type , QueueType : : FrameMarkMsg ) ;
MemWrite ( & item - > frameMark . time , GetTime ( ) ) ;
2017-10-10 23:27:22 +00:00
tail . store ( magic + 1 , std : : memory_order_release ) ;
2017-10-03 12:19:32 +00:00
}
2017-09-10 18:09:14 +00:00
2017-10-13 00:21:29 +00:00
static tracy_force_inline void PlotData ( const char * name , int64_t val )
{
Magic magic ;
auto & token = s_token . ptr ;
auto & tail = token - > get_tail_index ( ) ;
auto item = token - > enqueue_begin < moodycamel : : CanAlloc > ( magic ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > hdr . type , QueueType : : PlotData ) ;
MemWrite ( & item - > plotData . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotData . time , GetTime ( ) ) ;
MemWrite ( & item - > plotData . type , PlotDataType : : Int ) ;
MemWrite ( & item - > plotData . data . i , val ) ;
2017-10-13 00:21:29 +00:00
tail . store ( magic + 1 , std : : memory_order_release ) ;
}
static tracy_force_inline void PlotData ( const char * name , float val )
{
Magic magic ;
auto & token = s_token . ptr ;
auto & tail = token - > get_tail_index ( ) ;
auto item = token - > enqueue_begin < moodycamel : : CanAlloc > ( magic ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > hdr . type , QueueType : : PlotData ) ;
MemWrite ( & item - > plotData . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotData . time , GetTime ( ) ) ;
MemWrite ( & item - > plotData . type , PlotDataType : : Float ) ;
MemWrite ( & item - > plotData . data . f , val ) ;
2017-10-13 00:21:29 +00:00
tail . store ( magic + 1 , std : : memory_order_release ) ;
}
2017-10-13 00:07:03 +00:00
static tracy_force_inline void PlotData ( const char * name , double val )
{
Magic magic ;
auto & token = s_token . ptr ;
auto & tail = token - > get_tail_index ( ) ;
auto item = token - > enqueue_begin < moodycamel : : CanAlloc > ( magic ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > hdr . type , QueueType : : PlotData ) ;
MemWrite ( & item - > plotData . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotData . time , GetTime ( ) ) ;
MemWrite ( & item - > plotData . type , PlotDataType : : Double ) ;
MemWrite ( & item - > plotData . data . d , val ) ;
2017-10-13 00:07:03 +00:00
tail . store ( magic + 1 , std : : memory_order_release ) ;
}
2017-10-14 11:23:13 +00:00
static tracy_force_inline void Message ( const char * txt , size_t size )
{
Magic magic ;
2017-10-20 16:28:25 +00:00
auto & token = s_token . ptr ;
2017-10-14 15:15:18 +00:00
auto ptr = ( char * ) tracy_malloc ( size + 1 ) ;
2017-10-14 11:23:13 +00:00
memcpy ( ptr , txt , size ) ;
ptr [ size ] = ' \0 ' ;
auto & tail = token - > get_tail_index ( ) ;
auto item = token - > enqueue_begin < moodycamel : : CanAlloc > ( magic ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > hdr . type , QueueType : : Message ) ;
MemWrite ( & item - > message . time , GetTime ( ) ) ;
MemWrite ( & item - > message . thread , GetThreadHandle ( ) ) ;
MemWrite ( & item - > message . text , ( uint64_t ) ptr ) ;
2017-10-14 11:23:13 +00:00
tail . store ( magic + 1 , std : : memory_order_release ) ;
}
2017-10-15 11:06:49 +00:00
static tracy_force_inline void Message ( const char * txt )
{
Magic magic ;
auto & token = s_token . ptr ;
auto & tail = token - > get_tail_index ( ) ;
auto item = token - > enqueue_begin < moodycamel : : CanAlloc > ( magic ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > hdr . type , QueueType : : MessageLiteral ) ;
MemWrite ( & item - > message . time , GetTime ( ) ) ;
MemWrite ( & item - > message . thread , GetThreadHandle ( ) ) ;
MemWrite ( & item - > message . text , ( uint64_t ) txt ) ;
2017-10-15 11:06:49 +00:00
tail . store ( magic + 1 , std : : memory_order_release ) ;
}
2018-03-31 19:56:05 +00:00
static tracy_force_inline void MemAlloc ( const void * ptr , size_t size )
{
2018-04-01 17:53:24 +00:00
const auto thread = GetThreadHandle ( ) ;
s_profiler . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemAlloc ( QueueType : : MemAlloc , thread , ptr , size ) ;
2018-04-01 17:53:24 +00:00
s_profiler . m_serialLock . unlock ( ) ;
2018-03-31 19:56:05 +00:00
}
static tracy_force_inline void MemFree ( const void * ptr )
{
2018-04-01 17:53:24 +00:00
const auto thread = GetThreadHandle ( ) ;
s_profiler . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemFree ( QueueType : : MemFree , thread , ptr ) ;
2018-04-01 17:53:24 +00:00
s_profiler . m_serialLock . unlock ( ) ;
2018-03-31 19:56:05 +00:00
}
2018-06-19 16:51:21 +00:00
static tracy_force_inline void MemAllocCallstack ( const void * ptr , size_t size , int depth )
{
const auto thread = GetThreadHandle ( ) ;
s_profiler . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemAlloc ( QueueType : : MemAllocCallstack , thread , ptr , size ) ;
2018-06-19 16:51:21 +00:00
SendCallstackMemory ( depth ) ;
s_profiler . m_serialLock . unlock ( ) ;
}
static tracy_force_inline void MemFreeCallstack ( const void * ptr , int depth )
{
const auto thread = GetThreadHandle ( ) ;
s_profiler . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemFree ( QueueType : : MemFreeCallstack , thread , ptr ) ;
2018-06-19 16:51:21 +00:00
SendCallstackMemory ( depth ) ;
s_profiler . m_serialLock . unlock ( ) ;
}
2017-09-14 17:23:50 +00:00
static bool ShouldExit ( ) ;
2017-09-10 15:43:56 +00:00
private :
2017-10-18 16:48:51 +00:00
enum DequeueStatus { Success , ConnectionLost , QueueEmpty } ;
2017-10-16 19:13:57 +00:00
static void LaunchWorker ( void * ptr ) { ( ( Profiler * ) ptr ) - > Worker ( ) ; }
2017-09-10 15:43:56 +00:00
void Worker ( ) ;
2017-10-18 16:48:51 +00:00
DequeueStatus Dequeue ( moodycamel : : ConsumerToken & token ) ;
2018-04-01 18:04:35 +00:00
DequeueStatus DequeueSerial ( ) ;
2017-11-11 13:16:37 +00:00
bool AppendData ( const void * data , size_t len ) ;
bool CommitData ( ) ;
2017-11-11 14:08:03 +00:00
bool NeedDataSize ( size_t len ) ;
2017-10-18 16:48:51 +00:00
2017-09-14 17:07:56 +00:00
bool SendData ( const char * data , size_t len ) ;
2018-06-19 17:00:57 +00:00
void SendString ( uint64_t ptr , const char * str , QueueType type ) ;
2017-09-26 17:00:25 +00:00
void SendSourceLocation ( uint64_t ptr ) ;
2018-06-19 17:00:57 +00:00
void SendSourceLocationPayload ( uint64_t ptr ) ;
2018-06-19 17:09:43 +00:00
void SendCallstackPayload ( uint64_t ptr ) ;
2018-06-19 23:06:31 +00:00
void SendCallstackFrame ( uint64_t ptr ) ;
2017-09-21 23:54:04 +00:00
bool HandleServerQuery ( ) ;
2017-09-14 17:07:56 +00:00
2017-09-23 19:33:05 +00:00
void CalibrateTimer ( ) ;
2017-09-24 14:02:09 +00:00
void CalibrateDelay ( ) ;
2017-09-23 19:33:05 +00:00
2018-06-20 21:30:19 +00:00
static tracy_force_inline void SendCallstackMemory ( int depth )
{
# ifdef TRACY_HAS_CALLSTACK
auto ptr = Callstack ( depth ) ;
auto item = s_profiler . m_serialQueue . push_next ( ) ;
MemWrite ( & item - > hdr . type , QueueType : : CallstackMemory ) ;
MemWrite ( & item - > callstackMemory . ptr , ( uint64_t ) ptr ) ;
# endif
}
2018-06-20 21:29:44 +00:00
static tracy_force_inline void SendMemAlloc ( QueueType type , const uint64_t thread , const void * ptr , size_t size )
{
assert ( type = = QueueType : : MemAlloc | | type = = QueueType : : MemAllocCallstack ) ;
auto item = s_profiler . m_serialQueue . push_next ( ) ;
MemWrite ( & item - > hdr . type , type ) ;
MemWrite ( & item - > memAlloc . time , GetTime ( ) ) ;
MemWrite ( & item - > memAlloc . thread , thread ) ;
MemWrite ( & item - > memAlloc . ptr , ( uint64_t ) ptr ) ;
if ( sizeof ( size ) = = 4 )
{
memcpy ( & item - > memAlloc . size , & size , 4 ) ;
memset ( & item - > memAlloc . size + 4 , 0 , 2 ) ;
}
else
{
assert ( sizeof ( size ) = = 8 ) ;
memcpy ( & item - > memAlloc . size , & size , 6 ) ;
}
}
static tracy_force_inline void SendMemFree ( QueueType type , const uint64_t thread , const void * ptr )
{
assert ( type = = QueueType : : MemFree | | type = = QueueType : : MemFreeCallstack ) ;
auto item = s_profiler . m_serialQueue . push_next ( ) ;
MemWrite ( & item - > hdr . type , type ) ;
MemWrite ( & item - > memFree . time , GetTime ( ) ) ;
MemWrite ( & item - > memFree . thread , thread ) ;
MemWrite ( & item - > memFree . ptr , ( uint64_t ) ptr ) ;
}
2017-09-23 19:33:05 +00:00
double m_timerMul ;
2017-09-29 16:29:39 +00:00
uint64_t m_resolution ;
2017-09-24 14:02:09 +00:00
uint64_t m_delay ;
2017-10-16 23:07:54 +00:00
std : : atomic < int64_t > m_timeBegin ;
2017-09-22 23:37:07 +00:00
uint64_t m_mainThread ;
2017-10-03 22:34:05 +00:00
uint64_t m_epoch ;
2017-09-10 15:43:56 +00:00
std : : atomic < bool > m_shutdown ;
2017-10-18 17:49:17 +00:00
Socket * m_sock ;
2017-09-17 11:10:42 +00:00
LZ4_stream_t * m_stream ;
char * m_buffer ;
int m_bufferOffset ;
2017-11-11 13:16:37 +00:00
int m_bufferStart ;
2017-11-02 11:56:13 +00:00
QueueItem * m_itemBuf ;
2017-11-02 16:37:10 +00:00
char * m_lz4Buf ;
2018-04-01 17:53:05 +00:00
2018-04-14 13:46:11 +00:00
FastVector < QueueItem > m_serialQueue , m_serialDequeue ;
2018-04-01 17:53:05 +00:00
NonRecursiveBenaphore m_serialLock ;
2017-09-10 15:43:56 +00:00
} ;
} ;
# endif