Merge branch 'memory'

This commit is contained in:
Bartosz Taudul 2018-04-05 18:57:55 +02:00
commit a319ce13e9
19 changed files with 880 additions and 34 deletions

View File

@ -29,6 +29,9 @@
#define TracyMessage(x,y)
#define TracyMessageL(x)
#define TracyAlloc(x,y)
#define TracyFree(x)
#else
#include "client/TracyLock.hpp"
@ -57,6 +60,9 @@
#define TracyMessage( txt, size ) tracy::Profiler::Message( txt, size );
#define TracyMessageL( txt ) tracy::Profiler::Message( txt );
#define TracyAlloc( ptr, size ) tracy::Profiler::MemAlloc( ptr, size );
#define TracyFree( ptr ) tracy::Profiler::MemFree( ptr );
#endif
#endif

View File

@ -144,7 +144,9 @@
<ClInclude Include="..\..\..\common\TracyQueue.hpp" />
<ClInclude Include="..\..\..\common\TracySocket.hpp" />
<ClInclude Include="..\..\..\common\TracySystem.hpp" />
<ClInclude Include="..\..\..\common\tracy_benaphore.h" />
<ClInclude Include="..\..\..\common\tracy_lz4.hpp" />
<ClInclude Include="..\..\..\common\tracy_sema.h" />
<ClInclude Include="..\..\..\server\TracyCharUtil.hpp" />
<ClInclude Include="..\..\..\server\TracyEvent.hpp" />
<ClInclude Include="..\..\..\server\TracyFileWrite.hpp" />
@ -153,9 +155,7 @@
<ClInclude Include="..\..\..\server\TracySlab.hpp" />
<ClInclude Include="..\..\..\server\TracyVector.hpp" />
<ClInclude Include="..\..\..\server\TracyWorker.hpp" />
<ClInclude Include="..\..\..\server\tracy_benaphore.h" />
<ClInclude Include="..\..\..\server\tracy_flat_hash_map.hpp" />
<ClInclude Include="..\..\..\server\tracy_sema.h" />
<ClInclude Include="..\..\src\getopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -59,15 +59,9 @@
<ClInclude Include="..\..\..\common\TracySystem.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_benaphore.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_flat_hash_map.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_sema.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyCharUtil.hpp">
<Filter>server</Filter>
</ClInclude>
@ -98,5 +92,11 @@
<ClInclude Include="..\..\..\common\TracyAlign.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_benaphore.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_sema.h">
<Filter>common</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -9,7 +9,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "../../server/tracy_benaphore.h"
#include "../../server/TracyFileWrite.hpp"
#include "../../server/TracyMemory.hpp"
#include "../../server/TracyWorker.hpp"

View File

@ -0,0 +1,88 @@
#ifndef __TRACYFASTVECTOR_HPP__
#define __TRACYFASTVECTOR_HPP__
#include <stddef.h>
#include "../common/TracyAlloc.hpp"
#include "../common/TracyForceInline.hpp"
namespace tracy
{
template<typename T>
class FastVector
{
public:
using iterator = T*;
using const_iterator = const T*;
FastVector( size_t capacity )
: m_ptr( (T*)tracy_malloc( sizeof( T ) * capacity ) )
, m_size( 0 )
, m_capacity( capacity )
{
}
FastVector( const FastVector& ) = delete;
FastVector( FastVector&& ) = delete;
~FastVector()
{
tracy_free( m_ptr );
}
FastVector& operator=( const FastVector& ) = delete;
FastVector& operator=( FastVector&& ) = delete;
bool empty() const { return m_size == 0; }
size_t size() const { return m_size; }
T* data() { return m_ptr; }
const T* data() const { return m_ptr; };
T* begin() { return m_ptr; }
const T* begin() const { return m_ptr; }
T* end() { return m_ptr + m_size; }
const T* end() const { return m_ptr + m_size; }
T& front() { assert( m_size > 0 ); return m_ptr[0]; }
const T& front() const { assert( m_size > 0 ); return m_ptr[0]; }
T& back() { assert( m_size > 0 ); return m_ptr[m_size - 1]; }
const T& back() const { assert( m_size > 0 ); return m_ptr[m_size - 1]; }
T& operator[]( size_t idx ) { return m_ptr[idx]; }
const T& operator[]( size_t idx ) const { return m_ptr[idx]; }
T* push_next()
{
T* ret;
if( m_size == m_capacity ) AllocMore();
ret = m_ptr + m_size;
m_size++;
return ret;
}
void clear()
{
m_size = 0;
}
private:
tracy_no_inline void AllocMore()
{
m_capacity *= 2;
T* ptr = (T*)tracy_malloc( sizeof( T ) * m_capacity );
memcpy( ptr, m_ptr, m_size * sizeof( T ) );
tracy_free( m_ptr );
m_ptr = ptr;
}
T* m_ptr;
size_t m_size;
size_t m_capacity;
};
}
#endif

View File

