1
0
mirror of https://github.com/wolfpld/tracy.git synced 2025-03-20 07:40:02 +08:00

Merge branch 'master' into profiler

This commit is contained in:
Tyler Mayoff 2022-08-06 20:10:07 -04:00
commit 864fa54640
No known key found for this signature in database
GPG Key ID: 9318A9286352802A
30 changed files with 3202 additions and 1910 deletions

View File

@ -4,10 +4,12 @@ project(Tracy LANGUAGES CXX)
find_package(Threads REQUIRED)
add_library(TracyClient TracyClient.cpp)
set(TRACY_PUBLIC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/public)
add_library(TracyClient public/TracyClient.cpp)
target_compile_features(TracyClient PUBLIC cxx_std_11)
target_include_directories(TracyClient SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
target_include_directories(TracyClient SYSTEM PUBLIC
$<BUILD_INTERFACE:${TRACY_PUBLIC_DIR}>
$<INSTALL_INTERFACE:include>)
target_link_libraries(
TracyClient
@ -68,60 +70,59 @@ endif()
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
set(includes
${CMAKE_CURRENT_LIST_DIR}/TracyC.h
${CMAKE_CURRENT_LIST_DIR}/Tracy.hpp
${CMAKE_CURRENT_LIST_DIR}/TracyD3D11.hpp
${CMAKE_CURRENT_LIST_DIR}/TracyD3D12.hpp
${CMAKE_CURRENT_LIST_DIR}/TracyLua.hpp
${CMAKE_CURRENT_LIST_DIR}/TracyOpenCL.hpp
${CMAKE_CURRENT_LIST_DIR}/TracyOpenGL.hpp
${CMAKE_CURRENT_LIST_DIR}/TracyVulkan.hpp)
set(tracy_includes
${TRACY_PUBLIC_DIR}/tracy/TracyC.h
${TRACY_PUBLIC_DIR}/tracy/Tracy.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyD3D11.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyD3D12.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyLua.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyOpenCL.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyOpenGL.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyVulkan.hpp)
set(client_includes
${CMAKE_CURRENT_LIST_DIR}/client/tracy_concurrentqueue.h
${CMAKE_CURRENT_LIST_DIR}/client/tracy_rpmalloc.hpp
${CMAKE_CURRENT_LIST_DIR}/client/tracy_SPSCQueue.h
${CMAKE_CURRENT_LIST_DIR}/client/TracyArmCpuTable.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyCallstack.h
${CMAKE_CURRENT_LIST_DIR}/client/TracyCallstack.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyDebug.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyDxt1.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyFastVector.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyLock.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyProfiler.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyRingBuffer.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyScoped.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyStringHelpers.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracySysTime.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracySysTrace.hpp
${CMAKE_CURRENT_LIST_DIR}/client/TracyThread.hpp)
${TRACY_PUBLIC_DIR}/client/tracy_concurrentqueue.h
${TRACY_PUBLIC_DIR}/client/tracy_rpmalloc.hpp
${TRACY_PUBLIC_DIR}/client/tracy_SPSCQueue.h
${TRACY_PUBLIC_DIR}/client/TracyArmCpuTable.hpp
${TRACY_PUBLIC_DIR}/client/TracyCallstack.h
${TRACY_PUBLIC_DIR}/client/TracyCallstack.hpp
${TRACY_PUBLIC_DIR}/client/TracyDebug.hpp
${TRACY_PUBLIC_DIR}/client/TracyDxt1.hpp
${TRACY_PUBLIC_DIR}/client/TracyFastVector.hpp
${TRACY_PUBLIC_DIR}/client/TracyLock.hpp
${TRACY_PUBLIC_DIR}/client/TracyProfiler.hpp
${TRACY_PUBLIC_DIR}/client/TracyRingBuffer.hpp
${TRACY_PUBLIC_DIR}/client/TracyScoped.hpp
${TRACY_PUBLIC_DIR}/client/TracyStringHelpers.hpp
${TRACY_PUBLIC_DIR}/client/TracySysTime.hpp
${TRACY_PUBLIC_DIR}/client/TracySysTrace.hpp
${TRACY_PUBLIC_DIR}/client/TracyThread.hpp)
set(common_includes
${CMAKE_CURRENT_LIST_DIR}/common/tracy_lz4.hpp
${CMAKE_CURRENT_LIST_DIR}/common/tracy_lz4hc.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyAlign.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyAlign.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyAlloc.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyApi.h
${CMAKE_CURRENT_LIST_DIR}/common/TracyColor.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyForceInline.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyMutex.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyProtocol.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyQueue.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracySocket.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyStackFrames.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracySystem.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyUwp.hpp
${CMAKE_CURRENT_LIST_DIR}/common/TracyYield.hpp)
${TRACY_PUBLIC_DIR}/common/tracy_lz4.hpp
${TRACY_PUBLIC_DIR}/common/tracy_lz4hc.hpp
${TRACY_PUBLIC_DIR}/common/TracyAlign.hpp
${TRACY_PUBLIC_DIR}/common/TracyAlloc.hpp
${TRACY_PUBLIC_DIR}/common/TracyApi.h
${TRACY_PUBLIC_DIR}/common/TracyColor.hpp
${TRACY_PUBLIC_DIR}/common/TracyForceInline.hpp
${TRACY_PUBLIC_DIR}/common/TracyMutex.hpp
${TRACY_PUBLIC_DIR}/common/TracyProtocol.hpp
${TRACY_PUBLIC_DIR}/common/TracyQueue.hpp
${TRACY_PUBLIC_DIR}/common/TracySocket.hpp
${TRACY_PUBLIC_DIR}/common/TracyStackFrames.hpp
${TRACY_PUBLIC_DIR}/common/TracySystem.hpp
${TRACY_PUBLIC_DIR}/common/TracyUwp.hpp
${TRACY_PUBLIC_DIR}/common/TracyYield.hpp)
install(TARGETS TracyClient
EXPORT TracyConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${includes}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${tracy_includes}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
install(FILES ${client_includes}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/client)
install(FILES ${common_includes}

7
NEWS
View File

@ -36,6 +36,13 @@ v0.x.x (xxxx-xx-xx)
try to show which versions can be used to handle the connection.
- Messages list in zone info window can now show messages exclusive to the
zone, filtering out the messages emitted from child zones.
- Added capture of vertical synchronization timings on Linux.
- The range of frame bar colors in the frames overview on top of the screen
can be now controlled with the "Target FPS" entry box in the options menu.
- The "Draw frame targets" option does not need to be selected.
- Previously the hardcoded FPS target thresholds were: 30, 60, 144 FPS.
- Currently the FPS target threshold is: half of target, target, twice the
target.
v0.8.2 (2022-06-28)

View File

@ -844,7 +844,7 @@ Wait stacks & \faCheck & \faCheck & \faCheck & \faTimes & \faPoo & \faTimes \\
CPU topology information & \faCheck & \faCheck & \faCheck & \faTimes & \faTimes & \faTimes \\
Call stack sampling & \faCheck & \faCheck & \faCheck & \faTimes & \faPoo & \faTimes \\
Hardware sampling & \faCheck{}\textsuperscript{\emph{a}} & \faCheck & \faCheck & \faTimes & \faPoo & \faTimes \\
VSync capture & \faCheck & \faTimes & \faTimes & \faTimes & \faTimes & \faTimes \\
VSync capture & \faCheck & \faCheck & \faTimes & \faTimes & \faTimes & \faTimes \\
\end{tabular}
\vspace{1em}
@ -2128,7 +2128,7 @@ For proper program code retrieval, you can unload no module used by the applicat
\subsubsection{Vertical synchronization}
On Windows, Tracy will automatically capture hardware Vsync events if running with elevated privileges (see section~\ref{privilegeelevation}). These events will be reported as '\texttt{[x] Vsync}' frame sets, where \texttt{x} is the identifier of a specific monitor. Note that hardware vertical synchronization might not correspond to the one seen by your application due to desktop composition, command queue buffering, etc.
On Windows and Linux, Tracy will automatically capture hardware Vsync events, provided that the application has access to the kernel data (privilege elevation may be needed, see section~\ref{privilegeelevation}). These events will be reported as '\texttt{[x] Vsync}' frame sets, where \texttt{x} is the identifier of a specific monitor. Note that hardware vertical synchronization might not correspond to the one seen by your application due to desktop composition, command queue buffering, and so on. Also, in some instances, when there is nothing to update on the screen, the graphic driver may choose to stop issuing screen refresh. As a result, there may be periods where no vertical synchronization events are reported.
Use the \texttt{TRACY\_NO\_VSYNC\_CAPTURE} macro to disable capture of Vsync events.
@ -2583,12 +2583,12 @@ The graph of the currently selected frame set (figure~\ref{frametime}) provides
\label{frametime}
\end{figure}
Each bar displayed on the graph represents a unique frame in the current frame set\footnote{Unless the view is zoomed out and multiple frames are merged into one column.}. The progress of time is in the right direction. The height of the bar indicates the time spent in the frame, complemented with the color information:
Each bar displayed on the graph represents a unique frame in the current frame set\footnote{Unless the view is zoomed out and multiple frames are merged into one column.}. The progress of time is in the right direction. The bar height indicates the time spent in the frame, complemented by the color information, which depends on the target FPS value. You can set the desired FPS in the options menu (see section~\ref{options}).
\begin{itemize}
\item If the bar is \emph{blue}, then the frame met the \emph{best} time of 143 FPS, or 6.99 \si{\milli\second}\footnote{The actual target is 144 FPS, but one frame leeway is allowed to account for timing inaccuracies.} (represented by blue target line).
\item If the bar is \emph{green}, then the frame met the \emph{good} time of 59 FPS, or 16.94 \si{\milli\second} (represented by green target line).
\item If the bar is \emph{yellow}, then the frame met the \emph{bad} time of 29 FPS, or 34.48 \si{\milli\second} (represented by yellow target line).
\item If the bar is \emph{blue}, then the frame met the \emph{best} time of twice the target FPS (represented by the green target line).
\item If the bar is \emph{green}, then the frame met the \emph{good} time of target FPS (represented by the yellow line).
\item If the bar is \emph{yellow}, then the frame met the \emph{bad} time of half the FPS (represented by the red target line).
\item If the bar is \emph{red}, then the frame didn't meet any time limits.
\end{itemize}
@ -2948,6 +2948,9 @@ In this window, you can set various trace-related options. For example, the time
\begin{itemize}
\item \emph{\faExpand{} Draw empty labels} -- By default threads that don't have anything to display at the current zoom level are hidden. Enabling this option will show them anyway.
\item \emph{\faFlagCheckered{} Draw frame targets} -- If enabled, time regions in any frame from the currently selected frame set, which exceed the specified \emph{Target FPS} value will be marked with a red background on timeline view.
\begin{itemize}
\item \emph{Target FPS} -- Controls the option above, but also the frame bar colors in the frame time graph (section~\ref{frametimegraph}). The color range thresholds are presented in a line directly below.
\end{itemize}
\item \emph{\faHiking{} Draw context switches} -- Allows disabling context switch display in threads.
\begin{itemize}
\item \emph{\faMoon{} Darken inactive thread} -- If enabled, inactive regions in threads will be dimmed out.

View File

@ -103,63 +103,63 @@ endif
threads_dep = dependency('threads')
includes = files(
'TracyC.h',
'Tracy.hpp',
'TracyD3D11.hpp',
'TracyD3D12.hpp',
'TracyLua.hpp',
'TracyOpenCL.hpp',
'TracyOpenGL.hpp',
'TracyVulkan.hpp'
)
includes = [
'public/tracy/TracyC.h',
'public/tracy/Tracy.hpp',
'public/tracy/TracyD3D11.hpp',
'public/tracy/TracyD3D12.hpp',
'public/tracy/TracyLua.hpp',
'public/tracy/TracyOpenCL.hpp',
'public/tracy/TracyOpenGL.hpp',
'public/tracy/TracyVulkan.hpp'
]
client_includes = files(
'client/tracy_concurrentqueue.h',
'client/tracy_rpmalloc.hpp',
'client/tracy_SPSCQueue.h',
'client/TracyArmCpuTable.hpp',
'client/TracyCallstack.h',
'client/TracyCallstack.hpp',
'client/TracyDebug.hpp',
'client/TracyDxt1.hpp',
'client/TracyFastVector.hpp',
'client/TracyLock.hpp',
'client/TracyProfiler.hpp',
'client/TracyRingBuffer.hpp',
'client/TracyScoped.hpp',
'client/TracyStringHelpers.hpp',
'client/TracySysTime.hpp',
'client/TracySysTrace.hpp',
'client/TracyThread.hpp'
'public/client/tracy_concurrentqueue.h',
'public/client/tracy_rpmalloc.hpp',
'public/client/tracy_SPSCQueue.h',
'public/client/TracyArmCpuTable.hpp',
'public/client/TracyCallstack.h',
'public/client/TracyCallstack.hpp',
'public/client/TracyDebug.hpp',
'public/client/TracyDxt1.hpp',
'public/client/TracyFastVector.hpp',
'public/client/TracyLock.hpp',
'public/client/TracyProfiler.hpp',
'public/client/TracyRingBuffer.hpp',
'public/client/TracyScoped.hpp',
'public/client/TracyStringHelpers.hpp',
'public/client/TracySysTime.hpp',
'public/client/TracySysTrace.hpp',
'public/client/TracyThread.hpp'
)
common_includes = files(
'common/tracy_lz4.hpp',
'common/tracy_lz4hc.hpp',
'common/TracyAlign.hpp',
'common/TracyAlign.hpp',
'common/TracyAlloc.hpp',
'common/TracyApi.h',
'common/TracyColor.hpp',
'common/TracyForceInline.hpp',
'common/TracyMutex.hpp',
'common/TracyProtocol.hpp',
'common/TracyQueue.hpp',
'common/TracySocket.hpp',
'common/TracyStackFrames.hpp',
'common/TracySystem.hpp',
'common/TracyUwp.hpp',
'common/TracyYield.hpp'
)
common_includes = [
'public/common/tracy_lz4.hpp',
'public/common/tracy_lz4hc.hpp',
'public/common/TracyAlign.hpp',
'public/common/TracyAlign.hpp',
'public/common/TracyAlloc.hpp',
'public/common/TracyApi.h',
'public/common/TracyColor.hpp',
'public/common/TracyForceInline.hpp',
'public/common/TracyMutex.hpp',
'public/common/TracyProtocol.hpp',
'public/common/TracyQueue.hpp',
'public/common/TracySocket.hpp',
'public/common/TracyStackFrames.hpp',
'public/common/TracySystem.hpp',
'public/common/TracyUwp.hpp',
'public/common/TracyYield.hpp'
]
tracy_header_files = common_includes + client_includes + includes
tracy_src = files(
'TracyClient.cpp'
)
tracy_src = [
'public/TracyClient.cpp'
]
tracy_public_include_dirs = include_directories('.')
tracy_public_include_dirs = include_directories('public')
compiler = meson.get_compiler('cpp')
override_options = []

View File

@ -1035,7 +1035,7 @@ void InitCallstack()
void EndCallstack()
{
___tracy_free_demangle_buffer()
___tracy_free_demangle_buffer();
}
const char* DecodeCallstackPtrFast( uint64_t ptr )

View File

@ -216,20 +216,6 @@ void WINAPI EventRecordCallback( PEVENT_RECORD record )
}
}
static constexpr const char* VsyncName[] = {
"[0] Vsync",
"[1] Vsync",
"[2] Vsync",
"[3] Vsync",
"[4] Vsync",
"[5] Vsync",
"[6] Vsync",
"[7] Vsync",
"Vsync"
};
static uint32_t VsyncTarget[8] = {};
void WINAPI EventRecordCallbackVsync( PEVENT_RECORD record )
{
#ifdef TRACY_ON_DEMAND
@ -242,24 +228,9 @@ void WINAPI EventRecordCallbackVsync( PEVENT_RECORD record )
const auto vs = (const VSyncInfo*)record->UserData;
int idx = 0;
do
{
if( VsyncTarget[idx] == 0 )
{
VsyncTarget[idx] = vs->vidPnTargetId;
break;
}
else if( VsyncTarget[idx] == vs->vidPnTargetId )
{
break;
}
}
while( ++idx < 8 );
TracyLfqPrepare( QueueType::FrameMarkMsg );
MemWrite( &item->frameMark.time, hdr.TimeStamp.QuadPart );
MemWrite( &item->frameMark.name, uint64_t( VsyncName[idx] ) );
TracyLfqPrepare( QueueType::FrameVsync );
MemWrite( &item->frameVsync.time, hdr.TimeStamp.QuadPart );
MemWrite( &item->frameVsync.id, vs->vidPnTargetId );
TracyLfqCommit;
}
@ -690,6 +661,7 @@ enum TraceEventId
EventCacheMiss,
EventBranchRetired,
EventBranchMiss,
EventVsync,
EventContextSwitch,
EventWakeup,
};
@ -780,13 +752,17 @@ bool SysTraceStart( int64_t& samplingPeriod )
TracyDebug( "perf_event_paranoid: %i\n", paranoidLevel );
#endif
int switchId = -1, wakeupId = -1;
int switchId = -1, wakeupId = -1, vsyncId = -1;
const auto switchIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_switch/id" );
if( switchIdStr ) switchId = atoi( switchIdStr );
const auto wakeupIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_wakeup/id" );
if( wakeupIdStr ) wakeupId = atoi( wakeupIdStr );
const auto vsyncIdStr = ReadFile( "/sys/kernel/debug/tracing/events/drm/drm_vblank_event/id" );
if( vsyncIdStr ) vsyncId = atoi( vsyncIdStr );
TracyDebug( "sched_switch id: %i\nsched_wakeup id: %i\n", switchId, wakeupId );
TracyDebug( "sched_switch id: %i\n", switchId );
TracyDebug( "sched_wakeup id: %i\n", wakeupId );
TracyDebug( "drm_vblank_event id: %i\n", vsyncId );
#ifdef TRACY_NO_SAMPLE_RETIREMENT
const bool noRetirement = true;
@ -816,6 +792,13 @@ bool SysTraceStart( int64_t& samplingPeriod )
const bool noCtxSwitch = noCtxSwitchEnv && noCtxSwitchEnv[0] == '1';
#endif
#ifdef TRACY_NO_VSYNC_CAPTURE
const bool noVsync = true;
#else
const char* noVsyncEnv = GetEnvVar( "TRACY_NO_VSYNC_CAPTURE" );
const bool noVsync = noVsyncEnv && noVsyncEnv[0] == '1';
#endif
samplingPeriod = GetSamplingPeriod();
uint32_t currentPid = (uint32_t)getpid();
@ -826,7 +809,8 @@ bool SysTraceStart( int64_t& samplingPeriod )
2 + // CPU cycles + instructions retired
2 + // cache reference + miss
2 + // branch retired + miss
2 // context switches + wakeups
2 + // context switches + wakeups
1 // vsync
);
s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers );
s_numBuffers = 0;
@ -1002,6 +986,37 @@ bool SysTraceStart( int64_t& samplingPeriod )
s_ctxBufferIdx = s_numBuffers;
// vsync
if( !noVsync && vsyncId != -1 )
{
pe = {};
pe.type = PERF_TYPE_TRACEPOINT;
pe.size = sizeof( perf_event_attr );
pe.sample_period = 1;
pe.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_RAW;
pe.disabled = 1;
pe.config = vsyncId;
#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )
pe.use_clockid = 1;
pe.clockid = CLOCK_MONOTONIC_RAW;
#endif
TracyDebug( "Setup vsync capture\n" );
for( int i=0; i<s_numCpus; i++ )
{
const int fd = perf_event_open( &pe, -1, i, -1, PERF_FLAG_FD_CLOEXEC );
if( fd != -1 )
{
new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventVsync, i );
if( s_ring[s_numBuffers].IsValid() )
{
s_numBuffers++;
TracyDebug( " Core %i ok\n", i );
}
}
}
}
// context switches
if( !noCtxSwitch && switchId != -1 )
{
@ -1336,7 +1351,8 @@ void SysTraceWorker( void* ptr )
t0 = ring.ConvertTimeToTsc( t0 );
#endif
if( ring.GetId() == EventContextSwitch )
const auto rid = ring.GetId();
if( rid == EventContextSwitch )
{
// Layout:
// u64 time
@ -1404,10 +1420,8 @@ void SysTraceWorker( void* ptr )
TracyLfqCommit;
}
}
else
else if( rid == EventWakeup )
{
assert( ring.GetId() == EventWakeup );
// Layout:
// u64 time
// u32 size
@ -1429,6 +1443,40 @@ void SysTraceWorker( void* ptr )
MemWrite( &item->threadWakeup.thread, pid );
TracyLfqCommit;
}
else
{
assert( rid == EventVsync );
// Layout:
// u64 time
// u32 size
// u8 data[size]
// Data (not ABI stable):
// u8 hdr[8]
// i32 crtc
// u32 seq
// i64 ktime
// u8 high precision
offset += sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ) + 8;
int32_t crtc;
ring.Read( &crtc, offset, sizeof( int32_t ) );
// Note: The timestamp value t0 might be off by a number of microseconds from the
// true hardware vblank event. The ktime value should be used instead, but it is
// measured in CLOCK_MONOTONIC time. Tracy only supports the timestamp counter
// register (TSC) or CLOCK_MONOTONIC_RAW clock.
#if 0
offset += sizeof( uint32_t ) * 2;
int64_t ktime;
ring.Read( &ktime, offset, sizeof( int64_t ) );
#endif
TracyLfqPrepare( QueueType::FrameVsync );
MemWrite( &item->frameVsync.id, crtc );
MemWrite( &item->frameVsync.time, t0 );
TracyLfqCommit;
}
rbPos += hdr.size;
if( rbPos == end[sel] )

