Compare commits

..

7 Commits

Author SHA1 Message Date
Bartosz Taudul
7d475c3022 Reverse drawing order. 2019-08-06 17:08:54 +02:00
Bartosz Taudul
e7acf05a71 Better layout. 2019-08-06 16:29:01 +02:00
Bartosz Taudul
41c45e2d2b Draw mesh debug. 2019-08-06 16:20:40 +02:00
Bartosz Taudul
d4db8e2512 Save/load mesh data. 2019-08-06 11:44:05 +02:00
Bartosz Taudul
a25f541297 Associate mesh data with frames. 2019-08-05 16:58:20 +02:00
Bartosz Taudul
abacf6302b Push mesh triangles into staging vector. 2019-08-05 16:49:45 +02:00
Bartosz Taudul
5d673eb8f2 Add 2D mesh debug interface. 2019-08-05 16:47:20 +02:00
15 changed files with 325 additions and 53 deletions

5
NEWS
View File

@@ -6,12 +6,9 @@ Note: Release numbers are nothing more than numbers. There are some
"missing" versions due to trace file changes during development. This is not
a mistake.
v0.5 (2019-08-10)
v0.5 (xxxx-xx-xx)
-----------------
This is the last release which will be able to load pre-v0.4 traces. Use the
update utility to convert your old traces now!
- Major decrease of trace dump file size.
- Major optimizations across the board.
- Vcpkg is now used for library management on Windows.

View File