@ -16,6 +16,7 @@
#include <chrono>
#include <limits>
#include <memory>
#include <mutex>
#include <stdlib.h>
#include <string.h>
@ -108,7 +109,7 @@ struct ThreadNameData;
std::atomic<ThreadNameData*> init_order(104) s_threadNameData( nullptr );
#endif
static Profiler init_order(105) s_profiler;
Profiler init_order(105) s_profiler;
enum { BulkSize = TargetFrameSize / QueueItemSize };
@ -125,6 +126,7 @@ Profiler::Profiler()
, m_bufferStart( 0 )
, m_itemBuf( (QueueItem*)tracy_malloc( sizeof( QueueItem ) * BulkSize ) )
, m_lz4Buf( (char*)tracy_malloc( LZ4Size + sizeof( lz4sz_t ) ) )
, m_serialQueue( 1024*1024 )
{
assert( !s_instance );
s_instance = this;
@ -212,11 +214,12 @@ void Profiler::Worker()
for(;;)
{
const auto status = Dequeue( token );
if( status == ConnectionLost )
const auto serialStatus = DequeueSerial();
if( status == ConnectionLost || serialStatus == ConnectionLost )
{
break;
}
else if( status == QueueEmpty )
else if( status == QueueEmpty && serialStatus == QueueEmpty )
{
if( ShouldExit() ) break;
if( m_bufferOffset != m_bufferStart ) CommitData();
@ -234,11 +237,12 @@ void Profiler::Worker()
for(;;)
{
const auto status = Dequeue( token );
if( status == ConnectionLost )
const auto serialStatus = DequeueSerial();
if( status == ConnectionLost || serialStatus == ConnectionLost )
{
break;
}
else if( status == QueueEmpty )
else if( status == QueueEmpty && serialStatus == QueueEmpty )
{
if( m_bufferOffset != m_bufferStart ) CommitData();
break;
@ -266,6 +270,7 @@ void Profiler::Worker()
}
}
while( Dequeue( token ) == Success ) {}
while( DequeueSerial() == Success ) {}
if( m_bufferOffset != m_bufferStart )
{
if( !CommitData() ) return;
@ -325,6 +330,29 @@ Profiler::DequeueStatus Profiler::Dequeue( moodycamel::ConsumerToken& token )
return Success;
}
Profiler::DequeueStatus Profiler::DequeueSerial()
{
std::lock_guard<NonRecursiveBenaphore> lock( m_serialLock );
const auto sz = m_serialQueue.size();
if( sz > 0 )
{
auto item = m_serialQueue.data();
auto end = item + sz;
while( item != end )
{
const auto idx = MemRead<uint8_t>( &item->hdr.idx );
if( !AppendData( item, QueueDataSize[idx] ) ) return ConnectionLost;
item++;
}
m_serialQueue.clear();
}
else
{
return QueueEmpty;
}
return Success;
}
bool Profiler::AppendData( const void* data, size_t len )
{
auto ret = true;

View File

@ -7,7 +7,9 @@
#include <string.h>
#include "concurrentqueue.h"
#include "TracyFastVector.hpp"
#include "../common/tracy_lz4.hpp"
#include "../common/tracy_benaphore.h"
#include "../common/TracyQueue.hpp"
#include "../common/TracyAlign.hpp"
#include "../common/TracyAlloc.hpp"
@ -50,6 +52,9 @@ struct GpuCtxWrapper
using Magic = moodycamel::ConcurrentQueueDefaultTraits::index_t;
class Profiler;
extern Profiler s_profiler;
class Profiler
{
public:
@ -186,6 +191,33 @@ public:
tail.store( magic + 1, std::memory_order_release );
}
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();
MemWrite( &item->hdr.type, QueueType::MemAlloc );
MemWrite( &item->memAlloc.time, GetTime() );
MemWrite( &item->memAlloc.thread, thread );
MemWrite( &item->memAlloc.ptr, (uint64_t)ptr );
memcpy( &item->memAlloc.size, &size, 6 );
s_profiler.m_serialLock.unlock();
}
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();
MemWrite( &item->hdr.type, QueueType::MemFree );
MemWrite( &item->memFree.time, GetTime() );
MemWrite( &item->memFree.thread, thread );
MemWrite( &item->memFree.ptr, (uint64_t)ptr );
s_profiler.m_serialLock.unlock();
}
static bool ShouldExit();
private:
@ -195,6 +227,7 @@ private:
void Worker();
DequeueStatus Dequeue( moodycamel::ConsumerToken& token );
DequeueStatus DequeueSerial();
bool AppendData( const void* data, size_t len );
bool CommitData();
bool NeedDataSize( size_t len );
@ -225,6 +258,9 @@ private:
QueueItem* m_itemBuf;
char* m_lz4Buf;
FastVector<QueueItem> m_serialQueue;
NonRecursiveBenaphore m_serialLock;
};
};

View File

@ -31,6 +31,8 @@ enum class QueueType : uint8_t
GpuZoneEnd,
GpuTime,
GpuResync,
MemAlloc,
MemFree,
StringData,
ThreadName,
CustomStringData,
@ -187,6 +189,21 @@ struct QueueGpuResync
uint16_t context;
};
struct QueueMemAlloc
{
int64_t time;
uint64_t thread;
uint64_t ptr;
char size[6];
};
struct QueueMemFree
{
int64_t time;
uint64_t thread;
uint64_t ptr;
};
struct QueueHeader
{
union
@ -219,6 +236,8 @@ struct QueueItem
QueueGpuZoneEnd gpuZoneEnd;
QueueGpuTime gpuTime;
QueueGpuResync gpuResync;
QueueMemAlloc memAlloc;
QueueMemFree memFree;
};
};
@ -251,6 +270,8 @@ static const size_t QueueDataSize[] = {
sizeof( QueueHeader ) + sizeof( QueueGpuZoneEnd ),
sizeof( QueueHeader ) + sizeof( QueueGpuTime ),
sizeof( QueueHeader ) + sizeof( QueueGpuResync ),
sizeof( QueueHeader ) + sizeof( QueueMemAlloc ),
sizeof( QueueHeader ) + sizeof( QueueMemFree ),
// keep all QueueStringTransfer below
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // string data
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // thread name

View File

@ -30,9 +30,16 @@ namespace tracy
// Semaphore (Windows)
//---------------------------------------------------------
#include <windows.h>
#undef min
#undef max
#ifndef MAXLONG
enum { MAXLONG = 0x7fffffff };
enum { INFINITE = 0xFFFFFFFF };
typedef void* HANDLE;
extern "C" __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA( void*, long, long, const char* );
extern "C" __declspec(dllimport) int __stdcall CloseHandle( HANDLE );
extern "C" __declspec(dllimport) unsigned long __stdcall WaitForSingleObject( HANDLE, unsigned long );
extern "C" __declspec(dllimport) int __stdcall ReleaseSemaphore( HANDLE, long, long* );
#endif
class Semaphore
{
@ -46,7 +53,7 @@ public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
m_hSema = CreateSemaphore(NULL, initialCount, MAXLONG, NULL);
m_hSema = CreateSemaphoreA(NULL, initialCount, MAXLONG, NULL);
}
~Semaphore()

View File

@ -137,6 +137,20 @@ struct GpuEvent
enum { GpuEventSize = sizeof( GpuEvent ) };
static_assert( std::is_standard_layout<GpuEvent>::value, "GpuEvent is not standard layout" );
struct MemEvent
{
uint64_t ptr;
uint64_t size;
int64_t timeAlloc;
uint16_t threadAlloc;
int64_t timeFree;
uint16_t threadFree;
};
enum { MemEventSize = sizeof( MemEvent ) };
static_assert( std::is_standard_layout<MemEvent>::value, "MemEvent is not standard layout" );
#pragma pack()
@ -208,6 +222,15 @@ struct PlotData
uint64_t postponeTime;
};
struct MemData
{
Vector<MemEvent> data;
flat_hash_map<uint64_t, size_t, nohash<uint64_t>> active;
uint64_t high = std::numeric_limits<uint64_t>::min();
uint64_t low = std::numeric_limits<uint64_t>::max();
uint64_t usage = 0;
};
struct StringLocation
{
const char* ptr;

View File

@ -38,12 +38,24 @@ public:
}
}
bool IsEOF()
{
if( m_lastBlock != BufSize && m_offset == m_lastBlock ) return true;
if( m_offset == BufSize )
{
if( fseek( m_file, 1, SEEK_CUR ) != 0 ) return true;
fseek( m_file, -1, SEEK_CUR );
}
return false;
}
private:
FileRead( FILE* f )
: m_stream( LZ4_createStreamDecode() )
, m_file( f )
, m_offset( BufSize )
, m_active( 1 )
, m_lastBlock( 0 )
{}
tracy_force_inline void ReadSmall( void* ptr, size_t size )
@ -65,7 +77,7 @@ private:
uint32_t sz;
fread( &sz, 1, sizeof( sz ), m_file );
fread( m_lz4buf, 1, sz, m_file );
LZ4_decompress_safe_continue( m_stream, m_lz4buf, m_buf[m_active], sz, BufSize );
m_lastBlock = LZ4_decompress_safe_continue( m_stream, m_lz4buf, m_buf[m_active], sz, BufSize );
}
const auto sz = std::min( size, BufSize - m_offset );
@ -84,6 +96,7 @@ private:
char m_buf[2][BufSize];
size_t m_offset;
uint8_t m_active;
int m_lastBlock;
};
}