View File

@ -24,7 +24,7 @@ public:
~ThreadExitHandler()
{
#ifdef TRACY_MANUAL_LIFETIME
rpmalloc_thread_finalize();
rpmalloc_thread_finalize( 1 );
RpThreadInitDone = false;
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,12 @@ namespace tracy
#if defined(__clang__) || defined(__GNUC__)
# define RPMALLOC_EXPORT __attribute__((visibility("default")))
# define RPMALLOC_ALLOCATOR
# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
# if defined(__clang_major__) && (__clang_major__ < 4)
# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
# define RPMALLOC_ATTRIB_MALLOC
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
# else
# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
# endif
@ -45,13 +46,24 @@ namespace tracy
# define RPMALLOC_CDECL
#endif
//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes
//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
// a very small overhead due to some size calculations not being compile time constants
#ifndef RPMALLOC_CONFIGURABLE
#define RPMALLOC_CONFIGURABLE 0
#endif
//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
// Will introduce a very small overhead to track fully allocated spans in heaps
#ifndef RPMALLOC_FIRST_CLASS_HEAPS
#define RPMALLOC_FIRST_CLASS_HEAPS 0
#endif
//! Flag to rpaligned_realloc to not preserve content in reallocation
#define RPMALLOC_NO_PRESERVE 1
//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
// in which case the original pointer is still valid (just like a call to realloc which failes to allocate
// a new block).
#define RPMALLOC_GROW_OR_FAIL 2
typedef struct rpmalloc_global_statistics_t {
//! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
@ -99,7 +111,7 @@ typedef struct rpmalloc_thread_statistics_t {
size_t from_reserved;
//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
size_t map_calls;
} span_use[32];
} span_use[64];
//! Per size class statistics (only if ENABLE_STATISTICS=1)
struct {
//! Current number of allocations
@ -131,7 +143,8 @@ typedef struct rpmalloc_config_t {
// larger than 65535 (storable in an uint16_t), if it is you must use natural
// alignment to shift it into 16 bits. If you set a memory_map function, you
// must also set a memory_unmap function or else the default implementation will
// be used for both.
// be used for both. This function must be thread safe, it can be called by
// multiple threads simultaneously.
void* (*memory_map)(size_t size, size_t* offset);
//! Unmap the memory pages starting at address and spanning the given number of bytes.
// If release is set to non-zero, the unmap is for an entire span range as returned by
@ -139,8 +152,18 @@ typedef struct rpmalloc_config_t {
// release argument holds the size of the entire span range. If release is set to 0,
// the unmap is a partial decommit of a subset of the mapped memory range.
// If you set a memory_unmap function, you must also set a memory_map function or
// else the default implementation will be used for both.
// else the default implementation will be used for both. This function must be thread
// safe, it can be called by multiple threads simultaneously.
void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
//! Called when an assert fails, if asserts are enabled. Will use the standard assert()
// if this is not set.
void (*error_callback)(const char* message);
//! Called when a call to map memory pages fails (out of memory). If this callback is
// not set or returns zero the library will return a null pointer in the allocation
// call. If this callback returns non-zero the map call will be retried. The argument
// passed is the number of bytes that was requested in the map call. Only used if
// the default system memory map function is used (memory_map callback is not set).
int (*map_fail_callback)(size_t size);
//! Size of memory pages. The page size MUST be a power of two. All memory mapping
// requests to memory_map will be made with size set to a multiple of the page size.
// Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
@ -163,6 +186,10 @@ typedef struct rpmalloc_config_t {
// For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
// For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
int enable_huge_pages;
//! Respectively allocated pages and huge allocated pages names for systems
// supporting it to be able to distinguish among anonymous regions.
const char *page_name;
const char *huge_page_name;
} rpmalloc_config_t;
//! Initialize allocator with default configuration
@ -187,7 +214,7 @@ rpmalloc_thread_initialize(void);
//! Finalize allocator for calling thread
TRACY_API void
rpmalloc_thread_finalize(void);
rpmalloc_thread_finalize(int release_caches);
//! Perform deferred deallocations pending for the calling thread heap
RPMALLOC_EXPORT void
@ -240,6 +267,13 @@ rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsi
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
//! Allocate a memory block of at least the given size and alignment, and zero initialize it.
// Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
//! Allocate a memory block of at least the given size and alignment.
// Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc
@ -252,10 +286,78 @@ rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB
// and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT int
rpposix_memalign(void **memptr, size_t alignment, size_t size);
rpposix_memalign(void** memptr, size_t alignment, size_t size);
//! Query the usable size of the given memory block (from given pointer to the end of block)
RPMALLOC_EXPORT size_t
rpmalloc_usable_size(void* ptr);
#if RPMALLOC_FIRST_CLASS_HEAPS
//! Heap type
typedef struct heap_t rpmalloc_heap_t;
//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
// if none available. Heap API is implemented with the strict assumption that only one single
// thread will call heap functions for a given heap at any given time, no functions are thread safe.
RPMALLOC_EXPORT rpmalloc_heap_t*
rpmalloc_heap_acquire(void);
//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
RPMALLOC_EXPORT void
rpmalloc_heap_release(rpmalloc_heap_t* heap);
//! Allocate a memory block of at least the given size using the given heap.
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
//! Allocate a memory block of at least the given size using the given heap. The returned
// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB).
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
//! Allocate a memory block of at least the given size using the given heap and zero initialize it.
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB).
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
//! Reallocate the given block to at least the given size. The memory block MUST be allocated
// by the same heap given to this function.
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
//! Reallocate the given block to at least the given size. The memory block MUST be allocated
// by the same heap given to this function. The returned block will have the requested alignment.
// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
// the span size (default 64KiB).
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
//! Free the given memory block from the given heap. The memory block MUST be allocated
// by the same heap given to this function.
RPMALLOC_EXPORT void
rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
//! Free all memory allocated by the heap
RPMALLOC_EXPORT void
rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
// for a single thread, a heap can never be shared between multiple threads. The previous
// current heap for the calling thread is released to be reused by other threads.
RPMALLOC_EXPORT void
rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
#endif
}

View File

@ -9,7 +9,7 @@ namespace tracy
constexpr unsigned Lz4CompressBound( unsigned isize ) { return isize + ( isize / 255 ) + 16; }
enum : uint32_t { ProtocolVersion = 59 };
enum : uint32_t { ProtocolVersion = 60 };
enum : uint16_t { BroadcastVersion = 2 };
using lz4sz_t = uint32_t;
@ -34,7 +34,7 @@ enum HandshakeStatus : uint8_t
enum { WelcomeMessageProgramNameSize = 64 };
enum { WelcomeMessageHostInfoSize = 1024 };
#pragma pack( 1 )
#pragma pack( push, 1 )
// Must increase left query space after handling!
enum ServerQuery : uint8_t
@ -133,7 +133,7 @@ struct BroadcastMessage
enum { BroadcastMessageSize = sizeof( BroadcastMessage ) };
#pragma pack()
#pragma pack( pop )
}

View File

@ -78,6 +78,7 @@ enum class QueueType : uint8_t
FrameMarkMsg,
FrameMarkMsgStart,
FrameMarkMsgEnd,
FrameVsync,
SourceLocation,
LockAnnounce,
LockTerminate,
@ -121,7 +122,7 @@ enum class QueueType : uint8_t
NUM_TYPES
};
#pragma pack( 1 )
#pragma pack( push, 1 )
struct QueueThreadContext
{
@ -196,6 +197,12 @@ struct QueueFrameMark
uint64_t name; // ptr
};
struct QueueFrameVsync
{
int64_t time;
uint32_t id;
};
struct QueueFrameImage
{
uint32_t frame;
@ -670,6 +677,7 @@ struct QueueItem
QueueZoneValueThread zoneValueThread;
QueueStringTransfer stringTransfer;
QueueFrameMark frameMark;
QueueFrameVsync frameVsync;
QueueFrameImage frameImage;
QueueFrameImageFat frameImageFat;
QueueSourceLocation srcloc;
@ -737,7 +745,7 @@ struct QueueItem
QueueFiberLeave fiberLeave;
};
};
#pragma pack()
#pragma pack( pop )
enum { QueueItemSize = sizeof( QueueItem ) };
@ -813,6 +821,7 @@ static constexpr size_t QueueDataSize[] = {
sizeof( QueueHeader ) + sizeof( QueueFrameMark ), // continuous frames
sizeof( QueueHeader ) + sizeof( QueueFrameMark ), // start
sizeof( QueueHeader ) + sizeof( QueueFrameMark ), // end
sizeof( QueueHeader ) + sizeof( QueueFrameVsync ),
sizeof( QueueHeader ) + sizeof( QueueSourceLocation ),
sizeof( QueueHeader ) + sizeof( QueueLockAnnounce ),
sizeof( QueueHeader ) + sizeof( QueueLockTerminate ),

View File

@ -114,7 +114,7 @@ struct THREADNAME_INFO
DWORD dwThreadID;
DWORD dwFlags;
};
# pragma pack(pop)
# pragma pack( pop )
void ThreadNameMsvcMagic( const THREADNAME_INFO& info )
{

View File

@ -18,7 +18,7 @@
namespace tracy
{
#pragma pack( 1 )
#pragma pack( push, 1 )
struct StringRef
{
@ -663,7 +663,7 @@ struct ChildSample
enum { ChildSampleSize = sizeof( ChildSample ) };
#pragma pack()
#pragma pack( pop )
struct ThreadData

View File

@ -3,7 +3,7 @@
#include <inttypes.h>
#include "TracyEventDebug.hpp"
#include "../common/TracyQueue.hpp"
#include "../public/common/TracyQueue.hpp"
namespace tracy
{
@ -144,8 +144,14 @@ void EventDebug( const QueueItem& ev )
case QueueType::GpuZoneEndSerial:
fprintf( f, "ev %i (GpuZoneEndSerial)\n", ev.hdr.idx );
break;
case QueueType::PlotData:
fprintf( f, "ev %i (PlotData)\n", ev.hdr.idx );
case QueueType::PlotDataInt:
fprintf( f, "ev %i (PlotDataInt)\n", ev.hdr.idx );
break;
case QueueType::PlotDataFloat:
fprintf( f, "ev %i (PlotDataFloat)\n", ev.hdr.idx );
break;
case QueueType::PlotDataDouble:
fprintf( f, "ev %i (PlotDataDouble)\n", ev.hdr.idx );
break;
case QueueType::ContextSwitch:
fprintf( f, "ev %i (ContextSwitch)\n", ev.hdr.idx );

View File

@ -7,7 +7,7 @@
namespace tracy
{
#pragma pack( 1 )
#pragma pack( push, 1 )
template<typename T, class CompareDefault = std::less<T>>
class SortedVector
{
@ -118,7 +118,7 @@ private:
uint32_t sortedEnd;
};
#pragma pack()
#pragma pack( pop )
enum { SortedVectorSize = sizeof( SortedVector<int> ) };

View File

@ -3594,7 +3594,9 @@ void SourceView::RenderAsmLine( AsmLine& line, const AddrStat& ipcnt, const Addr
}
else
{
SmallColorBox( 0 );
ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( 0, 0 ) );
ImGui::ColorButton( "c1", ImVec4( 0.f, 0.f, 0.f, 1.f ), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2( ty - 3 * scale, ty - 3 * scale) );
ImGui::PopStyleVar();
ImGui::SameLine();
startPos = ImGui::GetCursorScreenPos();
TextDisabledUnformatted( "[unknown]" );

View File

@ -68,6 +68,11 @@ public:
}
}
tracy_force_inline void AddExternal( const T& val )
{
m_data.push_back( val );
}
private:
Vector<T> m_data;
unordered_flat_map<uint64_t, T> m_pending;

View File

@ -16,7 +16,7 @@
namespace tracy
{
#pragma pack( 1 )
#pragma pack( push, 1 )
template<typename T>
class VarArray
{
@ -56,7 +56,7 @@ private:
uint32_t m_hash;
const short_ptr<T> m_ptr;
};
#pragma pack()
#pragma pack( pop )
enum { VarArraySize = sizeof( VarArray<int> ) };

View File

@ -19,7 +19,7 @@
namespace tracy
{
#pragma pack( 1 )
#pragma pack( push, 1 )
template<typename T>
class Vector
{
@ -348,7 +348,7 @@ private:
template<typename T> struct VectorAdapterDirect { const T& operator()( const T& it ) const { return it; } };
template<typename T> struct VectorAdapterPointer { const T& operator()( const short_ptr<T>& it ) const { return *it; } };
#pragma pack()
#pragma pack( pop )
enum { VectorSize = sizeof( Vector<int> ) };

View File

@ -7,7 +7,7 @@ namespace Version
{
enum { Major = 0 };
enum { Minor = 8 };
enum { Patch = 3 };
enum { Patch = 4 };
}
}

View File

@ -845,7 +845,7 @@ bool View::DrawImpl()
{
ImGui::PushStyleColor( ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled] );
}
ImGui::Text( "%s: %s", m_frames->name == 0 ? "Frames" : m_worker.GetString( m_frames->name ), RealToString( m_worker.GetFrameCount( *m_frames ) ) );
ImGui::Text( "%s: %s", GetFrameSetName( *m_frames ), RealToString( m_worker.GetFrameCount( *m_frames ) ) );
if( !vis )
{
ImGui::PopStyleColor();
@ -861,7 +861,7 @@ bool View::DrawImpl()
for( auto& fd : frames )
{
bool isSelected = m_frames == fd;
if( ImGui::Selectable( fd->name == 0 ? "Frames" : m_worker.GetString( fd->name ), isSelected ) )
if( ImGui::Selectable( GetFrameSetName( *fd ), isSelected ) )
{
m_frames = fd;
}

View File

@ -303,6 +303,8 @@ private:
const ZoneEvent* FindZoneAtTime( uint64_t thread, int64_t time ) const;
uint64_t GetFrameNumber( const FrameData& fd, int i, uint64_t offset ) const;
const char* GetFrameText( const FrameData& fd, int i, uint64_t ftime, uint64_t offset ) const;
const char* GetFrameSetName( const FrameData& fd ) const;
static const char* GetFrameSetName( const FrameData& fd, const Worker& worker );
#ifndef TRACY_NO_STATISTICS
void FindZones();

View File

@ -405,7 +405,7 @@ void View::DrawCompare()
int idx = 0;
for( auto& v : f0 )
{
const auto name = m_worker.GetString( v->name );
const auto name = GetFrameSetName( *v );
ImGui::PushID( -1 - idx );
ImGui::RadioButton( name, &m_compare.selMatch[0], idx++ );
ImGui::SameLine();
@ -418,7 +418,7 @@ void View::DrawCompare()
idx = 0;
for( auto& v : f1 )
{
const auto name = m_compare.second->GetString( v->name );
const auto name = GetFrameSetName( *v, *m_compare.second );
ImGui::PushID( idx );
ImGui::RadioButton( name, &m_compare.selMatch[1], idx++ );
ImGui::SameLine();
@ -435,8 +435,8 @@ void View::DrawCompare()
if( m_compare.link )
{
auto string0 = m_worker.GetString( f0[m_compare.selMatch[0]]->name );
auto string1 = m_compare.second->GetString( f1[m_compare.selMatch[1]]->name );
auto string0 = GetFrameSetName( *f0[m_compare.selMatch[0]] );
auto string1 = GetFrameSetName( *f1[m_compare.selMatch[1]], *m_compare.second );
if( strcmp( string0, string1 ) != 0 )
{
@ -445,7 +445,7 @@ void View::DrawCompare()
{
for( auto& v : f1 )
{
auto string = m_compare.second->GetString( v->name );
auto string = GetFrameSetName( *v, *m_compare.second );
if( strcmp( string0, string ) == 0 )
{
m_compare.selMatch[1] = idx;
@ -459,7 +459,7 @@ void View::DrawCompare()
assert( prev1 != m_compare.selMatch[1] );
for( auto& v : f0 )
{
auto string = m_worker.GetString( v->name );
auto string = GetFrameSetName( *v );
if( strcmp( string1, string ) == 0 )
{
m_compare.selMatch[0] = idx;

View File

@ -7,15 +7,11 @@
namespace tracy
{
enum { BestTime = 1000 * 1000 * 1000 / 143 };
enum { GoodTime = 1000 * 1000 * 1000 / 59 };
enum { BadTime = 1000 * 1000 * 1000 / 29 };
static ImU32 GetFrameColor( uint64_t frameTime )
static uint32_t GetFrameColor( uint64_t time, uint64_t target )
{
return frameTime > BadTime ? 0xFF2222DD :
frameTime > GoodTime ? 0xFF22DDDD :
frameTime > BestTime ? 0xFF22DD22 : 0xFFDD9900;
return time > target * 2 ? 0xFF2222DD :
time > target ? 0xFF22DDDD :
time > target / 2 ? 0xFF22DD22 : 0xFFDD9900;
}
static int GetFrameWidth( int frameScale )
@ -41,11 +37,13 @@ void View::DrawFrames()
const auto scale = GetScale();
const auto Height = 50 * scale;
enum { MaxFrameTime = 50 * 1000 * 1000 }; // 50ms
constexpr uint64_t MaxFrameTime = 50 * 1000 * 1000; // 50ms
ImGuiWindow* window = ImGui::GetCurrentWindowRead();
if( window->SkipItems ) return;
const uint64_t frameTarget = 1000 * 1000 * 1000 / m_vd.frameTarget;
auto& io = ImGui::GetIO();
const auto wpos = ImGui::GetCursorScreenPos();
@ -185,7 +183,7 @@ void View::DrawFrames()
}
else
{
ImGui::TextDisabled( "%s:", m_worker.GetString( m_frames->name ) );
ImGui::TextDisabled( "%s:", GetFrameSetName( *m_frames ) );
ImGui::SameLine();
ImGui::TextUnformatted( RealToString( fnum ) );
ImGui::Separator();
@ -416,11 +414,11 @@ void View::DrawFrames()
const auto h = std::max( 1.f, float( std::min<uint64_t>( MaxFrameTime, f ) ) / MaxFrameTime * ( Height - 2 ) );
if( fwidth != 1 )
{
draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), GetFrameColor( f ) );
draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), GetFrameColor( f, frameTarget ) );
}
else
{
DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), GetFrameColor( f ) );
DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), GetFrameColor( f, frameTarget ) );
}
i++;
@ -447,9 +445,9 @@ void View::DrawFrames()
}
}
DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * BadTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * BadTime / MaxFrameTime ) ), 0x4422DDDD );
DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * GoodTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * GoodTime / MaxFrameTime ) ), 0x4422DD22 );
DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * BestTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * BestTime / MaxFrameTime ) ), 0x44DD9900 );
if( frameTarget * 2 <= MaxFrameTime ) DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * frameTarget * 2 / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * frameTarget * 2 / MaxFrameTime ) ), 0x442222DD );
if( frameTarget <= MaxFrameTime ) DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * frameTarget / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * frameTarget / MaxFrameTime ) ), 0x4422DDDD );
if( frameTarget / 2 <= MaxFrameTime ) DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * frameTarget / 2 / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * frameTarget / 2 / MaxFrameTime ) ), 0x4422DD22 );
}
}

