2017-09-10 15:43:56 +00:00
# ifndef __TRACYPROFILER_HPP__
# define __TRACYPROFILER_HPP__
2018-08-05 00:09:59 +00:00
# include <assert.h>
2017-09-10 15:43:56 +00:00
# include <atomic>
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
2019-07-29 19:47:50 +00:00
# include "tracy_concurrentqueue.h"
2018-06-19 16:51:21 +00:00
# include "TracyCallstack.hpp"
2019-02-21 20:59:02 +00:00
# include "TracySysTime.hpp"
2018-04-01 17:53:05 +00:00
# include "TracyFastVector.hpp"
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"
2018-07-13 22:39:01 +00:00
# include "../common/TracyMutex.hpp"
2020-02-23 13:44:19 +00:00
# include "../common/TracyProtocol.hpp"
2017-09-10 18:09:14 +00:00
2019-01-19 11:03:30 +00:00
# if defined _WIN32 || defined __CYGWIN__
2017-09-25 22:42:09 +00:00
# include <intrin.h>
# endif
2019-02-21 13:45:13 +00:00
# ifdef __APPLE__
# include <TargetConditionals.h>
# include <mach / mach_time.h>
# endif
2017-09-25 22:42:09 +00:00
2019-01-19 11:03:30 +00:00
# if defined _WIN32 || 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
# endif
2020-05-22 12:53:09 +00:00
# if !defined TRACY_HW_TIMER || ( defined __ARM_ARCH && __ARM_ARCH >= 6 && !defined CLOCK_MONOTONIC_RAW )
2019-11-05 19:09:40 +00:00
# include <chrono>
# endif
2019-01-14 19:55:37 +00:00
# ifndef TracyConcat
# define TracyConcat(x,y) TracyConcatIndirect(x,y)
# endif
# ifndef TracyConcatIndirect
# define TracyConcatIndirect(x,y) x##y
# endif
2018-07-26 17:52:27 +00:00
2017-09-10 15:43:56 +00:00
namespace tracy
{
2019-02-19 18:33:37 +00:00
class GpuCtx ;
2019-02-19 17:38:08 +00:00
class Profiler ;
2017-09-14 17:07:56 +00:00
class Socket ;
2019-06-17 00:25:09 +00:00
class UdpBroadcast ;
2017-09-14 17:07:56 +00:00
2019-02-19 18:33:37 +00:00
struct GpuCtxWrapper
2017-09-26 00:28:14 +00:00
{
2019-02-19 18:33:37 +00:00
GpuCtx * ptr ;
2017-09-26 00:28:14 +00:00
} ;
2019-06-07 13:56:46 +00:00
TRACY_API moodycamel : : ConcurrentQueue < QueueItem > : : ExplicitProducer * GetToken ( ) ;
TRACY_API Profiler & GetProfiler ( ) ;
TRACY_API std : : atomic < uint32_t > & GetLockCounter ( ) ;
TRACY_API std : : atomic < uint8_t > & GetGpuCtxCounter ( ) ;
TRACY_API GpuCtxWrapper & GetGpuCtx ( ) ;
2019-06-26 17:32:52 +00:00
TRACY_API uint64_t GetThreadHandle ( ) ;
2020-01-25 15:56:54 +00:00
TRACY_API void InitRPMallocThread ( ) ;
2020-06-23 23:32:57 +00:00
TRACY_API bool ProfilerAvailable ( ) ;
2019-02-19 19:43:14 +00:00
2019-02-19 18:33:37 +00:00
struct SourceLocationData
2017-11-14 22:29:48 +00:00
{
2019-02-19 18:33:37 +00:00
const char * name ;
const char * function ;
const char * file ;
uint32_t line ;
uint32_t color ;
2017-11-14 22:29:48 +00:00
} ;
2018-07-13 18:20:37 +00:00
# ifdef TRACY_ON_DEMAND
struct LuaZoneState
{
uint32_t counter ;
bool active ;
} ;
# endif
2020-01-19 14:06:11 +00:00
# define TracyLfqPrepare( _type ) \
moodycamel : : ConcurrentQueueDefaultTraits : : index_t __magic ; \
auto __token = GetToken ( ) ; \
auto & __tail = __token - > get_tail_index ( ) ; \
auto item = __token - > enqueue_begin ( __magic ) ; \
MemWrite ( & item - > hdr . type , _type ) ;
# define TracyLfqCommit \
__tail . store ( __magic + 1 , std : : memory_order_release ) ;
# define TracyLfqPrepareC( _type ) \
tracy : : moodycamel : : ConcurrentQueueDefaultTraits : : index_t __magic ; \
auto __token = tracy : : GetToken ( ) ; \
auto & __tail = __token - > get_tail_index ( ) ; \
auto item = __token - > enqueue_begin ( __magic ) ; \
tracy : : MemWrite ( & item - > hdr . type , _type ) ;
# define TracyLfqCommitC \
__tail . store ( __magic + 1 , std : : memory_order_release ) ;
2017-10-03 12:50:55 +00:00
2018-04-01 17:53:05 +00:00
2019-11-25 22:59:48 +00:00
typedef void ( * ParameterCallback ) ( uint32_t idx , int32_t val ) ;
2017-09-10 15:43:56 +00:00
class Profiler
{
2019-06-26 20:50:56 +00:00
struct FrameImageQueueItem
{
void * image ;
2019-06-26 21:18:30 +00:00
uint64_t frame ;
2019-06-26 20:50:56 +00:00
uint16_t w ;
uint16_t h ;
uint8_t offset ;
bool flip ;
} ;
2017-09-10 15:43:56 +00:00
public :
Profiler ( ) ;
~ Profiler ( ) ;
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
2020-05-22 12:53:09 +00:00
# if defined TARGET_OS_IOS && TARGET_OS_IOS == 1
2019-02-21 13:45:13 +00:00
return mach_absolute_time ( ) ;
2020-05-22 12:53:09 +00:00
# elif defined __ARM_ARCH && __ARM_ARCH >= 6
2019-08-14 14:19:02 +00:00
# ifdef CLOCK_MONOTONIC_RAW
struct timespec ts ;
clock_gettime ( CLOCK_MONOTONIC_RAW , & ts ) ;
return int64_t ( ts . tv_sec ) * 1000000000ll + int64_t ( ts . tv_nsec ) ;
# else
return std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : high_resolution_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
# endif
2019-01-19 11:03:30 +00:00
# elif defined _WIN32 || defined __CYGWIN__
2020-04-07 20:01:31 +00:00
# ifdef TRACY_TIMER_QPC
return GetTimeQpc ( ) ;
# else
Use rdtsc instead of rdtscp.
But rdtscp is serializing!
No, it's not. Quoting the Intel Instruction Set Reference:
"The RDTSCP instruction is not a serializing instruction, but it does
wait until all previous instructions have executed and all previous
loads are globally visible. But it does not wait for previous stores to
be globally visible, and subsequent instructions may begin execution
before the read operation is performed.",
"The RDTSC instruction is not a serializing instruction. It does not
necessarily wait until all previous instructions have been executed
before reading the counter. Similarly, subsequent instructions may begin
execution before the read operation is performed."
So, the difference is in waiting for prior instructions to finish
executing. Notice that even in the rdtscp case, execution of the
following instructions may commence before time measurement is finished
and data stores may be still pending.
But, you may say, Intel in its "How to Benchmark Code Execution Times"
document shows that using rdtscp is superior to rdstc. Well, not
exactly. What they do show is that when a *single function* is
considered, there are ways to measure its execution time with little to
no error.
This is not what Tracy is doing.
In our case there is no way to determine absolute "this is before" and
"this is after" points of a zone, as we probably already are inside
another zone. Stopping the CPU execution, so that a deeply nested zone
may be measured with great precision, will skew the measurements of all
parent zones.
And this is not what we want to measure, anyway. We are not interested
in how a *single function* behaves, but how a *whole program* behaves.
The out-of-order CPU behavior may influence the measurements? Good! We
are interested in that. We want to see *how* the code is really
executed. How is *stopping* the CPU to make a timer read an appropriate
thing to do, when we want to see how a program is performing?
At least that's the theory.
And besides all that, the profiling overhead is now reduced.
2019-10-20 18:52:33 +00:00
return int64_t ( __rdtsc ( ) ) ;
2020-04-07 20:01:31 +00:00
# endif
2019-10-20 23:13:55 +00:00
# elif defined __i386 || defined _M_IX86
2017-10-29 15:12:16 +00:00
uint32_t eax , edx ;
Use rdtsc instead of rdtscp.
But rdtscp is serializing!
No, it's not. Quoting the Intel Instruction Set Reference:
"The RDTSCP instruction is not a serializing instruction, but it does
wait until all previous instructions have executed and all previous
loads are globally visible. But it does not wait for previous stores to
be globally visible, and subsequent instructions may begin execution
before the read operation is performed.",
"The RDTSC instruction is not a serializing instruction. It does not
necessarily wait until all previous instructions have been executed
before reading the counter. Similarly, subsequent instructions may begin
execution before the read operation is performed."
So, the difference is in waiting for prior instructions to finish
executing. Notice that even in the rdtscp case, execution of the
following instructions may commence before time measurement is finished
and data stores may be still pending.
But, you may say, Intel in its "How to Benchmark Code Execution Times"
document shows that using rdtscp is superior to rdstc. Well, not
exactly. What they do show is that when a *single function* is
considered, there are ways to measure its execution time with little to
no error.
This is not what Tracy is doing.
In our case there is no way to determine absolute "this is before" and
"this is after" points of a zone, as we probably already are inside
another zone. Stopping the CPU execution, so that a deeply nested zone
may be measured with great precision, will skew the measurements of all
parent zones.
And this is not what we want to measure, anyway. We are not interested
in how a *single function* behaves, but how a *whole program* behaves.
The out-of-order CPU behavior may influence the measurements? Good! We
are interested in that. We want to see *how* the code is really
executed. How is *stopping* the CPU to make a timer read an appropriate
thing to do, when we want to see how a program is performing?
At least that's the theory.
And besides all that, the profiling overhead is now reduced.
2019-10-20 18:52:33 +00:00
asm volatile ( " rdtsc " : " =a " ( eax ) , " =d " ( edx ) ) ;
2017-10-29 15:12:16 +00:00
return ( uint64_t ( edx ) < < 32 ) + uint64_t ( eax ) ;
2019-10-20 23:13:55 +00:00
# elif defined __x86_64__ || defined _M_X64
uint64_t rax , rdx ;
asm volatile ( " rdtsc " : " =a " ( rax ) , " =d " ( rdx ) ) ;
return ( rdx < < 32 ) + rax ;
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
}
2019-01-14 21:23:24 +00:00
tracy_force_inline uint32_t GetNextZoneId ( )
{
return m_zoneId . fetch_add ( 1 , std : : memory_order_relaxed ) ;
}
2019-08-12 11:27:15 +00:00
static tracy_force_inline QueueItem * QueueSerial ( )
{
auto & p = GetProfiler ( ) ;
p . m_serialLock . lock ( ) ;
return p . m_serialQueue . prepare_next ( ) ;
}
static tracy_force_inline void QueueSerialFinish ( )
{
auto & p = GetProfiler ( ) ;
p . m_serialQueue . commit_next ( ) ;
p . m_serialLock . unlock ( ) ;
}
2019-02-28 18:21:23 +00:00
static tracy_force_inline void SendFrameMark ( const char * name )
2017-10-03 12:19:32 +00:00
{
2019-06-09 13:23:01 +00:00
if ( ! name ) GetProfiler ( ) . m_frameCount . fetch_add ( 1 , std : : memory_order_relaxed ) ;
2019-06-26 21:18:30 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-10 20:23:27 +00:00
# endif
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : FrameMarkMsg ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > frameMark . time , GetTime ( ) ) ;
2019-02-28 18:21:23 +00:00
MemWrite ( & item - > frameMark . name , uint64_t ( name ) ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2017-10-03 12:19:32 +00:00
}
2017-09-10 18:09:14 +00:00
2018-08-05 00:09:59 +00:00
static tracy_force_inline void SendFrameMark ( const char * name , QueueType type )
2018-08-04 13:04:18 +00:00
{
2019-02-28 18:21:23 +00:00
assert ( type = = QueueType : : FrameMarkMsgStart | | type = = QueueType : : FrameMarkMsgEnd ) ;
2018-08-04 13:04:18 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-08-04 13:04:18 +00:00
# endif
2019-08-12 11:27:15 +00:00
auto item = QueueSerial ( ) ;
2018-08-05 00:09:59 +00:00
MemWrite ( & item - > hdr . type , type ) ;
2018-08-04 13:04:18 +00:00
MemWrite ( & item - > frameMark . time , GetTime ( ) ) ;
MemWrite ( & item - > frameMark . name , uint64_t ( name ) ) ;
2019-08-12 11:27:15 +00:00
QueueSerialFinish ( ) ;
2018-08-04 13:04:18 +00:00
}
2019-07-13 10:33:55 +00:00
static tracy_force_inline void SendFrameImage ( const void * image , uint16_t w , uint16_t h , uint8_t offset , bool flip )
2019-06-06 19:39:54 +00:00
{
2019-06-26 20:50:56 +00:00
auto & profiler = GetProfiler ( ) ;
2019-06-06 19:39:54 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-26 20:50:56 +00:00
if ( ! profiler . IsConnected ( ) ) return ;
2019-06-06 19:39:54 +00:00
# endif
const auto sz = size_t ( w ) * size_t ( h ) * 4 ;
auto ptr = ( char * ) tracy_malloc ( sz ) ;
memcpy ( ptr , image , sz ) ;
2019-06-26 20:50:56 +00:00
profiler . m_fiLock . lock ( ) ;
auto fi = profiler . m_fiQueue . prepare_next ( ) ;
fi - > image = ptr ;
2019-06-26 21:18:30 +00:00
fi - > frame = profiler . m_frameCount . load ( std : : memory_order_relaxed ) - offset ;
2019-06-26 20:50:56 +00:00
fi - > w = w ;
fi - > h = h ;
fi - > flip = flip ;
profiler . m_fiQueue . commit_next ( ) ;
profiler . m_fiLock . unlock ( ) ;
2019-06-06 19:39:54 +00:00
}
2017-10-13 00:21:29 +00:00
static tracy_force_inline void PlotData ( const char * name , int64_t val )
{
2018-07-10 21:06:27 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-10 21:06:27 +00:00
# endif
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : PlotData ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > plotData . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotData . time , GetTime ( ) ) ;
MemWrite ( & item - > plotData . type , PlotDataType : : Int ) ;
MemWrite ( & item - > plotData . data . i , val ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2017-10-13 00:21:29 +00:00
}
static tracy_force_inline void PlotData ( const char * name , float val )
{
2018-07-10 21:06:27 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-10 21:06:27 +00:00
# endif
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : PlotData ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > plotData . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotData . time , GetTime ( ) ) ;
MemWrite ( & item - > plotData . type , PlotDataType : : Float ) ;
MemWrite ( & item - > plotData . data . f , val ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2017-10-13 00:21:29 +00:00
}
2017-10-13 00:07:03 +00:00
static tracy_force_inline void PlotData ( const char * name , double val )
{
2018-07-10 21:06:27 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-10 21:06:27 +00:00
# endif
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : PlotData ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > plotData . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotData . time , GetTime ( ) ) ;
MemWrite ( & item - > plotData . type , PlotDataType : : Double ) ;
MemWrite ( & item - > plotData . data . d , val ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2017-10-13 00:07:03 +00:00
}
2019-11-05 15:47:41 +00:00
static tracy_force_inline void ConfigurePlot ( const char * name , PlotFormatType type )
{
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : PlotConfig ) ;
2019-11-05 15:47:41 +00:00
MemWrite ( & item - > plotConfig . name , ( uint64_t ) name ) ;
MemWrite ( & item - > plotConfig . type , ( uint8_t ) type ) ;
# ifdef TRACY_ON_DEMAND
GetProfiler ( ) . DeferItem ( * item ) ;
# endif
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-05 15:47:41 +00:00
}
2019-11-14 22:40:41 +00:00
static tracy_force_inline void Message ( const char * txt , size_t size , int callstack )
2017-10-14 11:23:13 +00:00
{
2018-07-10 21:09:59 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-10 21:09:59 +00:00
# endif
2020-05-19 11:48:19 +00:00
TracyLfqPrepare ( callstack = = 0 ? QueueType : : Message : QueueType : : MessageCallstack ) ;
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 ' ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > message . time , GetTime ( ) ) ;
MemWrite ( & item - > message . text , ( uint64_t ) ptr ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-14 22:40:41 +00:00
if ( callstack ! = 0 ) tracy : : GetProfiler ( ) . SendCallstack ( callstack ) ;
2017-10-14 11:23:13 +00:00
}
2019-11-14 22:40:41 +00:00
static tracy_force_inline void Message ( const char * txt , int callstack )
2017-10-15 11:06:49 +00:00
{
2018-07-10 21:09:59 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-10 21:09:59 +00:00
# endif
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( callstack = = 0 ? QueueType : : MessageLiteral : QueueType : : MessageLiteralCallstack ) ;
2018-03-31 12:03:55 +00:00
MemWrite ( & item - > message . time , GetTime ( ) ) ;
MemWrite ( & item - > message . text , ( uint64_t ) txt ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-14 22:40:41 +00:00
if ( callstack ! = 0 ) tracy : : GetProfiler ( ) . SendCallstack ( callstack ) ;
2017-10-15 11:06:49 +00:00
}
2019-11-14 22:40:41 +00:00
static tracy_force_inline void MessageColor ( const char * txt , size_t size , uint32_t color , int callstack )
2019-05-10 18:17:44 +00:00
{
# ifdef TRACY_ON_DEMAND
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
# endif
2020-05-19 11:48:19 +00:00
TracyLfqPrepare ( callstack = = 0 ? QueueType : : MessageColor : QueueType : : MessageColorCallstack ) ;
2019-05-10 18:17:44 +00:00
auto ptr = ( char * ) tracy_malloc ( size + 1 ) ;
memcpy ( ptr , txt , size ) ;
ptr [ size ] = ' \0 ' ;
MemWrite ( & item - > messageColor . time , GetTime ( ) ) ;
MemWrite ( & item - > messageColor . text , ( uint64_t ) ptr ) ;
MemWrite ( & item - > messageColor . r , uint8_t ( ( color ) & 0xFF ) ) ;
MemWrite ( & item - > messageColor . g , uint8_t ( ( color > > 8 ) & 0xFF ) ) ;
MemWrite ( & item - > messageColor . b , uint8_t ( ( color > > 16 ) & 0xFF ) ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-14 22:40:41 +00:00
if ( callstack ! = 0 ) tracy : : GetProfiler ( ) . SendCallstack ( callstack ) ;
2019-05-10 18:17:44 +00:00
}
2019-11-14 22:40:41 +00:00
static tracy_force_inline void MessageColor ( const char * txt , uint32_t color , int callstack )
2019-05-10 18:17:44 +00:00
{
# ifdef TRACY_ON_DEMAND
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
# endif
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( callstack = = 0 ? QueueType : : MessageLiteralColor : QueueType : : MessageLiteralColorCallstack ) ;
2019-05-10 18:17:44 +00:00
MemWrite ( & item - > messageColor . time , GetTime ( ) ) ;
MemWrite ( & item - > messageColor . text , ( uint64_t ) txt ) ;
MemWrite ( & item - > messageColor . r , uint8_t ( ( color ) & 0xFF ) ) ;
MemWrite ( & item - > messageColor . g , uint8_t ( ( color > > 8 ) & 0xFF ) ) ;
MemWrite ( & item - > messageColor . b , uint8_t ( ( color > > 16 ) & 0xFF ) ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-11-14 22:40:41 +00:00
if ( callstack ! = 0 ) tracy : : GetProfiler ( ) . SendCallstack ( callstack ) ;
2019-05-10 18:17:44 +00:00
}
2019-07-12 16:14:42 +00:00
static tracy_force_inline void MessageAppInfo ( const char * txt , size_t size )
{
2020-05-19 11:48:19 +00:00
InitRPMallocThread ( ) ;
2019-07-12 16:14:42 +00:00
auto ptr = ( char * ) tracy_malloc ( size + 1 ) ;
memcpy ( ptr , txt , size ) ;
ptr [ size ] = ' \0 ' ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : MessageAppInfo ) ;
2019-07-12 16:14:42 +00:00
MemWrite ( & item - > message . time , GetTime ( ) ) ;
MemWrite ( & item - > message . text , ( uint64_t ) ptr ) ;
# ifdef TRACY_ON_DEMAND
GetProfiler ( ) . DeferItem ( * item ) ;
# endif
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2019-07-12 16:14:42 +00:00
}
2020-06-23 23:33:26 +00:00
static tracy_force_inline void MemAlloc ( const void * ptr , size_t size , bool secure )
2018-03-31 19:56:05 +00:00
{
2020-06-23 23:33:26 +00:00
if ( secure & & ! ProfilerAvailable ( ) ) return ;
2018-07-11 23:36:01 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-11 23:36:01 +00:00
# endif
2018-04-01 17:53:24 +00:00
const auto thread = GetThreadHandle ( ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemAlloc ( QueueType : : MemAlloc , thread , ptr , size ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialLock . unlock ( ) ;
2018-03-31 19:56:05 +00:00
}
2020-06-23 23:33:26 +00:00
static tracy_force_inline void MemFree ( const void * ptr , bool secure )
2018-03-31 19:56:05 +00:00
{
2020-06-23 23:33:26 +00:00
if ( secure & & ! ProfilerAvailable ( ) ) return ;
2018-07-11 23:36:01 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 17:38:08 +00:00
if ( ! GetProfiler ( ) . IsConnected ( ) ) return ;
2018-07-11 23:36:01 +00:00
# endif
2018-04-01 17:53:24 +00:00
const auto thread = GetThreadHandle ( ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemFree ( QueueType : : MemFree , thread , ptr ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialLock . unlock ( ) ;
2018-03-31 19:56:05 +00:00
}
2020-06-23 23:33:26 +00:00
static tracy_force_inline void MemAllocCallstack ( const void * ptr , size_t size , int depth , bool secure )
2018-06-19 16:51:21 +00:00
{
2020-06-23 23:33:26 +00:00
if ( secure & & ! ProfilerAvailable ( ) ) return ;
2018-06-22 21:00:03 +00:00
# ifdef TRACY_HAS_CALLSTACK
2019-10-05 00:11:45 +00:00
auto & profiler = GetProfiler ( ) ;
2018-07-11 23:36:01 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 19:43:14 +00:00
if ( ! profiler . IsConnected ( ) ) return ;
2018-07-11 23:36:01 +00:00
# endif
2018-06-19 16:51:21 +00:00
const auto thread = GetThreadHandle ( ) ;
2020-01-25 15:56:54 +00:00
InitRPMallocThread ( ) ;
2018-06-22 21:00:03 +00:00
auto callstack = Callstack ( depth ) ;
2019-02-19 19:43:14 +00:00
profiler . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemAlloc ( QueueType : : MemAllocCallstack , thread , ptr , size ) ;
2018-06-22 21:00:03 +00:00
SendCallstackMemory ( callstack ) ;
2019-02-19 19:43:14 +00:00
profiler . m_serialLock . unlock ( ) ;
2018-06-22 21:00:03 +00:00
# else
2020-07-02 15:17:01 +00:00
MemAlloc ( ptr , size , secure ) ;
2018-06-22 21:00:03 +00:00
# endif
2018-06-19 16:51:21 +00:00
}
2020-06-23 23:33:26 +00:00
static tracy_force_inline void MemFreeCallstack ( const void * ptr , int depth , bool secure )
2018-06-19 16:51:21 +00:00
{
2020-06-23 23:33:26 +00:00
if ( secure & & ! ProfilerAvailable ( ) ) return ;
2018-06-22 21:00:03 +00:00
# ifdef TRACY_HAS_CALLSTACK
2019-10-05 00:11:45 +00:00
auto & profiler = GetProfiler ( ) ;
2018-07-11 23:36:01 +00:00
# ifdef TRACY_ON_DEMAND
2019-02-19 19:43:14 +00:00
if ( ! profiler . IsConnected ( ) ) return ;
2018-07-11 23:36:01 +00:00
# endif
2018-06-19 16:51:21 +00:00
const auto thread = GetThreadHandle ( ) ;
2020-01-25 15:56:54 +00:00
InitRPMallocThread ( ) ;
2018-06-22 21:00:03 +00:00
auto callstack = Callstack ( depth ) ;
2019-02-19 19:43:14 +00:00
profiler . m_serialLock . lock ( ) ;
2018-06-20 21:29:44 +00:00
SendMemFree ( QueueType : : MemFreeCallstack , thread , ptr ) ;
2018-06-22 21:00:03 +00:00
SendCallstackMemory ( callstack ) ;
2019-02-19 19:43:14 +00:00
profiler . m_serialLock . unlock ( ) ;
2018-06-22 21:00:03 +00:00
# else
2020-07-02 15:17:01 +00:00
MemFree ( ptr , secure ) ;
2018-06-22 21:00:03 +00:00
# endif
2018-06-19 16:51:21 +00:00
}
2019-07-29 22:42:31 +00:00
static tracy_force_inline void SendCallstack ( int depth )
2018-06-21 22:56:01 +00:00
{
# ifdef TRACY_HAS_CALLSTACK
auto ptr = Callstack ( depth ) ;
2020-01-19 14:06:11 +00:00
TracyLfqPrepare ( QueueType : : Callstack ) ;
2020-02-22 12:38:09 +00:00
MemWrite ( & item - > callstack . ptr , ( uint64_t ) ptr ) ;
2020-01-19 14:06:11 +00:00
TracyLfqCommit ;
2018-06-21 22:56:01 +00:00
# endif
}
2020-01-25 15:51:17 +00:00
static tracy_force_inline void ParameterRegister ( ParameterCallback cb ) { GetProfiler ( ) . m_paramCallback = cb ; }
static tracy_force_inline void ParameterSetup ( uint32_t idx , const char * name , bool isBool , int32_t val )
{
TracyLfqPrepare ( QueueType : : ParamSetup ) ;
tracy : : MemWrite ( & item - > paramSetup . idx , idx ) ;
tracy : : MemWrite ( & item - > paramSetup . name , ( uint64_t ) name ) ;
tracy : : MemWrite ( & item - > paramSetup . isBool , ( uint8_t ) isBool ) ;
tracy : : MemWrite ( & item - > paramSetup . val , val ) ;
# ifdef TRACY_ON_DEMAND
GetProfiler ( ) . DeferItem ( * item ) ;
# endif
TracyLfqCommit ;
}
2019-11-25 22:59:48 +00:00
2019-07-29 22:42:31 +00:00
void SendCallstack ( int depth , const char * skipBefore ) ;
2019-03-05 01:15:13 +00:00
static void CutCallstack ( void * callstack , const char * skipBefore ) ;
2018-08-20 20:20:44 +00:00
2017-09-14 17:23:50 +00:00
static bool ShouldExit ( ) ;
2018-07-10 19:50:00 +00:00
# ifdef TRACY_ON_DEMAND
2019-06-09 15:15:47 +00:00
tracy_force_inline bool IsConnected ( ) const
2018-07-10 19:50:00 +00:00
{
2019-06-09 14:48:00 +00:00
return m_isConnected . load ( std : : memory_order_acquire ) ;
2018-07-10 19:50:00 +00:00
}
2018-07-11 10:21:39 +00:00
2019-06-09 15:15:47 +00:00
tracy_force_inline uint64_t ConnectionId ( ) const
{
return m_connectionId . load ( std : : memory_order_acquire ) ;
}
2018-07-11 10:21:39 +00:00
tracy_force_inline void DeferItem ( const QueueItem & item )
{
m_deferredLock . lock ( ) ;
auto dst = m_deferredQueue . push_next ( ) ;
memcpy ( dst , & item , sizeof ( item ) ) ;
m_deferredLock . unlock ( ) ;
}
2018-07-10 19:50:00 +00:00
# endif
2018-08-20 19:49:23 +00:00
void RequestShutdown ( ) { m_shutdown . store ( true , std : : memory_order_relaxed ) ; m_shutdownManual . store ( true , std : : memory_order_relaxed ) ; }
2018-08-19 23:02:27 +00:00
bool HasShutdownFinished ( ) const { return m_shutdownFinished . load ( std : : memory_order_relaxed ) ; }
2019-08-16 17:22:23 +00:00
void SendString ( uint64_t ptr , const char * str , QueueType type ) ;
2019-12-05 23:15:46 +00:00
// Allocated source location data layout:
// 4b payload size
// 4b color
// 4b source line
// fsz function name
// 1b null terminator
// ssz source file name
// 1b null terminator
// nsz zone name (optional)
static tracy_force_inline uint64_t AllocSourceLocation ( uint32_t line , const char * source , const char * function )
{
2020-06-20 14:31:12 +00:00
return AllocSourceLocation ( line , source , function , nullptr , 0 ) ;
2019-12-05 23:15:46 +00:00
}
static tracy_force_inline uint64_t AllocSourceLocation ( uint32_t line , const char * source , const char * function , const char * name , size_t nameSz )
{
2020-06-20 14:31:12 +00:00
return AllocSourceLocation ( line , source , strlen ( source ) , function , strlen ( function ) , name , nameSz ) ;
}
static tracy_force_inline uint64_t AllocSourceLocation ( uint32_t line , const char * source , size_t sourceSz , const char * function , size_t functionSz )
{
return AllocSourceLocation ( line , source , sourceSz , function , functionSz , nullptr , 0 ) ;
}
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 )
{
const uint32_t sz = uint32_t ( 4 + 4 + 4 + functionSz + 1 + sourceSz + 1 + nameSz ) ;
2019-12-05 23:15:46 +00:00
auto ptr = ( char * ) tracy_malloc ( sz ) ;
memcpy ( ptr , & sz , 4 ) ;
memset ( ptr + 4 , 0 , 4 ) ;
memcpy ( ptr + 8 , & line , 4 ) ;
2020-06-20 14:31:12 +00:00
memcpy ( ptr + 12 , function , functionSz ) ;
ptr [ 12 + functionSz ] = ' \0 ' ;
memcpy ( ptr + 12 + functionSz + 1 , source , sourceSz ) ;
ptr [ 12 + functionSz + 1 + sourceSz ] = ' \0 ' ;
if ( nameSz ! = 0 )
{
memcpy ( ptr + 12 + functionSz + 1 + sourceSz + 1 , name , nameSz ) ;
}
2019-12-05 23:15:46 +00:00
return uint64_t ( ptr ) ;
}
2017-09-10 15:43:56 +00:00
private :
2019-11-14 17:24:29 +00:00
enum class DequeueStatus { DataDequeued , ConnectionLost , QueueEmpty } ;
2017-10-18 16:48:51 +00:00
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 ( ) ;
2019-06-26 20:57:24 +00:00
static void LaunchCompressWorker ( void * ptr ) { ( ( Profiler * ) ptr ) - > CompressWorker ( ) ; }
void CompressWorker ( ) ;
2018-07-13 18:01:27 +00:00
void ClearQueues ( tracy : : moodycamel : : ConsumerToken & token ) ;
2019-08-14 20:39:12 +00:00
void ClearSerial ( ) ;
2018-07-13 18:01:27 +00:00
DequeueStatus Dequeue ( tracy : : moodycamel : : ConsumerToken & token ) ;
2019-08-14 21:06:13 +00:00
DequeueStatus DequeueContextSwitches ( tracy : : moodycamel : : ConsumerToken & token , int64_t & timeStop ) ;
2018-04-01 18:04:35 +00:00
DequeueStatus DequeueSerial ( ) ;
2017-11-11 13:16:37 +00:00
bool CommitData ( ) ;
2020-02-23 13:44:19 +00:00
tracy_force_inline bool AppendData ( const void * data , size_t len )
{
const auto ret = NeedDataSize ( len ) ;
AppendDataUnsafe ( data , len ) ;
return ret ;
}
tracy_force_inline bool NeedDataSize ( size_t len )
{
assert ( len < = TargetFrameSize ) ;
bool ret = true ;
if ( m_bufferOffset - m_bufferStart + len > TargetFrameSize )
{
ret = CommitData ( ) ;
}
return ret ;
}
2017-10-18 16:48:51 +00:00
2018-06-23 00:16:58 +00:00
tracy_force_inline void AppendDataUnsafe ( const void * data , size_t len )
{
memcpy ( m_buffer + m_bufferOffset , data , len ) ;
m_bufferOffset + = int ( len ) ;
}
2017-09-14 17:07:56 +00:00
bool SendData ( const char * data , size_t len ) ;
2019-06-06 22:22:00 +00:00
void SendLongString ( uint64_t ptr , const char * str , size_t len , 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 ) ;
2020-02-22 13:05:01 +00:00
void SendCallstackPayload64 ( uint64_t ptr ) ;
2019-02-28 19:30:07 +00:00
void SendCallstackAlloc ( uint64_t ptr ) ;
2018-06-19 23:06:31 +00:00
void SendCallstackFrame ( uint64_t ptr ) ;
2020-04-01 19:43:03 +00:00
void SendCodeLocation ( uint64_t ptr ) ;
2017-09-21 23:54:04 +00:00
bool HandleServerQuery ( ) ;
2019-08-01 21:14:09 +00:00
void HandleDisconnect ( ) ;
2019-11-25 22:59:48 +00:00
void HandleParameter ( uint64_t payload ) ;
2020-02-26 21:35:15 +00:00
void HandleSymbolQuery ( uint64_t symbol ) ;
2020-03-25 19:04:55 +00:00
void HandleSymbolCodeQuery ( uint64_t symbol , uint32_t size ) ;
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 ( ) ;
2019-11-29 17:29:09 +00:00
void ReportTopology ( ) ;
2017-09-23 19:33:05 +00:00
2018-06-22 21:00:03 +00:00
static tracy_force_inline void SendCallstackMemory ( void * ptr )
2018-06-20 21:30:19 +00:00
{
# ifdef TRACY_HAS_CALLSTACK
2019-02-19 17:38:08 +00:00
auto item = GetProfiler ( ) . m_serialQueue . prepare_next ( ) ;
2018-06-20 21:30:19 +00:00
MemWrite ( & item - > hdr . type , QueueType : : CallstackMemory ) ;
MemWrite ( & item - > callstackMemory . ptr , ( uint64_t ) ptr ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialQueue . commit_next ( ) ;
2018-06-20 21:30:19 +00:00
# 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 ) ;
2019-02-19 17:38:08 +00:00
auto item = GetProfiler ( ) . m_serialQueue . prepare_next ( ) ;
2018-06-20 21:29:44 +00:00
MemWrite ( & item - > hdr . type , type ) ;
MemWrite ( & item - > memAlloc . time , GetTime ( ) ) ;
MemWrite ( & item - > memAlloc . thread , thread ) ;
MemWrite ( & item - > memAlloc . ptr , ( uint64_t ) ptr ) ;
2018-08-01 12:07:30 +00:00
if ( compile_time_condition < sizeof ( size ) = = 4 > : : value )
2018-06-20 21:29:44 +00:00
{
memcpy ( & item - > memAlloc . size , & size , 4 ) ;
memset ( & item - > memAlloc . size + 4 , 0 , 2 ) ;
}
else
{
assert ( sizeof ( size ) = = 8 ) ;
2020-04-13 11:45:21 +00:00
memcpy ( & item - > memAlloc . size , & size , 4 ) ;
memcpy ( ( ( char * ) & item - > memAlloc . size ) + 4 , ( ( char * ) & size ) + 4 , 2 ) ;
2018-06-20 21:29:44 +00:00
}
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialQueue . commit_next ( ) ;
2018-06-20 21:29:44 +00:00
}
static tracy_force_inline void SendMemFree ( QueueType type , const uint64_t thread , const void * ptr )
{
assert ( type = = QueueType : : MemFree | | type = = QueueType : : MemFreeCallstack ) ;
2019-02-19 17:38:08 +00:00
auto item = GetProfiler ( ) . m_serialQueue . prepare_next ( ) ;
2018-06-20 21:29:44 +00:00
MemWrite ( & item - > hdr . type , type ) ;
MemWrite ( & item - > memFree . time , GetTime ( ) ) ;
MemWrite ( & item - > memFree . thread , thread ) ;
MemWrite ( & item - > memFree . ptr , ( uint64_t ) ptr ) ;
2019-02-19 17:38:08 +00:00
GetProfiler ( ) . m_serialQueue . commit_next ( ) ;
2018-06-20 21:29:44 +00:00
}
2020-04-07 20:01:31 +00:00
# if ( defined _WIN32 || defined __CYGWIN__ ) && defined TRACY_TIMER_QPC
static int64_t GetTimeQpc ( ) ;
# endif
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 ;
2018-08-20 19:49:23 +00:00
std : : atomic < bool > m_shutdownManual ;
2018-08-19 23:02:27 +00:00
std : : atomic < bool > m_shutdownFinished ;
2017-10-18 17:49:17 +00:00
Socket * m_sock ;
2019-06-17 00:25:09 +00:00
UdpBroadcast * m_broadcast ;
2018-07-13 21:55:40 +00:00
bool m_noExit ;
2020-03-08 15:14:36 +00:00
uint32_t m_userPort ;
2019-01-14 21:23:24 +00:00
std : : atomic < uint32_t > m_zoneId ;
2020-02-25 22:08:52 +00:00
int64_t m_samplingPeriod ;
2017-09-17 11:10:42 +00:00
2019-08-02 18:18:08 +00:00
uint64_t m_threadCtx ;
2019-10-23 22:04:31 +00:00
int64_t m_refTimeThread ;
int64_t m_refTimeSerial ;
2019-10-25 17:13:11 +00:00
int64_t m_refTimeCtx ;
2019-10-25 17:52:01 +00:00
int64_t m_refTimeGpu ;
2019-08-02 18:18:08 +00:00
2019-05-01 10:57:42 +00:00
void * m_stream ; // LZ4_stream_t*
2017-09-17 11:10:42 +00:00
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
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-07-13 22:39:01 +00:00
TracyMutex m_serialLock ;
2018-07-10 19:50:00 +00:00
2019-06-26 20:50:56 +00:00
FastVector < FrameImageQueueItem > m_fiQueue , m_fiDequeue ;
TracyMutex m_fiLock ;
2019-06-26 21:18:30 +00:00
std : : atomic < uint64_t > m_frameCount ;
2018-07-10 19:50:00 +00:00
# ifdef TRACY_ON_DEMAND
std : : atomic < bool > m_isConnected ;
2019-06-09 15:15:47 +00:00
std : : atomic < uint64_t > m_connectionId ;
2018-07-11 10:14:28 +00:00
2018-07-13 22:39:01 +00:00
TracyMutex m_deferredLock ;
2018-07-11 10:14:28 +00:00
FastVector < QueueItem > m_deferredQueue ;
2018-07-10 19:50:00 +00:00
# endif
2019-02-21 20:59:02 +00:00
# ifdef TRACY_HAS_SYSTIME
void ProcessSysTime ( ) ;
SysTime m_sysTime ;
uint64_t m_sysTimeLast = 0 ;
# else
void ProcessSysTime ( ) { }
# endif
2019-11-25 22:59:48 +00:00
ParameterCallback m_paramCallback ;
2017-09-10 15:43:56 +00:00
} ;
2020-05-10 13:32:39 +00:00
}
2017-09-10 15:43:56 +00:00
# endif