View File

@ -94,6 +94,12 @@ public:
m_ptr[m_size++] = std::move( v );
}
T& push_next()
{
if( m_size == Capacity() ) AllocMore();
return m_ptr[m_size++];
}
T* insert( T* it, const T& v )
{
assert( it >= m_ptr && it <= m_ptr + m_size );

View File

@ -307,6 +307,8 @@ void View::DrawImpl()
ImGui::SameLine();
if( ImGui::Button( "Statistics", ImVec2( bw, 0 ) ) ) m_showStatistics = true;
ImGui::SameLine();
if( ImGui::Button( "Memory", ImVec2( bw, 0 ) ) ) m_memInfo.show = true;
ImGui::SameLine();
ImGui::Text( "Frames: %-7" PRIu64 " Time span: %-10s View span: %-10s Zones: %-13s Queue delay: %s Timer resolution: %s", m_worker.GetFrameCount(), TimeToString( m_worker.GetLastTime() - m_worker.GetFrameBegin( 0 ) ), TimeToString( m_zvEnd - m_zvStart ), RealToString( m_worker.GetZoneCount(), true ), TimeToString( m_worker.GetDelay() ), TimeToString( m_worker.GetResolution() ) );
DrawFrames();
DrawZones();
@ -321,6 +323,7 @@ void View::DrawImpl()
if( m_showMessages ) DrawMessages();
if( m_findZone.show ) DrawFindZone();
if( m_showStatistics ) DrawStatistics();
if( m_memInfo.show ) DrawMemory();
if( m_zoomAnim.active )
{
@ -1089,6 +1092,13 @@ void View::DrawZones()
auto& io = ImGui::GetIO();
draw->AddLine( ImVec2( io.MousePos.x, linepos.y ), ImVec2( io.MousePos.x, linepos.y + lineh ), 0x33FFFFFF );
}
if( m_memInfo.show && m_memInfo.restrictTime )
{
const auto zvMid = ( m_zvEnd - m_zvStart ) / 2;
auto& io = ImGui::GetIO();
draw->AddLine( ImVec2( wpos.x + zvMid * pxns, linepos.y ), ImVec2( wpos.x + zvMid * pxns, linepos.y + lineh ), 0x88FF44FF );
}
}
int View::DrawZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, const ImVec2& wpos, int _offset, int depth )
@ -2508,7 +2518,7 @@ void View::DrawZoneInfoWindow()
cti[i] = uint32_t( i );
}
std::sort( cti.get(), cti.get() + ev.child.size(), [&ctt] ( const auto& lhs, const auto& rhs ) { return ctt[lhs] > ctt[rhs]; } );
pdqsort_branchless( cti.get(), cti.get() + ev.child.size(), [&ctt] ( const auto& lhs, const auto& rhs ) { return ctt[lhs] > ctt[rhs]; } );
if( !ev.child.empty() )
{
@ -2667,7 +2677,7 @@ void View::DrawGpuInfoWindow()
cti[i] = uint32_t( i );
}
std::sort( cti.get(), cti.get() + ev.child.size(), [&ctt] ( const auto& lhs, const auto& rhs ) { return ctt[lhs] > ctt[rhs]; } );
pdqsort_branchless( cti.get(), cti.get() + ev.child.size(), [&ctt] ( const auto& lhs, const auto& rhs ) { return ctt[lhs] > ctt[rhs]; } );
if( !ev.child.empty() )
{
@ -3481,7 +3491,7 @@ void View::DrawFindZone()
}
if( m_findZone.sortByCounts )
{
std::sort( threads.begin(), threads.end(), []( const auto& lhs, const auto& rhs ) { return lhs->second.size() > rhs->second.size(); } );
pdqsort_branchless( threads.begin(), threads.end(), []( const auto& lhs, const auto& rhs ) { return lhs->second.size() > rhs->second.size(); } );
}
ImGui::BeginChild( "##zonesScroll", ImVec2( ImGui::GetWindowContentRegionWidth(), std::max( 200.f, ImGui::GetContentRegionAvail().y ) ) );
@ -3647,6 +3657,481 @@ void View::DrawStatistics()
ImGui::End();
}
template<class T>
void View::ListMemData( T ptr, T end, std::function<const MemEvent*(T&)> DrawAddress )
{
ImGui::BeginChild( "##memScroll", ImVec2( 0, std::max( 200.f, ImGui::GetContentRegionAvail().y ) ) );
ImGui::Columns( 7 );
ImGui::Text( "Address" );
ImGui::NextColumn();
ImGui::Text( "Size" );
ImGui::NextColumn();
ImGui::Text( "Appeared at" );
ImGui::NextColumn();
ImGui::Text( "Duration" );
ImGui::SameLine();
ImGui::TextDisabled( "(?)" );
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::Text( "Active allocations are displayed using green color." );
ImGui::EndTooltip();
}
ImGui::NextColumn();
ImGui::Text( "Thread" );
ImGui::SameLine();
ImGui::TextDisabled( "(?)" );
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::Text( "Shows one thread if alloc and free was performed on the same thread." );
ImGui::Text( "Otherwise two threads are displayed in order: alloc, free." );
ImGui::EndTooltip();
}
ImGui::NextColumn();
ImGui::Text( "Zone alloc" );
ImGui::NextColumn();
ImGui::Text( "Zone free" );
ImGui::SameLine();
ImGui::TextDisabled( "(?)" );
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::Text( "If alloc and free is performed in the same zone, it is displayed in yellow color." );
ImGui::EndTooltip();
}
ImGui::NextColumn();
ImGui::Separator();
int idx = 0;
while( ptr != end )
{
auto v = DrawAddress( ptr );
ImGui::NextColumn();
ImGui::Text( "%s", RealToString( v->size, true ) );
ImGui::NextColumn();
ImGui::Text( "%s", TimeToString( v->timeAlloc - m_worker.GetFrameBegin( 0 ) ) );
ImGui::NextColumn();
if( v->timeFree < 0 )
{
ImGui::TextColored( ImVec4( 0.6f, 1.f, 0.6f, 1.f ), "%s", TimeToString( m_worker.GetLastTime() - v->timeAlloc ) );
ImGui::NextColumn();
ImGui::Text( "%s", m_worker.GetThreadString( m_worker.DecompressThread( v->threadAlloc ) ) );
}
else
{
ImGui::Text( "%s", TimeToString( v->timeFree - v->timeAlloc ) );
ImGui::NextColumn();
ImGui::Text( "%s", m_worker.GetThreadString( m_worker.DecompressThread( v->threadAlloc ) ) );
if( v->threadAlloc != v->threadFree )
{
ImGui::Text( "%s", m_worker.GetThreadString( m_worker.DecompressThread( v->threadFree ) ) );
}
}
ImGui::NextColumn();
auto zone = FindZoneAtTime( m_worker.DecompressThread( v->threadAlloc ), v->timeAlloc );
if( !zone )
{
ImGui::Text( "-" );
}
else
{
const auto& srcloc = m_worker.GetSourceLocation( zone->srcloc );
const auto txt = srcloc.name.active ? m_worker.GetString( srcloc.name ) : m_worker.GetString( srcloc.function );
ImGui::PushID( idx++ );
auto sel = ImGui::Selectable( txt, m_zoneInfoWindow == zone );
auto hover = ImGui::IsItemHovered();
ImGui::PopID();
if( sel )
{
m_zoneInfoWindow = zone;
}
if( hover )
{
m_zoneHighlight = zone;
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToZone( *zone );
}
ZoneTooltip( *zone );
}
}
ImGui::NextColumn();
if( v->timeFree < 0 )
{
ImGui::TextColored( ImVec4( 0.6f, 1.f, 0.6f, 1.f ), "active" );
}
else
{
auto zoneFree = FindZoneAtTime( m_worker.DecompressThread( v->threadFree ), v->timeFree );
if( !zoneFree )
{
ImGui::Text( "-" );
}
else
{
const auto& srcloc = m_worker.GetSourceLocation( zoneFree->srcloc );
const auto txt = srcloc.name.active ? m_worker.GetString( srcloc.name ) : m_worker.GetString( srcloc.function );
ImGui::PushID( idx++ );
bool sel;
if( zoneFree == zone )
{
sel = ImGui::Selectable( "", m_zoneInfoWindow == zoneFree );
ImGui::SameLine();
ImGui::TextColored( ImVec4( 1.f, 1.f, 0.6f, 1.f ), txt );
}
else
{
sel = ImGui::Selectable( txt, m_zoneInfoWindow == zoneFree );
}
auto hover = ImGui::IsItemHovered();
ImGui::PopID();
if( sel )
{
m_zoneInfoWindow = zoneFree;
}
if( hover )
{
m_zoneHighlight = zoneFree;
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToZone( *zoneFree );
}
ZoneTooltip( *zoneFree );
}
}
}
ImGui::NextColumn();
ptr++;
}
ImGui::EndColumns();
ImGui::EndChild();
}
enum { ChunkBits = 10 };
enum { PageBits = 10 };
enum { PageSize = 1 << PageBits };
enum { PageChunkBits = ChunkBits + PageBits };
enum { PageChunkSize = 1 << PageChunkBits };
uint32_t MemDecayColor[256] = {
0x0, 0xFF077F07, 0xFF078007, 0xFF078207, 0xFF078307, 0xFF078507, 0xFF078707, 0xFF078807,
0xFF078A07, 0xFF078B07, 0xFF078D07, 0xFF078F07, 0xFF079007, 0xFF089208, 0xFF089308, 0xFF089508,
0xFF089708, 0xFF089808, 0xFF089A08, 0xFF089B08, 0xFF089D08, 0xFF089F08, 0xFF08A008, 0xFF08A208,
0xFF09A309, 0xFF09A509, 0xFF09A709, 0xFF09A809, 0xFF09AA09, 0xFF09AB09, 0xFF09AD09, 0xFF09AF09,
0xFF09B009, 0xFF09B209, 0xFF09B309, 0xFF09B509, 0xFF0AB70A, 0xFF0AB80A, 0xFF0ABA0A, 0xFF0ABB0A,
0xFF0ABD0A, 0xFF0ABF0A, 0xFF0AC00A, 0xFF0AC20A, 0xFF0AC30A, 0xFF0AC50A, 0xFF0AC70A, 0xFF0BC80B,
0xFF0BCA0B, 0xFF0BCB0B, 0xFF0BCD0B, 0xFF0BCF0B, 0xFF0BD00B, 0xFF0BD20B, 0xFF0BD30B, 0xFF0BD50B,
0xFF0BD70B, 0xFF0BD80B, 0xFF0BDA0B, 0xFF0CDB0C, 0xFF0CDD0C, 0xFF0CDF0C, 0xFF0CE00C, 0xFF0CE20C,
0xFF0CE30C, 0xFF0CE50C, 0xFF0CE70C, 0xFF0CE80C, 0xFF0CEA0C, 0xFF0CEB0C, 0xFF0DED0D, 0xFF0DEF0D,
0xFF0DF00D, 0xFF0DF20D, 0xFF0DF30D, 0xFF0DF50D, 0xFF0DF70D, 0xFF0DF80D, 0xFF0DFA0D, 0xFF0DFB0D,
0xFF0DFD0D, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E,
0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0EFF0E, 0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F,
0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F, 0xFF0FFF0F,
0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF10FF10,
0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF10FF10, 0xFF11FF11, 0xFF11FF11, 0xFF11FF11, 0xFF11FF11,
0xFF11FF11, 0xFF11FF11, 0xFF11FF11, 0xFF11FF11, 0xFF11FF11, 0xFF11FF11, 0xFF11FF11, 0xFF12FF12,
0x0, 0xFF1212FF, 0xFF1111FF, 0xFF1111FF, 0xFF1111FF, 0xFF1111FF, 0xFF1111FF, 0xFF1111FF,
0xFF1111FF, 0xFF1111FF, 0xFF1111FF, 0xFF1111FF, 0xFF1111FF, 0xFF1010FF, 0xFF1010FF, 0xFF1010FF,
0xFF1010FF, 0xFF1010FF, 0xFF1010FF, 0xFF1010FF, 0xFF1010FF, 0xFF1010FF, 0xFF1010FF, 0xFF1010FF,
0xFF1010FF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF,
0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0F0FFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF,
0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF, 0xFF0E0EFF,
0xFF0D0DFD, 0xFF0D0DFB, 0xFF0D0DFA, 0xFF0D0DF8, 0xFF0D0DF7, 0xFF0D0DF5, 0xFF0D0DF3, 0xFF0D0DF2,
0xFF0D0DF0, 0xFF0D0DEF, 0xFF0D0DED, 0xFF0C0CEB, 0xFF0C0CEA, 0xFF0C0CE8, 0xFF0C0CE7, 0xFF0C0CE5,
0xFF0C0CE3, 0xFF0C0CE2, 0xFF0C0CE0, 0xFF0C0CDF, 0xFF0C0CDD, 0xFF0C0CDB, 0xFF0B0BDA, 0xFF0B0BD8,
0xFF0B0BD7, 0xFF0B0BD5, 0xFF0B0BD3, 0xFF0B0BD2, 0xFF0B0BD0, 0xFF0B0BCF, 0xFF0B0BCD, 0xFF0B0BCB,
0xFF0B0BCA, 0xFF0B0BC8, 0xFF0A0AC7, 0xFF0A0AC5, 0xFF0A0AC3, 0xFF0A0AC2, 0xFF0A0AC0, 0xFF0A0ABF,
0xFF0A0ABD, 0xFF0A0ABB, 0xFF0A0ABA, 0xFF0A0AB8, 0xFF0A0AB7, 0xFF0909B5, 0xFF0909B3, 0xFF0909B2,
0xFF0909B0, 0xFF0909AF, 0xFF0909AD, 0xFF0909AB, 0xFF0909AA, 0xFF0909A8, 0xFF0909A7, 0xFF0909A5,
0xFF0909A3, 0xFF0808A2, 0xFF0808A0, 0xFF08089F, 0xFF08089D, 0xFF08089B, 0xFF08089A, 0xFF080898,
0xFF080897, 0xFF080895, 0xFF080893, 0xFF080892, 0xFF070790, 0xFF07078F, 0xFF07078D, 0xFF07078B,
0xFF07078A, 0xFF070788, 0xFF070787, 0xFF070785, 0xFF070783, 0xFF070782, 0xFF070780, 0xFF07077F,
};
void View::DrawMemory()
{
auto& mem = m_worker.GetMemData();
ImGui::Begin( "Memory", &m_memInfo.show );
ImGui::Text( "Total allocations: %-15s Active allocations: %-15s Memory usage: %-15s Memory span: %s",
RealToString( mem.data.size(), true ),
RealToString( mem.active.size(), true ),
RealToString( mem.usage, true ),
RealToString( mem.high - mem.low, true ) );
ImGui::InputText( "", m_memInfo.pattern, 1024 );
ImGui::SameLine();
if( ImGui::Button( "Find" ) )
{
m_memInfo.ptrFind = strtoull( m_memInfo.pattern, nullptr, 0 );
}
ImGui::SameLine();
if( ImGui::Button( "Clear" ) )
{
m_memInfo.ptrFind = 0;
m_memInfo.pattern[0] = '\0';
}
ImGui::SameLine();
ImGui::Checkbox( "Restrict time", &m_memInfo.restrictTime );
ImGui::SameLine();
ImGui::TextDisabled( "(?)" );
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::Text( "Don't show allocations beyond the middle of timeline display." );
ImGui::EndTooltip();
}
const auto zvMid = m_zvStart + ( m_zvEnd - m_zvStart ) / 2;
ImGui::Separator();
if( ImGui::TreeNodeEx( "Allocations", ImGuiTreeNodeFlags_DefaultOpen ) )
{
if( m_memInfo.ptrFind != 0 )
{
std::vector<const MemEvent*> match;
match.reserve( mem.active.size() ); // heuristic
if( m_memInfo.restrictTime )
{
for( auto& v : mem.data )
{
if( v.ptr <= m_memInfo.ptrFind && v.ptr + v.size > m_memInfo.ptrFind && v.timeAlloc < zvMid )
{
match.emplace_back( &v );
}
}
}
else
{
for( auto& v : mem.data )
{
if( v.ptr <= m_memInfo.ptrFind && v.ptr + v.size > m_memInfo.ptrFind )
{
match.emplace_back( &v );
}
}
}
if( match.empty() )
{
ImGui::Text( "Found no allocations at given address" );
}
else
{
ImGui::SameLine();
ImGui::TextDisabled( "(%s)", RealToString( match.size(), true ) );
ListMemData<decltype( match.begin() )>( match.begin(), match.end(), [this]( auto& it ) {
auto& v = *it;
if( v->ptr == m_memInfo.ptrFind )
{
ImGui::Text( "0x%" PRIx64, m_memInfo.ptrFind );
}
else
{
ImGui::Text( "0x%" PRIx64 "+%" PRIu64, v->ptr, m_memInfo.ptrFind - v->ptr );
}
return v;
} );
}
}
ImGui::TreePop();
}
ImGui::Separator();
if( ImGui::TreeNode( "Active allocations" ) )
{
uint64_t total = 0;
std::vector<const MemEvent*> items;
items.reserve( mem.active.size() );
if( m_memInfo.restrictTime )
{
for( auto& v : mem.data )
{
if( v.timeAlloc < zvMid && ( v.timeFree > zvMid || v.timeFree < 0 ) )
{
items.emplace_back( &v );
total += v.size;
}
}
}
else
{
auto ptr = mem.data.data();
for( auto& v : mem.active )
{
items.emplace_back( ptr + v.second );
}
pdqsort_branchless( items.begin(), items.end(), []( const auto& lhs, const auto& rhs ) { return lhs->timeAlloc < rhs->timeAlloc; } );
total = mem.usage;
}
ImGui::SameLine();
ImGui::TextDisabled( "(%s)", RealToString( items.size(), true ) );
ImGui::Text( "Memory usage: %s", RealToString( total, true ) );
ListMemData<decltype( items.begin() )>( items.begin(), items.end(), []( auto& v ) {
ImGui::Text( "0x%" PRIx64, (*v)->ptr );
return *v;
} );
ImGui::TreePop();
}
ImGui::Separator();
if( ImGui::TreeNode( "Memory map" ) )
{
ImGui::Text( "Single pixel: %s KB Single line: %s KB", RealToString( ( 1 << ChunkBits ) / 1024, true ), RealToString( PageChunkSize / 1024, true ) );
auto pages = GetMemoryPages();
const int8_t empty[PageSize] = {};
const auto sz = pages.size() / PageSize;
auto pgptr = pages.data();
const auto end = pgptr + sz * PageSize;
size_t lines = sz;
while( pgptr != end )
{
if( memcmp( empty, pgptr, PageSize ) == 0 )
{
pgptr += PageSize;
while( pgptr != end && memcmp( empty, pgptr, PageSize ) == 0 )
{
lines--;
pgptr += PageSize;
}
}
else
{
pgptr += PageSize;
}
}
ImGui::BeginChild( "##memMap", ImVec2( PageSize + 2, lines + 2 ), false );
auto draw = ImGui::GetWindowDrawList();
const auto wpos = ImGui::GetCursorScreenPos() + ImVec2( 1, 1 );
draw->AddRect( wpos - ImVec2( 1, 1 ), wpos + ImVec2( PageSize + 1, lines + 1 ), 0xFF666666 );
draw->AddRectFilled( wpos, wpos + ImVec2( PageSize, lines ), 0xFF444444 );
size_t line = 0;
pgptr = pages.data();
while( pgptr != end )
{
if( memcmp( empty, pgptr, PageSize ) == 0 )
{
pgptr += PageSize;
draw->AddLine( wpos + ImVec2( 0, line ), wpos + ImVec2( PageSize, line ), 0x11000000 );
line++;
while( pgptr != end && memcmp( empty, pgptr, PageSize ) == 0 ) pgptr += PageSize;
}
else
{
size_t idx = 0;
while( idx < PageSize )
{
if( pgptr[idx] == 0 )
{
do
{
idx++;
}
while( idx < PageSize && pgptr[idx] == 0 );
}
else
{
auto val = pgptr[idx];
const auto i0 = idx;
do
{
idx++;
}
while( idx < PageSize && pgptr[idx] == val );
draw->AddLine( wpos + ImVec2( i0, line ), wpos + ImVec2( idx, line ), MemDecayColor[(uint8_t)val] );
}
}
line++;
pgptr += PageSize;
}
}
ImGui::EndChild();
ImGui::TreePop();
}
ImGui::End();
}
Vector<int8_t> View::GetMemoryPages() const
{
Vector<int8_t> ret;
const auto& mem = m_worker.GetMemData();
const auto span = mem.high - mem.low;
const auto pages = ( span / PageChunkSize ) + 1;
ret.reserve_and_use( pages * PageSize );
auto pgptr = ret.data();
memset( pgptr, 0, pages * PageSize );
const auto memlow = mem.low;
if( m_memInfo.restrictTime )
{
const auto zvMid = m_zvStart + ( m_zvEnd - m_zvStart ) / 2;
for( auto& alloc : mem.data )
{
if( m_memInfo.restrictTime && alloc.timeAlloc > zvMid ) break;
const auto a0 = alloc.ptr - memlow;
const auto a1 = a0 + alloc.size;
int8_t val = alloc.timeFree < 0 ?
int8_t( std::max( int64_t( 1 ), 127 - ( ( zvMid - alloc.timeAlloc ) >> 24 ) ) ) :
( alloc.timeFree > zvMid ?
int8_t( std::max( int64_t( 1 ), 127 - ( ( zvMid - alloc.timeAlloc ) >> 24 ) ) ) :
int8_t( -std::max( int64_t( 1 ), 127 - ( ( zvMid - alloc.timeFree ) >> 24 ) ) ) );
const auto c0 = a0 >> ChunkBits;
const auto c1 = a1 >> ChunkBits;
if( c0 == c1 )
{
pgptr[c0] = val;
}
else
{
memset( pgptr + c0, val, c1 - c0 + 1 );
}
}
}
else
{
const auto lastTime = m_worker.GetLastTime();
for( auto& alloc : mem.data )
{
const auto a0 = alloc.ptr - memlow;
const auto a1 = a0 + alloc.size;
const int8_t val = alloc.timeFree < 0 ?
int8_t( std::max( int64_t( 1 ), 127 - ( ( lastTime - std::min( lastTime, alloc.timeAlloc ) ) >> 24 ) ) ) :
int8_t( -std::max( int64_t( 1 ), 127 - ( ( lastTime - std::min( lastTime, alloc.timeFree ) ) >> 24 ) ) );
const auto c0 = a0 >> ChunkBits;
const auto c1 = a1 >> ChunkBits;
if( c0 == c1 )
{
pgptr[c0] = val;
}
else
{
memset( pgptr + c0, val, c1 - c0 + 1 );
}
}
}
return ret;
}
uint32_t View::GetZoneColor( const ZoneEvent& ev )
{
const auto& srcloc = m_worker.GetSourceLocation( ev.srcloc );
@ -3928,6 +4413,34 @@ uint64_t View::GetZoneThread( const GpuEvent& zone ) const
return 0;
}
const ZoneEvent* View::FindZoneAtTime( uint64_t thread, int64_t time ) const
{
// TODO add thread rev-map
ThreadData* td = nullptr;
for( const auto& t : m_worker.GetThreadData() )
{
if( t->id == thread )
{
td = t;
break;
}
}
if( !td ) return nullptr;
const Vector<ZoneEvent*>* timeline = &td->timeline;
if( timeline->empty() ) return nullptr;
ZoneEvent* ret = nullptr;
for(;;)
{
auto it = std::upper_bound( timeline->begin(), timeline->end(), time, [] ( const auto& l, const auto& r ) { return l < r->start; } );
if( it != timeline->begin() ) --it;
if( (*it)->start > time || ( (*it)->end >= 0 && (*it)->end < time ) ) return ret;
ret = *it;
if( (*it)->child.empty() ) return ret;
timeline = &(*it)->child;
}
}
#ifndef TRACY_NO_STATISTICS
void View::FindZones()
{

View File

@ -2,14 +2,15 @@
#define __TRACYVIEW_HPP__
#include <atomic>
#include <functional>
#include <map>
#include <string>
#include <thread>
#include <vector>
#include "../common/tracy_benaphore.h"
#include "TracyVector.hpp"
#include "TracyWorker.hpp"
#include "tracy_benaphore.h"
#include "tracy_flat_hash_map.hpp"
struct ImVec2;
@ -74,6 +75,10 @@ private:
void DrawMessages();
void DrawFindZone();
void DrawStatistics();
void DrawMemory();
template<class T>
void ListMemData( T ptr, T end, std::function<const MemEvent*(T&)> DrawAddress );
void DrawInfoWindow();
void DrawZoneInfoWindow();
@ -98,11 +103,14 @@ private:
const GpuEvent* GetZoneParent( const GpuEvent& zone ) const;
uint64_t GetZoneThread( const ZoneEvent& zone ) const;
uint64_t GetZoneThread( const GpuEvent& zone ) const;
const ZoneEvent* FindZoneAtTime( uint64_t thread, int64_t time ) const;
#ifndef TRACY_NO_STATISTICS
void FindZones();
#endif
Vector<int8_t> GetMemoryPages() const;
flat_hash_map<const void*, bool, nohash<const void*>> m_visible;
flat_hash_map<const void*, bool, nohash<const void*>> m_showFull;
@ -172,13 +180,13 @@ private:
struct {
enum : uint64_t { Unselected = std::numeric_limits<uint64_t>::max() - 1 };
bool show;
bool show = false;
std::vector<int32_t> match;
std::map<uint64_t, Vector<ZoneEvent*>> threads;
size_t processed;
int selMatch = 0;
uint64_t selThread = Unselected;
char pattern[1024] = { "" };
char pattern[1024] = {};
bool logVal = false;
bool logTime = false;
bool cumulateTime = false;
@ -201,6 +209,13 @@ private:
processed = 0;
}
} m_findZone;
struct {
bool show = false;
char pattern[1024] = {};
uint64_t ptrFind = 0;
bool restrictTime = false;
} m_memInfo;
};
}