View File

@ -320,7 +320,7 @@ void View::DrawTimelineFrames( const FrameData& frames )
ImGui::BeginTooltip();
TextDisabledUnformatted( "Frame set:" );
ImGui::SameLine();
ImGui::TextUnformatted( frames.name == 0 ? "Frames" : m_worker.GetString( frames.name ) );
ImGui::TextUnformatted( GetFrameSetName( frames ) );
ImGui::EndTooltip();
}
if( IsMouseClicked( 0 ) )

View File

@ -24,6 +24,7 @@ void View::DrawOptions()
m_vd.drawFrameTargets = val;
ImGui::Indent();
int tmp = m_vd.frameTarget;
ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( 0, 0 ) );
ImGui::SetNextItemWidth( 90 * scale );
if( ImGui::InputInt( "Target FPS", &tmp ) )
{
@ -32,6 +33,22 @@ void View::DrawOptions()
}
ImGui::SameLine();
TextDisabledUnformatted( TimeToString( 1000*1000*1000 / tmp ) );
ImGui::PopStyleVar();
ImGui::PushFont( m_smallFont );
SmallColorBox( 0xFF2222DD );
ImGui::SameLine( 0, 0 );
ImGui::Text( " < %i < ", tmp / 2 );
ImGui::SameLine( 0, 0 );
SmallColorBox( 0xFF22DDDD );
ImGui::SameLine( 0, 0 );
ImGui::Text( " < %i < ", tmp );
ImGui::SameLine( 0, 0 );
SmallColorBox( 0xFF22DD22 );
ImGui::SameLine( 0, 0 );
ImGui::Text( " < %i < ", tmp * 2 );
ImGui::SameLine( 0, 0 );
SmallColorBox( 0xFFDD9900 );
ImGui::PopFont();
ImGui::Unindent();
if( m_worker.HasContextSwitches() )
{
@ -701,7 +718,7 @@ void View::DrawOptions()
for( const auto& fd : m_worker.GetFrames() )
{
ImGui::PushID( idx++ );
SmallCheckbox( fd->name == 0 ? "Frames" : m_worker.GetString( fd->name ), &Vis( fd ).visible );
SmallCheckbox( GetFrameSetName( *fd ), &Vis( fd ).visible );
ImGui::PopID();
ImGui::SameLine();
ImGui::TextDisabled( "%s %sframes", RealToString( fd->frames.size() ), fd->continuous ? "" : "discontinuous " );

View File

@ -188,7 +188,7 @@ void View::DrawInfo()
auto fsz = m_worker.GetFullFrameCount( *m_frames );
if( fsz != 0 )
{
TextFocused( "Frame set:", m_frames->name == 0 ? "Frames" : m_worker.GetString( m_frames->name ) );
TextFocused( "Frame set:", GetFrameSetName( *m_frames ) );
ImGui::SameLine();
ImGui::TextDisabled( "(%s)", m_frames->continuous ? "continuous" : "discontinuous" );
ImGui::SameLine();
@ -199,7 +199,7 @@ void View::DrawInfo()
for( auto& fd : frames )
{
bool isSelected = m_frames == fd;
if( ImGui::Selectable( fd->name == 0 ? "Frames" : m_worker.GetString( fd->name ), isSelected ) )
if( ImGui::Selectable( GetFrameSetName( *fd ), isSelected ) )
{
m_frames = fd;
fsz = m_worker.GetFullFrameCount( *m_frames );

View File

@ -1,3 +1,5 @@
#include <inttypes.h>
#include "TracyColor.hpp"
#include "TracyPrint.hpp"
#include "TracyView.hpp"
@ -791,11 +793,39 @@ const char* View::GetFrameText( const FrameData& fd, int i, uint64_t ftime, uint
}
else
{
sprintf( buf, "%s %s (%s)", m_worker.GetString( fd.name ), RealToString( fnum ), TimeToString( ftime ) );
sprintf( buf, "%s %s (%s)", GetFrameSetName( fd ), RealToString( fnum ), TimeToString( ftime ) );
}
return buf;
}
const char* View::GetFrameSetName( const FrameData& fd ) const
{
return GetFrameSetName( fd, m_worker );
}
const char* View::GetFrameSetName( const FrameData& fd, const Worker& worker )
{
enum { Pool = 4 };
static char bufpool[Pool][64];
static int bufsel = 0;
if( fd.name == 0 )
{
return "Frames";
}
else if( fd.name >> 63 != 0 )
{
char* buf = bufpool[bufsel];
bufsel = ( bufsel + 1 ) % Pool;
sprintf( buf, "[%" PRIu32 "] Vsync", uint32_t( fd.name ) );
return buf;
}
else
{
return worker.GetString( fd.name );
}
}
const char* View::ShortenNamespace( const char* name ) const
{
if( m_namespace == Namespace::Full ) return name;

View File

@ -1705,6 +1705,13 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks )
{
m_data.symbolLocInline[symInlineIdx] = std::numeric_limits<uint64_t>::max();
}
#ifdef NO_PARALLEL_SORT
pdqsort_branchless( m_data.symbolLoc.begin(), m_data.symbolLoc.end(), [] ( const auto& l, const auto& r ) { return l.addr < r.addr; } );
pdqsort_branchless( m_data.symbolLocInline.begin(), m_data.symbolLocInline.end() );
#else
std::sort( std::execution::par_unseq, m_data.symbolLoc.begin(), m_data.symbolLoc.end(), [] ( const auto& l, const auto& r ) { return l.addr < r.addr; } );
std::sort( std::execution::par_unseq, m_data.symbolLocInline.begin(), m_data.symbolLocInline.end() );
#endif
f.Read( sz );
if( eventMask & EventType::SymbolCode )
@ -4675,6 +4682,9 @@ bool Worker::Process( const QueueItem& ev )
case QueueType::FrameMarkMsgEnd:
ProcessFrameMarkEnd( ev.frameMark );
break;
case QueueType::FrameVsync:
ProcessFrameVsync( ev.frameVsync );
break;
case QueueType::FrameImage:
ProcessFrameImage( ev.frameImage );
break;
@ -5310,6 +5320,38 @@ void Worker::ProcessFrameMarkEnd( const QueueFrameMark& ev )
#endif
}
void Worker::ProcessFrameVsync( const QueueFrameVsync& ev )
{
auto it = m_vsyncFrameMap.find( ev.id );
if( it == m_vsyncFrameMap.end() )
{
auto fd = m_slab.AllocInit<FrameData>();
// Hackfix workaround to maintain backwards compatibility.
// Frame name pointers won't be in kernel space. Exploit that to store custom IDs.
fd->name = uint64_t( m_vsyncFrameMap.size() ) | 0x8000000000000000;
fd->continuous = 1;
m_data.frames.AddExternal( fd );
it = m_vsyncFrameMap.emplace( ev.id, fd ).first;
}
auto fd = it->second;
assert( fd->continuous == 1 );
const auto time = TscTime( ev.time );
assert( fd->frames.empty() || fd->frames.back().start <= time );
fd->frames.push_back( FrameEvent{ time, -1, -1 } );
if( m_data.lastTime < time ) m_data.lastTime = time;
#ifndef TRACY_NO_STATISTICS
const auto timeSpan = GetFrameTime( *fd, fd->frames.size() - 1 );
if( timeSpan > 0 )
{
fd->min = std::min( fd->min, timeSpan );
fd->max = std::max( fd->max, timeSpan );
fd->total += timeSpan;
fd->sumSq += double( timeSpan ) * timeSpan;
}
#endif
}
void Worker::ProcessFrameImage( const QueueFrameImage& ev )
{
assert( m_pendingFrameImageData.image != nullptr );

View File

@ -158,13 +158,13 @@ public:
uint8_t inlineFrame;
};
#pragma pack( 1 )
#pragma pack( push, 1 )
struct GhostKey
{
CallstackFrameId frame;
uint8_t inlineFrame;
};
#pragma pack()
#pragma pack( pop )
struct GhostKeyHasher
{
@ -683,6 +683,7 @@ private:
tracy_force_inline void ProcessFrameMark( const QueueFrameMark& ev );
tracy_force_inline void ProcessFrameMarkStart( const QueueFrameMark& ev );
tracy_force_inline void ProcessFrameMarkEnd( const QueueFrameMark& ev );
tracy_force_inline void ProcessFrameVsync( const QueueFrameVsync& ev );
tracy_force_inline void ProcessFrameImage( const QueueFrameImage& ev );
tracy_force_inline void ProcessZoneText();
tracy_force_inline void ProcessZoneName();
@ -983,6 +984,7 @@ private:
Vector<uint64_t> m_sourceLocationQueue;
unordered_flat_map<uint64_t, int16_t> m_sourceLocationShrink;
unordered_flat_map<uint64_t, ThreadData*> m_threadMap;
unordered_flat_map<uint32_t, FrameData*> m_vsyncFrameMap;
FrameImagePending m_pendingFrameImageData = {};
unordered_flat_map<uint64_t, SymbolPending> m_pendingSymbols;
unordered_flat_set<StringRef, StringRefHasher, StringRefComparator> m_pendingFileStrings;