mirror of
https://github.com/wolfpld/tracy.git
synced 2026-06-12 10:43:49 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c556831ddc | ||
|
|
8a8e16a559 | ||
|
|
be89f228ee | ||
|
|
4f9107fac5 | ||
|
|
17ab46c539 | ||
|
|
8caf4f0d60 | ||
|
|
8b1576170d | ||
|
|
1d6fda26ea | ||
|
|
581e9cb28e | ||
|
|
84cbf46cc5 | ||
|
|
250daeabe7 | ||
|
|
1fa69045a3 | ||
|
|
1a872faae6 | ||
|
|
f1119d88b9 | ||
|
|
22e580d4c0 | ||
|
|
764624d3d1 | ||
|
|
e1b325741e | ||
|
|
b69813f077 | ||
|
|
d181e80c29 | ||
|
|
650c98ece7 | ||
|
|
310c9389b2 | ||
|
|
e660821d75 | ||
|
|
fae74430c5 | ||
|
|
3100c39a68 | ||
|
|
0dd5c8b507 | ||
|
|
a0b2a1d4bc | ||
|
|
09558a0347 | ||
|
|
b57f08f166 | ||
|
|
7f56f1d182 | ||
|
|
7e833e7ddc | ||
|
|
bbf225b788 | ||
|
|
18242189e1 | ||
|
|
9becb3221d | ||
|
|
2875926cdb | ||
|
|
79c5bdcf62 | ||
|
|
b8267a1660 |
3
.github/workflows/latex.yml
vendored
3
.github/workflows/latex.yml
vendored
@@ -13,9 +13,6 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Fix stupidity
|
||||
run: |
|
||||
cp LICENSE LICENSE.
|
||||
- name: Compile LaTeX
|
||||
uses: xu-cheng/latex-action@v3
|
||||
with:
|
||||
|
||||
@@ -49,7 +49,7 @@ target_compile_features(TracyClient PUBLIC cxx_std_11)
|
||||
set_target_properties(TracyClient PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
|
||||
target_include_directories(TracyClient SYSTEM PUBLIC
|
||||
$<BUILD_INTERFACE:${TRACY_PUBLIC_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
$<INSTALL_INTERFACE:include/tracy>)
|
||||
target_link_libraries(
|
||||
TracyClient
|
||||
PUBLIC
|
||||
@@ -61,7 +61,7 @@ if(TRACY_Fortran)
|
||||
add_library(TracyClientF90 ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.F90")
|
||||
target_include_directories(TracyClientF90 PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
$<INSTALL_INTERFACE:include/tracy>)
|
||||
target_link_libraries(
|
||||
TracyClientF90
|
||||
PUBLIC
|
||||
@@ -164,9 +164,11 @@ endif()
|
||||
set(tracy_includes
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyC.h
|
||||
${TRACY_PUBLIC_DIR}/tracy/Tracy.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyCUDA.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyD3D11.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyD3D12.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyLua.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyMetal.hmm
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyOpenCL.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyOpenGL.hpp
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyVulkan.hpp)
|
||||
|
||||
25
NEWS
25
NEWS
@@ -2,6 +2,31 @@ Note: There is no guarantee that version mismatched client and server will
|
||||
be able to talk with each other. Network protocol breakages won't be listed
|
||||
here.
|
||||
|
||||
v0.12.2 (2025-06-25)
|
||||
--------------------
|
||||
|
||||
- Fixed builds made out of git checkout directory.
|
||||
- Added range limits for flame graph.
|
||||
- Fixed wayland include paths for distros that use non-standard package
|
||||
layouts.
|
||||
- Workarounded MinGW build problems. Safe symbol retrieval is not available
|
||||
on this platform.
|
||||
- Fixed Lua bindings when TRACY_NO_CALLSTACK is defined.
|
||||
|
||||
|
||||
v0.12.1 (2025-06-07)
|
||||
--------------------
|
||||
|
||||
- Fixed window size calculation on macOS, most notably enabling the vertical
|
||||
timeline scroll bar.
|
||||
- Made debug builds of the GUI profiler work with broken Apple compiler.
|
||||
- Fixed profiler compilation when build directory is outside the source
|
||||
directory.
|
||||
- Set proper include path when using CMake integration.
|
||||
- Added the Tracy Metal and CUDA headers to CMake install configuration.
|
||||
- Documented flame graphs.
|
||||
|
||||
|
||||
v0.12.0 (2025-05-30)
|
||||
--------------------
|
||||
|
||||
|
||||
14
cmake/ppqsort-nodebug.patch
Normal file
14
cmake/ppqsort-nodebug.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
diff --git i/include/ppqsort/parameters.h w/include/ppqsort/parameters.h
|
||||
index 115c3a1..3f4b669 100644
|
||||
--- i/include/ppqsort/parameters.h
|
||||
+++ w/include/ppqsort/parameters.h
|
||||
@@ -3,7 +3,8 @@
|
||||
#include <bit>
|
||||
#include <execution>
|
||||
|
||||
-#ifndef NDEBUG
|
||||
+//#ifndef NDEBUG
|
||||
+#if 0
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
#include <syncstream>
|
||||
@@ -187,5 +187,7 @@ CPMAddPackage(
|
||||
NAME PPQSort
|
||||
GITHUB_REPOSITORY GabTux/PPQSort
|
||||
VERSION 1.0.5
|
||||
PATCHES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ppqsort-nodebug.patch"
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
|
||||
@@ -188,6 +188,12 @@ std::pair<bool, Record> read_next_record(std::vector<uint8_t> const &input, size
|
||||
CHECK_BOUND(offset + 8*len_word);
|
||||
|
||||
Record r{(uint64_t *)&input[offset], len_word, header};
|
||||
|
||||
if (len_word == 0) {
|
||||
fprintf(stderr, "warning: invalid record with length=0 at offset %" PRIu64 "\n", offset); \
|
||||
return std::make_pair(false,Record{}); \
|
||||
}
|
||||
|
||||
offset += 8 * len_word;
|
||||
return std::make_pair(true, r);
|
||||
}
|
||||
|
||||
@@ -3223,7 +3223,7 @@ The control menu (top row of buttons) provides access to various profiler featur
|
||||
\item \emph{\faTags{} Messages} -- Toggles the message log window (section~\ref{messages}), which displays custom messages sent by the client, as described in section~\ref{messagelog}.
|
||||
\item \emph{\faSearch{} Find} -- This buttons toggles the find zone window, which allows inspection of zone behavior statistics (section~\ref{findzone}).
|
||||
\item \emph{\faSortAmountUp{} Statistics} -- Toggles the statistics window, which displays zones sorted by their total time cost (section~\ref{statistics}).
|
||||
\item \emph{\faFire{} Flame} -- Enables the flame graph window.
|
||||
\item \emph{\faFire{} Flame} -- Enables the flame graph window (section~\ref{flamegraph}).
|
||||
\item \emph{\faMemory{} Memory} -- Various memory profiling options may be accessed here (section~\ref{memorywindow}).
|
||||
\item \emph{\faBalanceScale{} Compare} -- Toggles the trace compare window, which allows you to see the performance difference between two profiling runs (section~\ref{compare}).
|
||||
\item \emph{\faFingerprint{} Info} -- Show general information about the trace (section~\ref{traceinfo}).
|
||||
@@ -3658,6 +3658,7 @@ To define a time range, drag the \LMB{}~left mouse button over the timeline view
|
||||
\begin{itemize}
|
||||
\item \emph{\faSearch{}~Limit find zone time range} -- this will limit find zone results. See chapter~\ref{findzone} for more details.
|
||||
\item \emph{\faSortAmountUp{}~Limit statistics time range} -- selecting this option will limit statistics results. See chapter~\ref{statistics} for more details.
|
||||
\item \emph{\faFire{}~Limit flame graph time range} -- limits flame graph results. Refer to chapter~\ref{flamegraph}.
|
||||
\item \emph{\faHourglassHalf{}~Limit wait stacks time range} -- limits wait stacks results. Refer to chapter~\ref{waitstackswindow}.
|
||||
\item \emph{\faMemory{}~Limit memory time range} -- limits memory results. Read more about this in chapter~\ref{memorywindow}.
|
||||
\item \emph{\faStickyNote{}~Add annotation} -- use to annotate regions of interest, as described in chapter~\ref{annotatingtrace}.
|
||||
@@ -4050,6 +4051,67 @@ To see what changes were made in the source code between the two compared traces
|
||||
|
||||
Please note that changes will be registered only if the file has the same name and location in both traces. Tracy does not resolve file renames or moves.
|
||||
|
||||
\subsection{Flame graph}
|
||||
\label{flamegraph}
|
||||
|
||||
The flame graph is a way of showing the general performance characteristics of a program on a single chart. While the timeline view displays each zone individually, the flame graph aggregates all zones into a tree structure that better conveys where the application spends its time in relation to the program flow.
|
||||
|
||||
Figure~\ref{flamegraphfigure} shows an example flame graph. The graph shows that the program has been running for 11 seconds. Looking at the top row of the zones tree, we see that during this time one second was spent in the \emph{Init} zone and the remaining ten seconds in the \emph{Game loop} zone.
|
||||
|
||||
The rows below show the zone times of the child functions. For example, the \emph{Game loop} zone goes into the \emph{Logic update} and \emph{Render} zones. Only one aggregated \emph{Logic update} and \emph{Render} zone is displayed, even though the \emph{Game loop} would enter these functions hundreds of times in a 10-second span.
|
||||
|
||||
There are two different \emph{Raycast} zones on the graph. This is because there are two code paths that lead to this function, and the graph distinguishes between them.
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering\begin{tikzpicture}
|
||||
\foreach \x in {0,1,2,...,10} {
|
||||
\draw (\x+0, 0) -- +(0, -0.4);
|
||||
\draw (\x+0.1, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.2, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.3, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.4, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.5, 0) -- +(0, -0.3);
|
||||
\draw (\x+0.6, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.7, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.8, 0) -- +(0, -0.2);
|
||||
\draw (\x+0.9, 0) -- +(0, -0.2); }
|
||||
\draw (11, 0) -- +(0, -0.4);
|
||||
|
||||
\draw (-0.2, -0.4) node[anchor=north west] {0};
|
||||
\draw (1.85, -0.4) node[anchor=north west] {2 \si{\second}};
|
||||
\draw (3.85, -0.4) node[anchor=north west] {4 \si{\second}};
|
||||
\draw (5.85, -0.4) node[anchor=north west] {6 \si{\second}};
|
||||
\draw (7.85, -0.4) node[anchor=north west] {8 \si{\second}};
|
||||
\draw (9.85, -0.4) node[anchor=north west] {10 \si{\second}};
|
||||
|
||||
\draw(0, -1) rectangle+(1, -0.5) node[midway] {Init};
|
||||
\draw(1, -1) rectangle+(10, -0.5) node[midway] {Game loop};
|
||||
\draw(0, -1.5) rectangle+(0.1, -0.5);
|
||||
\draw(0.1, -1.5) rectangle+(0.3, -0.5);
|
||||
\draw(0.4, -1.5) rectangle+(0.2, -0.5);
|
||||
\draw(1, -1.5) rectangle+(7, -0.5) node[midway] {Logic update};
|
||||
\draw(8, -1.5) rectangle+(2, -0.5) node[midway] {Render};
|
||||
\draw(1, -2) rectangle+(3, -0.5) node[midway] {AI};
|
||||
\draw(4, -2) rectangle+(2, -0.5) node[midway] {Projectiles};
|
||||
\draw(6, -2) rectangle+(1.5, -0.5) node[midway] {Particles};
|
||||
\draw(1, -2.5) rectangle+(1, -0.5) node[midway] {A*};
|
||||
\draw(2, -2.5) rectangle+(1.5, -0.5) node[midway] {Raycast};
|
||||
\draw(4, -2.5) rectangle+(1.25, -0.5) node[midway] {Raycast};
|
||||
\end{tikzpicture}
|
||||
\caption{Flame graph.}
|
||||
\label{flamegraphfigure}
|
||||
\end{figure}
|
||||
|
||||
The default sorting order of the zones on a flame graph \emph{approximates} the real call ordering. The program will call \emph{Init} before entering \emph{Game loop}, and each frame update will call \emph{Logic update} before doing \emph{Render}. This order is preserved. However, the logic update function may need to interleave the processing of AI entities and projectile movement\footnote{Such design would be less than ideal, but sometimes that's how you have to go.}. This interleaving won't be represented on the graph. Each zone will be placed in the appropriate bin in a first-come, first-served manner.
|
||||
|
||||
You can use an alternative sorting method by enabling the \emph{Sort by time} option. This will place the most time-consuming zones first (to the left) on the graph.
|
||||
|
||||
Similar to the statistics window (section~\ref{statistics}), the flame graph can operate in two modes: \emph{\faSyringe{}~Instrumentation} and \emph{\faEyeDropper{}~Sampling}. In the instrumentation mode, the graph represents the zones you put in your program. In the sampling mode, the graph is constructed from the automatically captured call stack data (section~\ref{sampling}).
|
||||
|
||||
In the sampling mode you can exclude \emph{external frames} from the graph, which typically would be internal implementation details of starting threads, handling smart pointers, and other such things that are quick to execute and not really interesting. This leaves only the frames from your code. One exception is \emph{external tails}, or calls that your code makes that do not eventually land in your application down the call chain. Think of functions that write to a file or send data on the network. These can be time-consuming, and you may want to see them. There is a separate option to disable these.
|
||||
|
||||
The flame graph can be restricted to a specific time extent using the \emph{Limit range} option (chapter~\ref{timeranges}). You can access more options through the \emph{\faRuler{}~Limits} button, which will open the time range limits window, described in section~\ref{timerangelimits}.
|
||||
|
||||
\subsection{Memory window}
|
||||
\label{memorywindow}
|
||||
|
||||
@@ -4461,7 +4523,7 @@ A new view-sized annotation can be added in this window by pressing the \emph{\f
|
||||
\subsection{Time range limits}
|
||||
\label{timerangelimits}
|
||||
|
||||
This window displays information about time range limits (section~\ref{timeranges}) for find zone (section~\ref{findzone}), statistics (section~\ref{statistics}), memory (section~\ref{memorywindow}) and wait stacks (section~\ref{waitstackswindow}) results. Each limit can be enabled or disabled and adjusted through the following options:
|
||||
This window displays information about time range limits (section~\ref{timeranges}) for find zone (section~\ref{findzone}), statistics (section~\ref{statistics}), flame graph (section~\ref{flamegraph}), memory (section~\ref{memorywindow}) and wait stacks (section~\ref{waitstackswindow}) results. Each limit can be enabled or disabled and adjusted through the following options:
|
||||
|
||||
\begin{itemize}
|
||||
\item \emph{Limit to view} -- Set the time range limit to current view.
|
||||
@@ -4587,7 +4649,7 @@ The profiler never prunes user settings.
|
||||
|
||||
\section{License}
|
||||
|
||||
\verbatiminput{../LICENSE.}
|
||||
\verbatiminput{../LICENSE}
|
||||
|
||||
\section{Inventory of external libraries}
|
||||
|
||||
@@ -4600,6 +4662,7 @@ The following libraries are included with and used by the Tracy Profiler. Entrie
|
||||
\item libbacktrace \faStar{} -- \url{https://github.com/ianlancetaylor/libbacktrace}
|
||||
\item Zstandard -- \url{https://github.com/facebook/zstd}
|
||||
\item Diff Template Library -- \url{https://github.com/cubicdaiya/dtl}
|
||||
\item Capstone -- \url{https://github.com/capstone-engine/capstone}
|
||||
\end{itemize}
|
||||
|
||||
\item 2-clause BSD license
|
||||
@@ -4622,6 +4685,7 @@ The following libraries are included with and used by the Tracy Profiler. Entrie
|
||||
\item Native File Dialog Extended -- \url{https://github.com/btzy/nativefiledialog-extended}
|
||||
\item IconFontCppHeaders -- \url{https://github.com/juliettef/IconFontCppHeaders}
|
||||
\item pdqsort -- \url{https://github.com/orlp/pdqsort}
|
||||
\item glfw -- \url{https://www.glfw.org/}
|
||||
\end{itemize}
|
||||
|
||||
\item MIT license
|
||||
@@ -4631,6 +4695,14 @@ The following libraries are included with and used by the Tracy Profiler. Entrie
|
||||
\item robin-hood-hashing -- \url{https://github.com/martinus/robin-hood-hashing}
|
||||
\item SPSCQueue \faStar{} -- \url{https://github.com/rigtorp/SPSCQueue}
|
||||
\item ini -- \url{https://github.com/rxi/ini}
|
||||
\item PPQSort -- \url{https://github.com/GabTux/PPQSort}
|
||||
\item wayland-protocols -- \url{https://gitlab.freedesktop.org/wayland/wayland-protocols}
|
||||
\item JSON for Modern C++ -- \url{https://github.com/nlohmann/json}
|
||||
\end{itemize}
|
||||
|
||||
\item FreeType License
|
||||
\begin{itemize}
|
||||
\item FreeType -- \url{https://freetype.org/}
|
||||
\end{itemize}
|
||||
|
||||
\item Apache license 2.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project('tracy', ['cpp'], version: '0.12.0', meson_version: '>=1.3.0', default_options : ['cpp_std=c++11'])
|
||||
project('tracy', ['cpp'], version: '0.12.2', meson_version: '>=1.3.0', default_options : ['cpp_std=c++11'])
|
||||
|
||||
# internal compiler flags
|
||||
tracy_compile_args = []
|
||||
@@ -132,6 +132,7 @@ endif
|
||||
includes = [
|
||||
'public/tracy/TracyC.h',
|
||||
'public/tracy/Tracy.hpp',
|
||||
'public/tracy/TracyCUDA.hpp',
|
||||
'public/tracy/TracyD3D11.hpp',
|
||||
'public/tracy/TracyD3D12.hpp',
|
||||
'public/tracy/TracyLua.hpp',
|
||||
|
||||
@@ -106,6 +106,7 @@ set(LIBS "")
|
||||
|
||||
if(USE_WAYLAND)
|
||||
pkg_check_modules(WAYLAND REQUIRED egl wayland-egl wayland-cursor xkbcommon)
|
||||
set(INCLUDES "${INCLUDES};${WAYLAND_INCLUDE_DIRS}")
|
||||
set(LIBS "${LIBS};${WAYLAND_LIBRARIES}")
|
||||
set(PROFILER_FILES ${PROFILER_FILES}
|
||||
src/BackendWayland.cpp
|
||||
@@ -193,7 +194,8 @@ endif()
|
||||
find_package(Git)
|
||||
if(Git_FOUND)
|
||||
add_custom_target(git-ref
|
||||
COMMAND ${GIT_EXECUTABLE} log -1 "--format=#pragma once %nnamespace tracy { static inline const char* GitRef = %x22%h%x22; }" ${GIT_REV} > GitRef.hpp.tmp
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#pragma once" > GitRef.hpp.tmp
|
||||
COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} log -1 "--format=namespace tracy { static inline const char* GitRef = %x22%h%x22; }" ${GIT_REV} >> GitRef.hpp.tmp || echo "namespace tracy { static inline const char* GitRef = \"unknown\"; }" >> GitRef.hpp.tmp
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different GitRef.hpp.tmp GitRef.hpp
|
||||
BYPRODUCTS GitRef.hpp GitRef.hpp.tmp
|
||||
VERBATIM
|
||||
|
||||
@@ -166,6 +166,10 @@ void Backend::NewFrame( int& w, int& h )
|
||||
}
|
||||
|
||||
glfwGetFramebufferSize( s_window, &w, &h );
|
||||
#if defined( __APPLE__ )
|
||||
w = static_cast<int>( w / scale );
|
||||
h = static_cast<int>( h / scale );
|
||||
#endif
|
||||
m_w = w;
|
||||
m_h = h;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace tracy
|
||||
{
|
||||
|
||||
constexpr ProtocolHistory_t ProtocolHistoryArr[] = {
|
||||
{ 74, FileVersion( 0, 12, 0 ) },
|
||||
{ 74, FileVersion( 0, 12, 0 ), FileVersion( 0, 12, 2 ) },
|
||||
{ 69, FileVersion( 0, 11, 1 ) },
|
||||
{ 66, FileVersion( 0, 11, 0 ) },
|
||||
{ 64, FileVersion( 0, 10, 0 ) },
|
||||
|
||||
@@ -808,6 +808,7 @@ bool View::DrawImpl()
|
||||
sprintf( tmp, "%s###Profiler", m_worker.GetCaptureName().c_str() );
|
||||
ImGui::SetNextWindowSize( ImVec2( 1550, 800 ), ImGuiCond_FirstUseEver );
|
||||
ImGui::Begin( tmp, keepOpenPtr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoBringToFrontOnFocus );
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
#endif
|
||||
|
||||
if( !m_staticView )
|
||||
@@ -1172,6 +1173,12 @@ bool View::DrawImpl()
|
||||
m_statRange.min = s;
|
||||
m_statRange.max = e;
|
||||
}
|
||||
if( ImGui::Selectable( ICON_FA_FIRE_FLAME_CURVED " Limit flame time range" ) )
|
||||
{
|
||||
m_flameRange.active = true;
|
||||
m_flameRange.min = s;
|
||||
m_flameRange.max = e;
|
||||
}
|
||||
if( ImGui::Selectable( ICON_FA_HOURGLASS_HALF " Limit wait stacks range" ) )
|
||||
{
|
||||
m_waitStackRange.active = true;
|
||||
|
||||
@@ -167,6 +167,7 @@ public:
|
||||
|
||||
bool m_showRanges = false;
|
||||
Range m_statRange;
|
||||
Range m_flameRange;
|
||||
Range m_waitStackRange;
|
||||
|
||||
private:
|
||||
@@ -377,6 +378,7 @@ private:
|
||||
int64_t GetZoneSelfTime( const ZoneEvent& zone );
|
||||
int64_t GetZoneSelfTime( const GpuEvent& zone );
|
||||
bool GetZoneRunningTime( const ContextSwitch* ctx, const ZoneEvent& ev, int64_t& time, uint64_t& cnt );
|
||||
bool GetZoneRunningTime( const ContextSwitch* ctx, const ZoneEvent& ev, const RangeSlim& range, int64_t& time, uint64_t& cnt );
|
||||
const char* GetThreadContextData( uint64_t thread, bool& local, bool& untracked, const char*& program );
|
||||
|
||||
tracy_force_inline void CalcZoneTimeData( unordered_flat_map<int16_t, ZoneTimeData>& data, int64_t& ztime, const ZoneEvent& zone );
|
||||
@@ -926,6 +928,7 @@ private:
|
||||
{
|
||||
uint64_t count = 0;
|
||||
uint64_t lastTime = 0;
|
||||
RangeSlim range = {false, 0, 0};
|
||||
|
||||
void Reset()
|
||||
{
|
||||
|
||||
@@ -307,6 +307,7 @@ void View::DrawFindZone()
|
||||
|
||||
if( ImGui::Button( ICON_FA_BAN " Clear" ) )
|
||||
{
|
||||
m_findZone.pattern[0] = '\0';
|
||||
m_findZone.Reset();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
@@ -27,7 +27,17 @@ void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& d
|
||||
{
|
||||
if( !v.IsEndValid() ) break;
|
||||
const auto srcloc = v.SrcLoc();
|
||||
const auto duration = v.End() - v.Start();
|
||||
|
||||
auto start = v.Start();
|
||||
auto end = v.End();
|
||||
|
||||
if ( m_flameGraphInvariant.range.active )
|
||||
{
|
||||
start = std::clamp(start, m_flameGraphInvariant.range.min, m_flameGraphInvariant.range.max);
|
||||
end = std::clamp(end, m_flameGraphInvariant.range.min, m_flameGraphInvariant.range.max);
|
||||
}
|
||||
|
||||
const auto duration = end - start;
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
@@ -70,7 +80,17 @@ void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& d
|
||||
{
|
||||
if( !v->IsEndValid() ) break;
|
||||
const auto srcloc = v->SrcLoc();
|
||||
const auto duration = v->End() - v->Start();
|
||||
|
||||
auto start = v->Start();
|
||||
auto end = v->End();
|
||||
|
||||
if ( m_flameGraphInvariant.range.active )
|
||||
{
|
||||
start = std::clamp(start, m_flameGraphInvariant.range.min, m_flameGraphInvariant.range.max);
|
||||
end = std::clamp(end, m_flameGraphInvariant.range.min, m_flameGraphInvariant.range.max);
|
||||
}
|
||||
|
||||
const auto duration = end - start;
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
@@ -124,7 +144,15 @@ void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& d
|
||||
const auto srcloc = v.SrcLoc();
|
||||
int64_t duration;
|
||||
uint64_t cnt;
|
||||
if( !GetZoneRunningTime( ctx, v, duration, cnt ) ) break;
|
||||
if ( m_flameRange.active )
|
||||
{
|
||||
if( !GetZoneRunningTime( ctx, v, m_flameGraphInvariant.range, duration, cnt ) ) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !GetZoneRunningTime( ctx, v, duration, cnt ) ) break;
|
||||
}
|
||||
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
@@ -169,7 +197,15 @@ void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& d
|
||||
const auto srcloc = v->SrcLoc();
|
||||
int64_t duration;
|
||||
uint64_t cnt;
|
||||
if( !GetZoneRunningTime( ctx, *v, duration, cnt ) ) break;
|
||||
if ( m_flameRange.active )
|
||||
{
|
||||
if( !GetZoneRunningTime( ctx, *v, m_flameGraphInvariant.range, duration, cnt ) ) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !GetZoneRunningTime( ctx, *v, duration, cnt ) ) break;
|
||||
}
|
||||
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
@@ -221,6 +257,15 @@ void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& d
|
||||
|
||||
for( auto& v : samples )
|
||||
{
|
||||
if ( m_flameGraphInvariant.range.active )
|
||||
{
|
||||
if ( v.time.Val() < m_flameGraphInvariant.range.min ||
|
||||
v.time.Val() > m_flameGraphInvariant.range.max )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cache.clear();
|
||||
|
||||
const auto cs = v.callstack.Val();
|
||||
@@ -730,6 +775,24 @@ void View::DrawFlameGraph()
|
||||
if( m_flameExternal ) ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
if( ImGui::Checkbox( "Limit range", &m_flameRange.active ) )
|
||||
{
|
||||
if( m_flameRange.active && m_flameRange.min == 0 && m_flameRange.max == 0 )
|
||||
{
|
||||
m_flameRange.min = m_vd.zvStart;
|
||||
m_flameRange.max = m_vd.zvEnd;
|
||||
}
|
||||
|
||||
m_flameGraphInvariant.Reset();
|
||||
}
|
||||
if( m_flameRange.active )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
TextColoredUnformatted( 0xFF00FFFF, ICON_FA_TRIANGLE_EXCLAMATION );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_RULER " Limits", m_showRanges );
|
||||
}
|
||||
|
||||
auto& td = m_worker.GetThreadData();
|
||||
auto expand = ImGui::TreeNode( ICON_FA_SHUFFLE " Visible threads:" );
|
||||
ImGui::SameLine();
|
||||
@@ -791,8 +854,11 @@ void View::DrawFlameGraph()
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if( m_flameMode == 0 && ( m_flameGraphInvariant.count != m_worker.GetZoneCount() || m_flameGraphInvariant.lastTime != m_worker.GetLastTime() ) ||
|
||||
m_flameMode == 1 && ( m_flameGraphInvariant.count != m_worker.GetCallstackSampleCount() ) )
|
||||
m_flameMode == 1 && ( m_flameGraphInvariant.count != m_worker.GetCallstackSampleCount() ) ||
|
||||
m_flameGraphInvariant.range != m_flameRange )
|
||||
{
|
||||
m_flameGraphInvariant.range = m_flameRange;
|
||||
|
||||
size_t sz = 0;
|
||||
for( auto& thread : td ) if( FlameGraphThread( thread->id ) ) sz++;
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@ void View::DrawRanges()
|
||||
ImGui::Separator();
|
||||
DrawRangeEntry( m_statRange, ICON_FA_ARROW_UP_WIDE_SHORT " Statistics", 0x448888EE, "RangeStatisticsCopyFrom", 1 );
|
||||
ImGui::Separator();
|
||||
DrawRangeEntry( m_waitStackRange, ICON_FA_HOURGLASS_HALF " Wait stacks", 0x44EEB588, "RangeWaitStackCopyFrom", 2 );
|
||||
DrawRangeEntry( m_flameRange, ICON_FA_FIRE_FLAME_CURVED " Flame", 0x4488B5EE, "RangeFlameCopyFrom", 2 );
|
||||
ImGui::Separator();
|
||||
DrawRangeEntry( m_memInfo.range, ICON_FA_MEMORY " Memory", 0x4488EEE3, "RangeMemoryCopyFrom", 3 );
|
||||
DrawRangeEntry( m_waitStackRange, ICON_FA_HOURGLASS_HALF " Wait stacks", 0x44EEB588, "RangeWaitStackCopyFrom", 3 );
|
||||
ImGui::Separator();
|
||||
DrawRangeEntry( m_memInfo.range, ICON_FA_MEMORY " Memory", 0x4488EEE3, "RangeMemoryCopyFrom", 4 );
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -79,9 +81,14 @@ void View::DrawRangeEntry( Range& range, const char* label, uint32_t color, cons
|
||||
if( id != 2 )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if( SmallButtonDisablable( ICON_FA_HOURGLASS_HALF " Copy from wait stacks", m_waitStackRange.min == 0 && m_waitStackRange.max == 0 ) ) range = m_waitStackRange;
|
||||
if( SmallButtonDisablable( ICON_FA_FIRE_FLAME_CURVED " Copy from flame", m_flameRange.min == 0 && m_flameRange.max == 0 ) ) range = m_flameRange;
|
||||
}
|
||||
if( id != 3 )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if( SmallButtonDisablable( ICON_FA_HOURGLASS_HALF " Copy from wait stacks", m_waitStackRange.min == 0 && m_waitStackRange.max == 0 ) ) range = m_waitStackRange;
|
||||
}
|
||||
if( id != 4 )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if( SmallButtonDisablable( ICON_FA_MEMORY " Copy from memory", m_memInfo.range.min == 0 && m_memInfo.range.max == 0 ) ) range = m_memInfo.range;
|
||||
|
||||
@@ -254,6 +254,7 @@ void View::DrawTimeline()
|
||||
m_zoneHover2.Decay( nullptr );
|
||||
m_findZone.range.StartFrame();
|
||||
m_statRange.StartFrame();
|
||||
m_flameRange.StartFrame();
|
||||
m_waitStackRange.StartFrame();
|
||||
m_memInfo.range.StartFrame();
|
||||
m_yDelta = 0;
|
||||
@@ -283,6 +284,7 @@ void View::DrawTimeline()
|
||||
{
|
||||
HandleRange( m_findZone.range, timespan, ImGui::GetCursorScreenPos(), w );
|
||||
HandleRange( m_statRange, timespan, ImGui::GetCursorScreenPos(), w );
|
||||
HandleRange( m_flameRange, timespan, ImGui::GetCursorScreenPos(), w );
|
||||
HandleRange( m_waitStackRange, timespan, ImGui::GetCursorScreenPos(), w );
|
||||
HandleRange( m_memInfo.range, timespan, ImGui::GetCursorScreenPos(), w );
|
||||
for( auto& v : m_annotations )
|
||||
@@ -495,6 +497,15 @@ void View::DrawTimeline()
|
||||
DrawLine( draw, ImVec2( dpos.x + px1, linepos.y + 0.5f ), ImVec2( dpos.x + px1, linepos.y + lineh + 0.5f ), m_statRange.hiMax ? 0x998888EE : 0x338888EE, m_statRange.hiMax ? 2 : 1 );
|
||||
}
|
||||
|
||||
if( m_flameRange.active && ( m_showFlameGraph || m_showRanges ) )
|
||||
{
|
||||
const auto px0 = ( m_flameRange.min - m_vd.zvStart ) * pxns;
|
||||
const auto px1 = std::max( px0 + std::max( 1.0, pxns * 0.5 ), ( m_flameRange.max - m_vd.zvStart ) * pxns );
|
||||
DrawStripedRect( draw, wpos, px0, linepos.y, px1, linepos.y + lineh, 10 * scale, 0x2288B5EE, true, false );
|
||||
DrawLine( draw, ImVec2( dpos.x + px0, linepos.y + 0.5f ), ImVec2( dpos.x + px0, linepos.y + lineh + 0.5f ), m_flameRange.hiMin ? 0x9988B5EE : 0x3388B5EE, m_flameRange.hiMin ? 2 : 1 );
|
||||
DrawLine( draw, ImVec2( dpos.x + px1, linepos.y + 0.5f ), ImVec2( dpos.x + px1, linepos.y + lineh + 0.5f ), m_flameRange.hiMax ? 0x9988B5EE : 0x3388B5EE, m_flameRange.hiMax ? 2 : 1 );
|
||||
}
|
||||
|
||||
if( m_waitStackRange.active && ( m_showWaitStacks || m_showRanges ) )
|
||||
{
|
||||
const auto px0 = ( m_waitStackRange.min - m_vd.zvStart ) * pxns;
|
||||
|
||||
@@ -737,6 +737,35 @@ bool View::GetZoneRunningTime( const ContextSwitch* ctx, const ZoneEvent& ev, in
|
||||
return true;
|
||||
}
|
||||
|
||||
bool View::GetZoneRunningTime( const ContextSwitch* ctx, const ZoneEvent& ev, const RangeSlim& range, int64_t& time, uint64_t& cnt )
|
||||
{
|
||||
const auto start = std::max( ev.Start(), range.min );
|
||||
auto it = std::lower_bound( ctx->v.begin(), ctx->v.end(), start, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } );
|
||||
if( it == ctx->v.end() ) return false;
|
||||
const auto end = std::min( m_worker.GetZoneEnd( ev ), range.max );
|
||||
const auto eit = std::upper_bound( it, ctx->v.end(), end, [] ( const auto& l, const auto& r ) { return l < r.Start(); } );
|
||||
if( eit == ctx->v.end() ) return false;
|
||||
cnt = std::distance( it, eit );
|
||||
if( cnt == 0 ) return false;
|
||||
if( cnt == 1 )
|
||||
{
|
||||
time = end - start;
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t running = it->End() - start;
|
||||
++it;
|
||||
for( uint64_t i=0; i<cnt-2; i++ )
|
||||
{
|
||||
running += it->End() - it->Start();
|
||||
++it;
|
||||
}
|
||||
running += end - it->Start();
|
||||
time = running;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* View::SourceSubstitution( const char* srcFile ) const
|
||||
{
|
||||
if( !m_sourceRegexValid || m_sourceSubstitutions.empty() ) return srcFile;
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
# include <inttypes.h>
|
||||
# include <intrin.h>
|
||||
# include "../common/TracyUwp.hpp"
|
||||
# ifndef _MSC_VER
|
||||
# include <excpt.h>
|
||||
# endif
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
# include <sys/param.h>
|
||||
@@ -909,6 +912,13 @@ LONG WINAPI CrashFilter( PEXCEPTION_POINTERS pExp )
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined _WIN32 && !defined _MSC_VER
|
||||
LONG WINAPI CrashFilterExecute( PEXCEPTION_POINTERS pExp )
|
||||
{
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Profiler* s_instance = nullptr;
|
||||
static Thread* s_thread;
|
||||
#ifndef TRACY_NO_FRAME_IMAGE
|
||||
@@ -1511,7 +1521,7 @@ void Profiler::InstallCrashHandler()
|
||||
#if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER
|
||||
// We cannot use Vectored Exception handling because it catches application-wide frame-based SEH blocks. We only
|
||||
// want to catch unhandled exceptions.
|
||||
m_prevHandler = SetUnhandledExceptionFilter( CrashFilter );
|
||||
m_prevHandler = reinterpret_cast<void*>( SetUnhandledExceptionFilter( CrashFilter ) );
|
||||
#endif
|
||||
|
||||
#ifndef TRACY_NO_CRASH_HANDLER
|
||||
@@ -3122,6 +3132,7 @@ char* Profiler::SafeCopyProlog( const char* data, size_t size )
|
||||
if( size > SafeSendBufferSize ) buf = (char*)tracy_malloc( size );
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _MSC_VER
|
||||
__try
|
||||
{
|
||||
memcpy( buf, data, size );
|
||||
@@ -3130,6 +3141,9 @@ char* Profiler::SafeCopyProlog( const char* data, size_t size )
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
# else
|
||||
memcpy( buf, data, size );
|
||||
# endif
|
||||
#else
|
||||
// Send through the pipe to ensure safe reads
|
||||
for( size_t offset = 0; offset != size; /*in loop*/ )
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Version
|
||||
{
|
||||
enum { Major = 0 };
|
||||
enum { Minor = 12 };
|
||||
enum { Patch = 0 };
|
||||
enum { Patch = 2 };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,13 @@ TRACY_API LuaZoneState& GetLuaZoneState();
|
||||
namespace detail
|
||||
{
|
||||
|
||||
static inline void LuaShortenSrc( char* dst, const char* src )
|
||||
{
|
||||
size_t l = std::min( (size_t)255, strlen( src ) );
|
||||
memcpy( dst, src, l );
|
||||
dst[l] = 0;
|
||||
}
|
||||
|
||||
#ifdef TRACY_HAS_CALLSTACK
|
||||
static tracy_force_inline void SendLuaCallstack( lua_State* L, uint32_t depth )
|
||||
{
|
||||
@@ -190,13 +197,6 @@ static tracy_force_inline void SendLuaCallstack( lua_State* L, uint32_t depth )
|
||||
TracyQueueCommit( callstackAllocFatThread );
|
||||
}
|
||||
|
||||
static inline void LuaShortenSrc( char* dst, const char* src )
|
||||
{
|
||||
size_t l = std::min( (size_t)255, strlen( src ) );
|
||||
memcpy( dst, src, l );
|
||||
dst[l] = 0;
|
||||
}
|
||||
|
||||
static inline int LuaZoneBeginS( lua_State* L )
|
||||
{
|
||||
#ifdef TRACY_ON_DEMAND
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
||||
|
||||
set(NO_STATISTICS ON)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ bool ApplyPathSubstitutions( std::string& path, const PathSubstitutionList& path
|
||||
{
|
||||
for( const auto& substitution : pathSubstitutionlist )
|
||||
{
|
||||
if( std::regex_match(path, substitution.first) )
|
||||
if( std::regex_search(path, substitution.first) )
|
||||
{
|
||||
path = std::regex_replace( path, substitution.first, substitution.second );
|
||||
return true;
|
||||
@@ -168,4 +168,4 @@ void PatchSymbols( tracy::Worker& worker, const std::vector<std::string>& pathSu
|
||||
{
|
||||
std::cerr << "Failed to patch symbols" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
const size_t startIdx = entryIdx;
|
||||
const size_t batchEndIdx = std::min( inputEntryList.size(), startIdx + (size_t)1024 );
|
||||
|
||||
printf( "Resolving symbols [%zu-%zu[\n", startIdx, batchEndIdx );
|
||||
printf( "Resolving symbols [%zu-%zu]\n", startIdx, batchEndIdx );
|
||||
|
||||
// generate a single addr2line cmd line for all addresses in one invocation
|
||||
std::stringstream ss;
|
||||
|
||||
Reference in New Issue
Block a user