View File

@ -243,6 +243,35 @@ Worker::Worker( FileRead& f )
f.Read( pd->data.data(), psz * sizeof( PlotItem ) );
m_data.plots.push_back_no_space_check( pd );
}
// Support pre-0.3 traces
if( f.IsEOF() ) return;
f.Read( &sz, sizeof( sz ) );
m_data.memory.data.reserve_and_use( sz );
auto mem = m_data.memory.data.data();
for( uint64_t i=0; i<sz; i++ )
{
f.Read( &mem->ptr, sizeof( mem->ptr ) );
f.Read( &mem->size, sizeof( mem->size ) );
f.Read( &mem->timeAlloc, sizeof( mem->timeAlloc ) );
f.Read( &mem->timeFree, sizeof( mem->timeFree ) );
uint64_t t;
f.Read( &t, sizeof( t ) );
mem->threadAlloc = CompressThread( t );
f.Read( &t, sizeof( t ) );
mem->threadFree = CompressThread( t );
if( mem->timeFree < 0 )
{
m_data.memory.active.emplace( mem->ptr, i );
}
mem++;
}
f.Read( &m_data.memory.high, sizeof( m_data.memory.high ) );
f.Read( &m_data.memory.low, sizeof( m_data.memory.low ) );
f.Read( &m_data.memory.usage, sizeof( m_data.memory.usage ) );
}
Worker::~Worker()
@ -1200,6 +1229,12 @@ void Worker::Process( const QueueItem& ev )
case QueueType::GpuResync:
ProcessGpuResync( ev.gpuResync );
break;
case QueueType::MemAlloc:
ProcessMemAlloc( ev.memAlloc );
break;
case QueueType::MemFree:
ProcessMemFree( ev.memFree );
break;
case QueueType::Terminate:
m_terminate = true;
break;
@ -1625,6 +1660,40 @@ void Worker::ProcessGpuResync( const QueueGpuResync& ev )
}
}
void Worker::ProcessMemAlloc( const QueueMemAlloc& ev )
{
const auto time = TscTime( ev.time );
assert( m_data.memory.active.find( ev.ptr ) == m_data.memory.active.end() );
assert( m_data.memory.data.empty() || m_data.memory.data.back().timeAlloc <= time );
m_data.memory.active.emplace( ev.ptr, m_data.memory.data.size() );
auto& mem = m_data.memory.data.push_next();
mem.ptr = ev.ptr;
mem.size = 0;
memcpy( &mem.size, ev.size, 6 );
mem.timeAlloc = time;
mem.threadAlloc = CompressThread( ev.thread );
mem.timeFree = -1;
mem.threadFree = 0;
m_data.memory.low = std::min( m_data.memory.low, mem.ptr );
m_data.memory.high = std::max( m_data.memory.high, mem.ptr + mem.size );
m_data.memory.usage += mem.size;
}
void Worker::ProcessMemFree( const QueueMemFree& ev )
{
auto it = m_data.memory.active.find( ev.ptr );
assert( it != m_data.memory.active.end() );
auto& mem = m_data.memory.data[it->second];
mem.timeFree = TscTime( ev.time );
mem.threadFree = CompressThread( ev.thread );
m_data.memory.usage -= mem.size;
m_data.memory.active.erase( it );
}
void Worker::ReadTimeline( FileRead& f, Vector<ZoneEvent*>& vec, uint16_t thread )
{
uint64_t sz;
@ -1838,6 +1907,23 @@ void Worker::Write( FileWrite& f )
f.Write( &sz, sizeof( sz ) );
f.Write( plot->data.data(), sizeof( PlotItem ) * sz );
}
sz = m_data.memory.data.size();
f.Write( &sz, sizeof( sz ) );
for( auto& mem : m_data.memory.data )
{
f.Write( &mem.ptr, sizeof( mem.ptr ) );
f.Write( &mem.size, sizeof( mem.size ) );
f.Write( &mem.timeAlloc, sizeof( mem.timeAlloc ) );
f.Write( &mem.timeFree, sizeof( mem.timeFree ) );
uint64_t t = DecompressThread( mem.threadAlloc );
f.Write( &t, sizeof( t ) );
t = DecompressThread( mem.threadFree );
f.Write( &t, sizeof( t ) );
}
f.Write( &m_data.memory.high, sizeof( m_data.memory.high ) );
f.Write( &m_data.memory.low, sizeof( m_data.memory.low ) );
f.Write( &m_data.memory.usage, sizeof( m_data.memory.usage ) );
}
void Worker::WriteTimeline( FileWrite& f, const Vector<ZoneEvent*>& vec )