@@ -24,8 +24,7 @@ The following platforms are confirmed to be working (this is not a complete list
[Introduction to Tracy Profiler v0.2](https://www.youtube.com/watch?v=fB5B46lbapc)
[New features in Tracy Profiler v0.3](https://www.youtube.com/watch?v=3SXpDpDh2Uo)
[New features in Tracy Profiler v0.4](https://www.youtube.com/watch?v=eAkgkaO8B9o)
[New features in Tracy Profiler v0.5](https://www.youtube.com/watch?v=P6E7qLMmzTQ)
[New features in Tracy Profiler v0.4](https://www.youtube.com/watch?v=eAkgkaO8B9o)
[A quick FAQ.](FAQ.md)
[List of changes.](NEWS)

View File

@@ -58,11 +58,15 @@
#define TracyAllocS(x,y,z)
#define TracyFreeS(x,y)
#define TracyMeshTri(v0,v1,v2,v3,v4,v5)
#define TracyMeshEnd
#else
#include "client/TracyLock.hpp"
#include "client/TracyProfiler.hpp"
#include "client/TracyScoped.hpp"
#include "client/TracyMesh.hpp"
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define ZoneNamed( varname, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
@@ -143,6 +147,9 @@
# define TracyFreeS( ptr, depth ) TracyFree( ptr )
#endif
#define TracyMeshTri( x0, y0, x1, y1, x2, y2 ) tracy::mesh::MeshTri( x0, y0, x1, y1, x2, y2 )
#define TracyMeshEnd tracy::mesh::MeshEnd();
#endif
#endif

40
client/TracyMesh.hpp Normal file
View File

@@ -0,0 +1,40 @@
#ifndef __TRACYMESH_HPP__
#define __TRACYMESH_HPP__
#include "TracyProfiler.hpp"
namespace tracy
{
namespace mesh
{
static void MeshTri( float x0, float y0, float x1, float y1, float x2, float y2 )
{
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::MeshTri );
MemWrite( &item->meshTri.x0, x0 );
MemWrite( &item->meshTri.y0, y0 );
MemWrite( &item->meshTri.x1, x1 );
MemWrite( &item->meshTri.y1, y1 );
MemWrite( &item->meshTri.x2, x2 );
MemWrite( &item->meshTri.y2, y2 );
tail.store( magic + 1, std::memory_order_release );
}
static void MeshEnd()
{
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::MeshEnd );
tail.store( magic + 1, std::memory_order_release );
}
}
}
#endif

View File

@@ -245,35 +245,7 @@ static inline void CpuId( uint32_t* regs, uint32_t leaf )
static void InitFailure( const char* msg )
{
#if defined _WIN32 || defined __CYGWIN__
bool hasConsole = false;
bool reopen = false;
const auto attached = AttachConsole( ATTACH_PARENT_PROCESS );
if( attached )
{
hasConsole = true;
reopen = true;
}
else
{
const auto err = GetLastError();
if( err == ERROR_ACCESS_DENIED )
{
hasConsole = true;
}
}
if( hasConsole )
{
fprintf( stderr, "Tracy Profiler initialization failure: %s\n", msg );
if( reopen )
{
freopen( "CONOUT$", "w", stderr );
fprintf( stderr, "Tracy Profiler initialization failure: %s\n", msg );
}
}
else
{
MessageBoxA( nullptr, msg, "Tracy Profiler initialization failure", MB_ICONSTOP );
}
MessageBoxA( nullptr, msg, "Tracy Profiler initialization failure", MB_ICONSTOP );
#else
fprintf( stderr, "Tracy Profiler initialization failure: %s\n", msg );
#endif
@@ -286,14 +258,7 @@ static int64_t SetupHwTimer()
CpuId( regs, 0x80000001 );
if( !( regs[3] & ( 1 << 27 ) ) ) InitFailure( "CPU doesn't support RDTSCP instruction." );
CpuId( regs, 0x80000007 );
if( !( regs[3] & ( 1 << 8 ) ) )
{
const char* noCheck = getenv( "TRACY_NO_INVARIANT_CHECK" );
if( !noCheck || noCheck[0] != '1' )
{
InitFailure( "CPU doesn't support invariant TSC.\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*." );
}
}
if( !( regs[3] & ( 1 << 8 ) ) ) InitFailure( "CPU doesn't support invariant TSC." );
return Profiler::GetTime();
}

View File

@@ -9,7 +9,7 @@
namespace tracy
{
enum : uint32_t { ProtocolVersion = 14 };
enum : uint32_t { ProtocolVersion = 15 };
enum : uint32_t { BroadcastVersion = 0 };
using lz4sz_t = uint32_t;

View File

@@ -56,6 +56,8 @@ enum class QueueType : uint8_t
CallstackFrameSize,
CallstackFrame,
SysTimeReport,
MeshTri,
MeshEnd,
StringData,
ThreadName,
CustomStringData,
@@ -297,6 +299,13 @@ struct QueueSysTime
float sysTime;
};
struct QueueMeshTri
{
float x0, y0;
float x1, y1;
float x2, y2;
};
struct QueueHeader
{
union
@@ -342,6 +351,7 @@ struct QueueItem
QueueCallstackFrame callstackFrame;
QueueCrashReport crashReport;
QueueSysTime sysTime;
QueueMeshTri meshTri;
};
};
#pragma pack()
@@ -399,6 +409,8 @@ static const size_t QueueDataSize[] = {
sizeof( QueueHeader ) + sizeof( QueueCallstackFrameSize ),
sizeof( QueueHeader ) + sizeof( QueueCallstackFrame ),
sizeof( QueueHeader ) + sizeof( QueueSysTime ),
sizeof( QueueHeader ) + sizeof( QueueMeshTri ),
sizeof( QueueHeader ), // mesh end
// keep all QueueStringTransfer below
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // string data
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // thread name

View File

@@ -188,7 +188,7 @@ The Microsoft compiler is very insistent on writing the CPU core identifier to t
\subsubsection{Misinformation about \texttt{rdtscp}}
In various internet sources you can find warnings that the \texttt{rdtscp} readings are not reliable, can vary between CPU cores, or can be affected by the CPU frequency adjustments. While this was a sound advice a long time ago, it is no longer valid since the Intel Sandy Bridge microarchitecture (released in 2011) introduced \emph{invariant TSC}. Tracy will check for this feature and refuse to run, if it is not found\footnote{Invariant TSC might be not available in specific scenarios, e.g. in some virtual environments. You may set the environment variable \texttt{TRACY\_NO\_INVARIANT\_CHECK=1} to skip this check, \emph{only if you know what you are doing}.}.
In various internet sources you can find warnings that the \texttt{rdtscp} readings are not reliable, can vary between CPU cores, or can be affected by the CPU frequency adjustments. While this was a sound advice a long time ago, it is no longer valid since the Intel Sandy Bridge microarchitecture (released in 2011) introduced \emph{invariant TSC}. Tracy will check for this feature and refuse to run, if it is not found.
While there could be a timer dispatch function, similar to the one on ARM CPUs, it would incur additional cost, which would be paid by everyone, while benefiting (almost) no one. If need be, an optional macro should be added to enable such dispatch.

View File

@@ -404,10 +404,6 @@ int main( int argc, char** argv )
{
OpenWebpage( "https://www.youtube.com/watch?v=eAkgkaO8B9o" );
}
if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.5" ) )
{
OpenWebpage( "https://www.youtube.com/watch?v=P6E7qLMmzTQ" );
}
ImGui::EndPopup();
}
ImGui::Separator();

View File

@@ -221,6 +221,16 @@ struct CrashEvent
enum { CrashEventSize = sizeof( CrashEvent ) };
struct MeshTriangle
{
float x0, y0;
float x1, y1;
float x2, y2;
};
enum { MeshTriangleSize = sizeof( MeshTriangle ) };
#pragma pack()
@@ -325,6 +335,7 @@ struct FrameEvent
int64_t start;
int64_t end;
int32_t frameImage;
Vector<Vector<MeshTriangle>> mesh;
};
struct FrameData

View File

@@ -6,8 +6,8 @@ namespace tracy
namespace Version
{
enum { Major = 0 };
enum { Minor = 5 };
enum { Patch = 0 };
enum { Minor = 4 };
enum { Patch = 11 };
}
}

View File

@@ -717,6 +717,7 @@ bool View::DrawImpl()
if( m_goToFrame ) DrawGoToFrame();
if( m_lockInfoWindow != InvalidId ) DrawLockInfoWindow();
if( m_showPlayback ) DrawPlayback();
if( m_meshDebug >= 0 ) DrawMeshDebug();
if( m_zoomAnim.active )
{
@@ -5964,10 +5965,24 @@ void View::DrawMessages()
}
m_visibleMessages = msgcnt;
if( ImGui::GetScrollY() >= ImGui::GetScrollMaxY() )
if( !filterActive )
{
ImGui::SetScrollHereY( 1.f );
const auto maxScroll = ImGui::GetScrollMaxY();
if( maxScroll != 0 )
{
const auto msgssize = msgs.size();
if( m_prevMessages == msgssize && !m_messageFilterWasActive )
{
m_messagesScrollBottom = ImGui::GetScrollY() == maxScroll;
}
else
{
m_prevMessages = msgssize;
if( m_messagesScrollBottom ) ImGui::SetScrollHereY();
}
}
}
m_messageFilterWasActive = filterActive;
ImGui::EndColumns();
ImGui::EndChild();
@@ -9555,9 +9570,178 @@ void View::DrawPlayback()
ImGui::SameLine();
ImGui::Checkbox( "Zoom 2x", &m_playback.zoom );
TextFocused( "Timestamp:", TimeToString( tstart - m_worker.GetTimeBegin() ) );
const auto& frame = m_worker.GetFramesBase()->frames[fi->frameRef];
if( !frame.mesh.empty() )
{
if( ImGui::Button( "Mesh debug" ) )
{
m_meshDebug = fi->frameRef;
m_meshDrawList = ~0;
}
}
ImGui::End();
}
const uint32_t MeshColors[6] = {
0xFFFF8888,
0xFF88FF88,
0xFF8888FF,
0xFFAAAAAA,
0xFFFFFF44,
0xFFFF44FF
};
static ImVec2 GetRegionRect()
{
const auto region = ImGui::GetContentRegionAvail();
const auto v = std::min( region.x, region.y );
return ImVec2( v, v );
}
void View::DrawMeshDebug()
{
assert( m_meshDebug >= 0 );
bool show = true;
ImGui::Begin( "Mesh debug", &show );
ImGui::Columns( 2 );
TextFocused( "Mesh debug frame", RealToString( m_meshDebug, true ) );
TextFocused( "X range", RealToString( m_meshx1 - m_meshx0, true ) );
TextFocused( "Y range", RealToString( m_meshy1 - m_meshy0, true ) );
const auto& meshList = m_worker.GetFramesBase()->frames[m_meshDebug].mesh;
assert( !meshList.empty() );
const auto msz = meshList.size();
for( size_t i=0; i<msz; i++ )
{
const auto bit = 1 << i;
bool enabled = m_meshDrawList & bit;
char buf[128];
sprintf( buf, "Mesh %llu (%llu tris)", i, meshList[i].size() );
SmallCheckbox( buf, &enabled );
if( enabled ) { m_meshDrawList |= bit; } else { m_meshDrawList &= ~bit; }
}
if( ImGui::SmallButton( "Auto fit" ) )
{
float minx = std::numeric_limits<float>::max();
float miny = std::numeric_limits<float>::max();
float maxx = std::numeric_limits<float>::min();
float maxy = std::numeric_limits<float>::min();
int bit = 1;
for( auto& mesh : meshList )
{
if( m_meshDrawList & bit )
{
for( auto& tri : mesh )
{
minx = std::min( { minx, tri.x0, tri.x1, tri.x2 } );
maxx = std::max( { maxx, tri.x0, tri.x1, tri.x2 } );
miny = std::min( { miny, tri.y0, tri.y1, tri.y2 } );
maxy = std::max( { maxy, tri.y0, tri.y1, tri.y2 } );
}
}
bit <<= 1;
}
const auto dx = maxx - minx;
const auto dy = maxy - miny;
const auto dd = std::max( dx, dy ) * 0.5f;
const auto ax = ( minx + maxx ) * 0.5f;
const auto ay = ( miny + maxy ) * 0.5f;
m_meshx0 = ax - dd;
m_meshx1 = ax + dd;
m_meshy0 = ay - dd;
m_meshy1 = ay + dd;
}
ImGui::NextColumn();
auto& io = ImGui::GetIO();
auto draw = ImGui::GetWindowDrawList();
const auto wpos = ImGui::GetWindowPos() + ImGui::GetCursorPos();
const auto region = GetRegionRect();
draw->AddRectFilled( wpos, wpos + region, 0xFF444444 );
draw->PushClipRect( wpos, wpos + region, true );
if( ImGui::IsMouseHoveringRect( wpos, wpos + region ) )
{
const auto px = ( m_meshx1 - m_meshx0 ) / region.x;
if( ImGui::IsMouseDragging( 1, 0 ) )
{
auto delta = ImGui::GetMouseDragDelta( 1, 0 );
m_meshx0 -= delta.x * px;
m_meshx1 -= delta.x * px;
m_meshy0 -= delta.y * px;
m_meshy1 -= delta.y * px;
io.MouseClickedPos[1] = io.MousePos;
}
const auto wheel = io.MouseWheel;
if( wheel != 0 )
{
const auto mouse = io.MousePos - wpos;
const auto p = ImVec2( mouse.x / region.x, mouse.y / region.y );
const auto xZoomSpan = m_meshx1 - m_meshx0;
const auto yZoomSpan = m_meshy1 - m_meshy0;
const auto p1x = xZoomSpan * p.x;
const auto p2x = xZoomSpan - p1x;
const auto p1y = yZoomSpan * p.y;
const auto p2y = yZoomSpan - p1y;
if( wheel > 0 )
{
m_meshx0 += p1x * 0.25;
m_meshx1 -= p2x * 0.25;
m_meshy0 += p1y * 0.25;
m_meshy1 -= p2y * 0.25;
}
else
{
m_meshx0 -= p1x * 0.25;
m_meshx1 += p2x * 0.25;
m_meshy0 -= p1y * 0.25;
m_meshy1 += p2y * 0.25;
}
}
}
const auto mulx = region.x / ( m_meshx1 - m_meshx0 );
const auto muly = region.y / ( m_meshy1 - m_meshy0 );
for( int idx=meshList.size()-1; idx>=0; idx-- )
{
if( m_meshDrawList & ( 1 << idx ) )
{
for( auto& tri : meshList[idx] )
{
const auto x0 = ( tri.x0 - m_meshx0 ) * mulx;
const auto x1 = ( tri.x1 - m_meshx0 ) * mulx;
const auto x2 = ( tri.x2 - m_meshx0 ) * mulx;
const auto y0 = ( tri.y0 - m_meshy0 ) * muly;
const auto y1 = ( tri.y1 - m_meshy0 ) * muly;
const auto y2 = ( tri.y2 - m_meshy0 ) * muly;
const auto col = MeshColors[idx%6];
draw->AddLine( wpos + ImVec2( x0, y0 ), wpos + ImVec2( x1, y1 ), col );
draw->AddLine( wpos + ImVec2( x1, y1 ), wpos + ImVec2( x2, y2 ), col );
draw->AddLine( wpos + ImVec2( x2, y2 ), wpos + ImVec2( x0, y0 ), col );
}
}
}
draw->PopClipRect();
ImGui::NextColumn();
ImGui::EndColumns();
ImGui::End();
if( !show ) m_meshDebug = -1;
}
template<class T>
void View::ListMemData( T ptr, T end, std::function<void(T&)> DrawAddress, const char* id, int64_t startTime )
{

View File

@@ -133,6 +133,7 @@ private:
void DrawGoToFrame();
void DrawLockInfoWindow();
void DrawPlayback();
void DrawMeshDebug();
template<class T>
void ListMemData( T ptr, T end, std::function<void(T&)> DrawAddress, const char* id = nullptr, int64_t startTime = -1 );
@@ -267,7 +268,9 @@ private:
ZoneEvent* m_zoneHover = nullptr;
int m_frameHover = -1;
bool m_messagesScrollBottom;
size_t m_prevMessages = 0;
ImGuiTextFilter m_messageFilter;
bool m_messageFilterWasActive = false;
int m_visibleMessages = 0;
bool m_disconnectIssued = false;
@@ -540,6 +543,13 @@ private:
bool sync = false;
bool zoom = false;
} m_playback;
int m_meshDebug = -1;
uint64_t m_meshDrawList;
double m_meshx0 = -1;
double m_meshy0 = -1;
double m_meshx1 = 1;
double m_meshy1 = 1;
};
}

