tracy(1)
Tracy is a frame profiler, supporting manual code instrumentation and providing a sampling profiler.
One can either record and visualize the profiling data live using
tracy-profiler
or record the profiling data to a file using tracy-capture
.
tracy-profiler [file] [-p port]
tracy-capture -o file [-f] [-p port]
-f overwrite <file> if it exists
Example
The example showcases different cases:
- Use tracy from a single binary. In that case the
TracyClient.cpp
can be directly linked / included in the instrumented binary. - Use tracy from different binaries (eg main executable + shared library). In
this case the
TracyClient.cpp
should be compiled into its own shared library, such that there is a single tracy client. - Use tracy from different binaries on windows. In this case the
TracyClient.cpp
must be compiled again into a separate shared library, while definingTRACY_EXPORTS
. The code being instrumented must be compiled withTRACY_IMPORTS
defined.
An instrumented c++
example:
#include <chrono>
#include <thread>
#include <tracy/Tracy.hpp>
#ifdef USE_FOO
extern "C" void foo_comp_hook(int64_t);
#endif
void init() {
// Create a named zone (active for the current scope).
// Name will be used when rendering the zone in the thread timeline.
ZoneScopedN("init()");
// Set explicit color for the rendered zone.
ZoneColor(0xff0000);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void comp(const char* name) {
// Track call count.
static int64_t ccnt = 0;
ccnt += 1;
// Create an unnamed zone for the current scope.
ZoneScoped;
// Name the zone by formatting the name dynamically.
// This name is shown for the zone in the thread timeline, however
// in the zone statistics they are all accounted under one common
// zone "comp".
ZoneNameF("comp(%s)", name);
// Additional text to attach to the zone.
ZoneTextF("text(%s)", name);
// Additional value to attach to the zone measurement.
ZoneValue(ccnt);
// Statistics for dynamic names, text and values can be looked at in the zone
// statistics.There measurements can be grouped by different categories.
// Add a simple plot.
TracyPlot("comp-plot", ccnt % 4);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
#ifdef USE_FOO
foo_comp_hook(ccnt);
#endif
}
void post_comp() {
// Create an unnamed zone for the current scope and capture callstack (max
// depth 10). Capturing callstack requires platform with TRACY_HAS_CALLSTACK
// support.
ZoneScopedS(10);
// Name the zone, w/o formatting.
const char name[] = "post_comp()";
ZoneName(name, sizeof(name));
// Add trace messages to the timeline.
TracyMessageL("start sleep in post_comp()");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
TracyMessageL("end sleep in post_comp()");
}
void fini() {
// Create a named zone with an explicit color.
ZoneScopedNC("fini()", 0x00ff00);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main() {
// Create a named zone.
ZoneScopedN("main()");
init();
int step = 0;
while (step++ < 10) {
// Create a frame message, this start a new frame with the name
// "step" and end the previous frame with the name "step".
FrameMarkNamed("step");
// Create a named scope.
ZoneScopedN("step()");
comp("a");
comp("b");
comp("c");
post_comp();
}
fini();
}
An instrumented c
example:
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <tracy/TracyC.h>
static void comp_helper(int64_t i) {
char buf[64];
int cnt = snprintf(buf, sizeof(buf), "helper(%" PRId64 ")", i);
// Create an active unnamed zone.
TracyCZone(ctx, 1);
// Name the zone.
TracyCZoneName(ctx, buf, cnt);
// Add custom text to the zone measurement.
TracyCZoneText(ctx, buf, cnt);
// Add custom value to the zone measurement.
TracyCZoneValue(ctx, i);
for (int ii = 0; ii < i * 100000; ++ii) {
/* fake work */
}
// End the zone measurement.
TracyCZoneEnd(ctx);
}
void foo_comp_hook(int64_t cnt) {
// Create an active named zone.
TracyCZoneN(ctx, "foo", 1);
for (int i = 0; i < cnt; ++i) {
// Plot value.
TracyCPlot("foo_comp_hook", cnt + i);
comp_helper(i);
}
// Configure plot "foo", probably best done once during initialization..
TracyCPlotConfig("foo", TracyPlotFormatNumber, 1 /* step */, 1 /* fill */,
0xff0000);
// Plot value.
TracyCPlot("foo", cnt);
// End the zone measurement.
TracyCZoneEnd(ctx);
}
Raw build commands to demonstrate compiling tracy w/o cmake
, in case we need
to integrate it into a different build system.
B := BUILD
main: $(B)/main-static $(B)/main-dynamic $(B)/main-dynamic-win
tracy: $(B)/tracy
.PHONY: main tracy
# -- TRACY STATIC ---------------------------------------------------------------
$(B)/main-static: main.cpp | $(B)
clang++ -DTRACY_ENABLE -I$(B)/tracy/public -o $@ $^ $(B)/tracy/public/TracyClient.cpp
# -- TRACY DYNAMIC --------------------------------------------------------------
$(B)/main-dynamic: main.cpp $(B)/foo.so $(B)/TracyClient.so | $(B)
clang++ -DTRACY_ENABLE -I$(B)/tracy/public -DUSE_FOO -o $@ $^
$(B)/foo.so: foo.c $(B)/TracyClient.so
clang -DTRACY_ENABLE -I$(B)/tracy/public -fPIC -shared -o $@ $^
$(B)/TracyClient.so: $(B)/tracy/public/TracyClient.cpp
clang++ -DTRACY_ENABLE -I$(B)/tracy/public -fPIC -shared -o $@ $^
# -- TRACY DYNAMIC WINDOWS ------------------------------------------------------
$(B)/main-dynamic-win: main.cpp $(B)/foo.dll $(B)/TracyClient.dll
@# eg run with wine
zig c++ -target x86_64-windows -DTRACY_ENABLE -DTRACY_IMPORTS -DUSE_FOO -o $@ $^ -I $(B)/tracy/public
$(B)/foo.dll: foo.c $(B)/TracyClient.dll
zig c++ -target x86_64-windows -DTRACY_ENABLE -DTRACY_IMPORTS -fPIC -shared -o $@ $^ -I $(B)/tracy/public
$(B)/TracyClient.dll: $(B)/tracy/public/TracyClient.cpp
@# win libs from 'pragma comment(lib, ..)'
zig c++ -target x86_64-windows -DTRACY_ENABLE -DTRACY_EXPORTS -fPIC -shared -o $@ $^ -lws2_32 -ldbghelp -ladvapi32 -luser32
# -- TRACY ----------------------------------------------------------------------
# Get latest tracy and build profiler.
$(B)/tracy: $(B)
cd $(B); bash $(CURDIR)/get-tracy.sh
.PHONY: $(B)/tracy
$B:
mkdir -p $(B)
.PHONY: $(B)
# -- CLEAN ----------------------------------------------------------------------
clean:
$(RM) $(B)/*.so $(B)/*.dll $(B)/*.pdb $(B)/*.lib $(B)/main*
distclean:
rm -rf $(B)
Find
get-tracy.sh
here.