View File

@ -8,11 +8,11 @@
#include <thread>
#include <vector>
#include "../common/tracy_benaphore.h"
#include "../common/tracy_lz4.hpp"
#include "../common/TracyForceInline.hpp"
#include "../common/TracyQueue.hpp"
#include "../common/TracySocket.hpp"
#include "tracy_benaphore.h"
#include "tracy_flat_hash_map.hpp"
#include "TracyEvent.hpp"
#include "TracySlab.hpp"
@ -57,6 +57,7 @@ class Worker
Vector<MessageData*> messages;
Vector<PlotData*> plots;
Vector<ThreadData*> threads;
MemData memory;
uint64_t zonesCnt;
int64_t lastTime;
@ -113,6 +114,7 @@ public:
const Vector<GpuCtxData*>& GetGpuData() const { return m_data.gpuData; }
const Vector<PlotData*>& GetPlots() const { return m_data.plots; }
const Vector<ThreadData*>& GetThreadData() const { return m_data.threads; }
const MemData& GetMemData() const { return m_data.memory; }
// Some zones may have incomplete timing data (only start time is available, end hasn't arrived yet).
// GetZoneEnd() will try to infer the end time by looking at child zones (parent zone can't end
@ -177,6 +179,8 @@ private:
tracy_force_inline void ProcessGpuZoneEnd( const QueueGpuZoneEnd& ev );
tracy_force_inline void ProcessGpuTime( const QueueGpuTime& ev );
tracy_force_inline void ProcessGpuResync( const QueueGpuResync& ev );
tracy_force_inline void ProcessMemAlloc( const QueueMemAlloc& ev );
tracy_force_inline void ProcessMemFree( const QueueMemFree& ev );
tracy_force_inline void CheckSourceLocation( uint64_t ptr );
void NewSourceLocation( uint64_t ptr );
@ -204,6 +208,7 @@ private:
void InsertPlot( PlotData* plot, int64_t time, double val );
void HandlePlotName( uint64_t name, char* str, size_t sz );
void HandlePostponedPlots();
StringLocation StoreString( char* str, size_t sz );