View File

@@ -394,15 +394,28 @@ Worker::Worker( FileRead& f, EventType::Type eventMask )
{
for( uint64_t j=0; j<fsz; j++ )
{
new(&ptr->frames[j].mesh) Vector<Vector<MeshTriangle>>();
ptr->frames[j].start = ReadTimeOffset( f, refTime );
ptr->frames[j].end = -1;
f.Read( &ptr->frames[j].frameImage, sizeof( int32_t ) );
uint64_t msz;
f.Read( &msz, sizeof( msz ) );
for( uint64_t k=0; k<msz; k++ )
{
Vector<MeshTriangle> mesh;
uint64_t dsz;
f.Read( &dsz, sizeof( dsz ) );
mesh.reserve_exact( dsz, m_slab );
f.Read( mesh.data(), sizeof( MeshTriangle ) * dsz );
ptr->frames[j].mesh.push_back( std::move( mesh ) );
}
}
}
else
{
for( uint64_t j=0; j<fsz; j++ )
{
new(&ptr->frames[j].mesh) Vector<Vector<MeshTriangle>>();
ptr->frames[j].start = ReadTimeOffset( f, refTime );
ptr->frames[j].end = ReadTimeOffset( f, refTime );
f.Read( &ptr->frames[j].frameImage, sizeof( int32_t ) );
@@ -2780,6 +2793,12 @@ bool Worker::Process( const QueueItem& ev )
case QueueType::SysTimeReport:
ProcessSysTime( ev.sysTime );
break;
case QueueType::MeshEnd:
ProcessMeshEnd();
break;
case QueueType::MeshTri:
ProcessMeshTri( ev.meshTri );
break;
default:
assert( false );
break;
@@ -3804,6 +3823,26 @@ void Worker::ProcessSysTime( const QueueSysTime& ev )
}
}
void Worker::ProcessMeshEnd()
{
auto& mesh = m_data.framesBase->frames.back().mesh.push_next();
const auto sz = m_data.meshStaging.size();
mesh.reserve_exact( sz, m_slab );
memcpy( mesh.data(), m_data.meshStaging.data(), sizeof( MeshTriangle ) * sz );
m_data.meshStaging.clear();
}
void Worker::ProcessMeshTri( const QueueMeshTri& ev )
{
auto& tri = m_data.meshStaging.push_next();
tri.x0 = ev.x0;
tri.y0 = ev.y0;
tri.x1 = ev.x1;
tri.y1 = ev.y1;
tri.x2 = ev.x2;
tri.y2 = ev.y2;
}
void Worker::MemAllocChanged( int64_t time )
{
const auto val = (double)m_data.memory.usage;
@@ -4252,6 +4291,14 @@ void Worker::Write( FileWrite& f )
{
WriteTimeOffset( f, refTime, fe.start );
f.Write( &fe.frameImage, sizeof( fe.frameImage ) );
sz = fe.mesh.size();
f.Write( &sz, sizeof( sz ) );
for( auto& mesh : fe.mesh )
{
sz = mesh.size();
f.Write( &sz, sizeof( sz ) );
f.Write( mesh.data(), sizeof( MeshTriangle ) * sz );
}
}
}
else

View File

@@ -188,6 +188,8 @@ private:
Vector<StringRef> appInfo;
CrashEvent crashEvent;
Vector<MeshTriangle> meshStaging;
};
struct MbpsBlock
@@ -406,6 +408,8 @@ private:
tracy_force_inline void ProcessCallstackFrame( const QueueCallstackFrame& ev );
tracy_force_inline void ProcessCrashReport( const QueueCrashReport& ev );
tracy_force_inline void ProcessSysTime( const QueueSysTime& ev );
tracy_force_inline void ProcessMeshEnd();
tracy_force_inline void ProcessMeshTri( const QueueMeshTri& ev );
tracy_force_inline void ProcessZoneBeginImpl( ZoneEvent* zone, const QueueZoneBegin& ev );
tracy_force_inline void ProcessZoneBeginAllocSrcLocImpl( ZoneEvent* zone, const QueueZoneBegin& ev );