tracy/client/TracyProfiler.hpp

334 lines
10 KiB
C++
Raw Normal View History

2017-09-10 15:43:56 +00:00
#ifndef __TRACYPROFILER_HPP__
#define __TRACYPROFILER_HPP__
#include <atomic>
#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
#include "concurrentqueue.h"
#include "TracyCallstack.hpp"
2018-04-01 17:53:05 +00:00
#include "TracyFastVector.hpp"
#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"
#include "../common/TracyAlign.hpp"
#include "../common/TracyAlloc.hpp"
2017-11-11 18:44:09 +00:00
#include "../common/TracySystem.hpp"
2017-09-10 18:09:14 +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
# define TRACY_HW_TIMER
# 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
#endif
2017-09-10 15:43:56 +00:00
namespace tracy
{
class Socket;
struct SourceLocation
{
const char* name;
const char* function;
const char* file;
uint32_t line;
uint32_t color;
};
2017-10-10 23:44:35 +00:00
struct ProducerWrapper
{
moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* ptr;
};
extern thread_local ProducerWrapper s_token;
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();
static tracy_force_inline int64_t GetTime( uint32_t& cpu )
{
#ifdef TRACY_HW_TIMER
2018-04-27 14:58:45 +00:00
# if __ARM_ARCH >= 6
cpu = 0xFFFFFFFF;
2018-04-27 14:58:45 +00:00
return GetTimeImpl();
# elif defined _MSC_VER || defined __CYGWIN__
const auto t = int64_t( __rdtscp( &cpu ) );
2017-10-01 17:11:01 +00:00
return t;
# elif defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
uint32_t eax, edx;
asm volatile ( "rdtscp" : "=a" (eax), "=d" (edx), "=c" (cpu) :: );
return ( uint64_t( edx ) << 32 ) + uint64_t( eax );
# 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
}
static tracy_force_inline int64_t GetTime()
{
#ifdef TRACY_HW_TIMER
2018-04-27 14:58:45 +00:00
# if __ARM_ARCH >= 6
return GetTimeImpl();
# elif defined _MSC_VER || defined __CYGWIN__
2018-04-26 14:12:52 +00:00
unsigned int dontcare;
const auto t = int64_t( __rdtscp( &dontcare ) );
return t;
# elif defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
uint32_t eax, edx;
2017-10-29 15:20:07 +00:00
asm volatile ( "rdtscp" : "=a" (eax), "=d" (edx) :: "%ecx" );
return ( uint64_t( edx ) << 32 ) + uint64_t( eax );
# endif
#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: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 );
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-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 );
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 );
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 );
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;
auto& token = s_token.ptr;
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 );
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 );
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 )
{
const auto thread = GetThreadHandle();
s_profiler.m_serialLock.lock();
auto item = s_profiler.m_serialQueue.push_next();
2018-03-31 19:56:05 +00:00
MemWrite( &item->hdr.type, QueueType::MemAlloc );
MemWrite( &item->memAlloc.time, GetTime() );
MemWrite( &item->memAlloc.thread, thread );
2018-03-31 19:56:05 +00:00
MemWrite( &item->memAlloc.ptr, (uint64_t)ptr );
2018-04-14 14:08:39 +00:00
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 );
}
s_profiler.m_serialLock.unlock();
2018-03-31 19:56:05 +00:00
}
static tracy_force_inline void MemFree( const void* ptr )
{
const auto thread = GetThreadHandle();
s_profiler.m_serialLock.lock();
auto item = s_profiler.m_serialQueue.push_next();
2018-03-31 19:56:05 +00:00
MemWrite( &item->hdr.type, QueueType::MemFree );
MemWrite( &item->memFree.time, GetTime() );
MemWrite( &item->memFree.thread, thread );
2018-03-31 19:56:05 +00:00
MemWrite( &item->memFree.ptr, (uint64_t)ptr );
s_profiler.m_serialLock.unlock();
2018-03-31 19:56:05 +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();
auto item = s_profiler.m_serialQueue.push_next();
MemWrite( &item->hdr.type, QueueType::MemAllocCallstack );
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 );
}
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();
auto item = s_profiler.m_serialQueue.push_next();
MemWrite( &item->hdr.type, QueueType::MemFreeCallstack );
MemWrite( &item->memFree.time, GetTime() );
MemWrite( &item->memFree.thread, thread );
MemWrite( &item->memFree.ptr, (uint64_t)ptr );
SendCallstackMemory( depth );
s_profiler.m_serialLock.unlock();
}
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
}
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 };
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();
bool AppendData( const void* data, size_t len );
bool CommitData();
bool NeedDataSize( size_t len );
2017-10-18 16:48:51 +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 );
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 );
bool HandleServerQuery();
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
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;
std::atomic<int64_t> m_timeBegin;
2017-09-22 23:37:07 +00:00
uint64_t m_mainThread;
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;
LZ4_stream_t* m_stream;
char* m_buffer;
int m_bufferOffset;
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
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