View File

@ -103,7 +103,9 @@
<ClInclude Include="..\..\..\common\TracyQueue.hpp" />
<ClInclude Include="..\..\..\common\TracySocket.hpp" />
<ClInclude Include="..\..\..\common\TracySystem.hpp" />
<ClInclude Include="..\..\..\common\tracy_benaphore.h" />
<ClInclude Include="..\..\..\common\tracy_lz4.hpp" />
<ClInclude Include="..\..\..\common\tracy_sema.h" />
<ClInclude Include="..\..\..\imgui\imconfig.h" />
<ClInclude Include="..\..\..\imgui\imgui.h" />
<ClInclude Include="..\..\..\imgui\imgui_internal.h" />
@ -124,10 +126,8 @@
<ClInclude Include="..\..\..\server\TracyVector.hpp" />
<ClInclude Include="..\..\..\server\TracyView.hpp" />
<ClInclude Include="..\..\..\server\TracyWorker.hpp" />
<ClInclude Include="..\..\..\server\tracy_benaphore.h" />
<ClInclude Include="..\..\..\server\tracy_flat_hash_map.hpp" />
<ClInclude Include="..\..\..\server\tracy_pdqsort.h" />
<ClInclude Include="..\..\..\server\tracy_sema.h" />
<ClInclude Include="..\..\libs\gl3w\GL\gl3w.h" />
<ClInclude Include="..\..\libs\gl3w\GL\glcorearb.h" />
<ClInclude Include="..\..\src\imgui_impl_glfw_gl3.h" />

View File

@ -146,12 +146,6 @@
<ClInclude Include="..\..\..\server\TracyPopcnt.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_benaphore.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_sema.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_flat_hash_map.hpp">
<Filter>server</Filter>
</ClInclude>
@ -167,6 +161,12 @@
<ClInclude Include="..\..\..\common\TracyAlign.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_benaphore.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_sema.h">
<Filter>imgui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="DebugVis.natvis" />