diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2025-03-24 00:50:34 +0100 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2025-03-24 00:50:34 +0100 |
commit | 916b73bee95494c205ba67e4a50e6a525afc3a3c (patch) | |
tree | b544937a4a7aeb7a81f3262ed03e434d3da91312 /src | |
parent | 023f5799d537b491151704b15ac59bdaef62c259 (diff) | |
download | notes-master.tar.gz notes-master.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/SUMMARY.md | 1 | ||||
-rw-r--r-- | src/trace_profile/README.md | 1 | ||||
-rw-r--r-- | src/trace_profile/tracy.md | 48 | ||||
-rw-r--r-- | src/trace_profile/tracy/.gitignore | 3 | ||||
-rw-r--r-- | src/trace_profile/tracy/Makefile | 53 | ||||
-rw-r--r-- | src/trace_profile/tracy/foo.c | 48 | ||||
-rw-r--r-- | src/trace_profile/tracy/get-tracy.sh | 39 | ||||
-rw-r--r-- | src/trace_profile/tracy/main.cpp | 91 |
8 files changed, 284 insertions, 0 deletions
diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 145d900..2daa08a 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -54,6 +54,7 @@ - [callgrind](./trace_profile/callgrind.md) - [valgrind](./trace_profile/valgrind.md) - [vtune](./trace_profile/vtune.md) + - [tracy](./trace_profile/tracy.md) - [Debug](./debug/README.md) - [gdb](./debug/gdb.md) diff --git a/src/trace_profile/README.md b/src/trace_profile/README.md index d9635dd..5365aae 100644 --- a/src/trace_profile/README.md +++ b/src/trace_profile/README.md @@ -8,3 +8,4 @@ - [callgrind](./callgrind.md) - [valgrind](./valgrind.md) - [vtune](./vtune.md) +- [tracy](./tracy.md) diff --git a/src/trace_profile/tracy.md b/src/trace_profile/tracy.md new file mode 100644 index 0000000..c6d26d3 --- /dev/null +++ b/src/trace_profile/tracy.md @@ -0,0 +1,48 @@ +# tracy(1) + +[Tracy][gh-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: +1. Use tracy from a single binary. In that case the `TracyClient.cpp` can be + directly linked / included in the instrumented binary. +2. 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. +3. Use tracy from different binaries on windows. In this case the + `TracyClient.cpp` must be compiled again into a separate shared library, + while defining `TRACY_EXPORTS`. The code being instrumented must be compiled + with `TRACY_IMPORTS` defined. + +An instrumented `c++` example: +```cpp +{{#include tracy/main.cpp}} +``` + +An instrumented `c` example: +```c +{{#include tracy/foo.c}} +``` + +Raw build commands to demonstrate compiling tracy w/o `cmake`, in case we need +to integrate it into a different build system. +```makefile +{{#include tracy/Makefile}} +``` +> Find `get-tracy.sh` [here][get-tracy]. + +[gh-tracy]: https://github.com/wolfpld/tracy +[gh-doc]: https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf +[get-tracy]: https://github.com/johannst/notes/blob/master/src/trace_profile/tracy/get-tracy.sh diff --git a/src/trace_profile/tracy/.gitignore b/src/trace_profile/tracy/.gitignore new file mode 100644 index 0000000..83f22d3 --- /dev/null +++ b/src/trace_profile/tracy/.gitignore @@ -0,0 +1,3 @@ +BUILD/ +.cache +compile_commands.json
\ No newline at end of file diff --git a/src/trace_profile/tracy/Makefile b/src/trace_profile/tracy/Makefile new file mode 100644 index 0000000..0d21426 --- /dev/null +++ b/src/trace_profile/tracy/Makefile @@ -0,0 +1,53 @@ +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) diff --git a/src/trace_profile/tracy/foo.c b/src/trace_profile/tracy/foo.c new file mode 100644 index 0000000..e233e68 --- /dev/null +++ b/src/trace_profile/tracy/foo.c @@ -0,0 +1,48 @@ +#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); +} diff --git a/src/trace_profile/tracy/get-tracy.sh b/src/trace_profile/tracy/get-tracy.sh new file mode 100644 index 0000000..4fab480 --- /dev/null +++ b/src/trace_profile/tracy/get-tracy.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# -- DOWNLOAD ------------------------------------------------------------------- + +test -f tracy.json || curl -s -L https://api.github.com/repos/wolfpld/tracy/releases/latest > tracy.json +TRACY_URL=$(cat tracy.json | jq -r .tarball_url) +TRACY_TAG=$(cat tracy.json | jq -r .tag_name) + +echo TRACY_URL $TRACY_URL +echo TRACY_TAG $TRACY_TAG + +if ! test -d tracy; then + wget --no-clobber -O tracy-$TRACY_TAG.tgz $TRACY_URL + mkdir tracy + tar xf tracy-$TRACY_TAG.tgz -C tracy --strip-component 1 + echo $TRACY_TAG > tracy/VERSION +elif ! test $TRACY_TAG = $(cat tracy/VERSION); then + echo -e "\e[1;33mWARN\e[0m: new tracy version available have:$(cat tracy/VERSION) new:$TRACY_TAG" +fi + +export CC=$(which clang) +export CXX=$(which clang++) + +# -- BUILD PROFILER ------------------------------------------------------------- + +if ! test -d build-profiler; then + # Legacy -> x11 + cmake -B build-profiler -S tracy/profiler -DLEGACY=ON +fi + +cmake --build build-profiler -j$(nproc) + +# -- BUILD CAPTURE -------------------------------------------------------------- + +if ! test -d build-capture; then + cmake -B build-capture -S tracy/capture +fi + +cmake --build build-capture/ -j$(nproc) diff --git a/src/trace_profile/tracy/main.cpp b/src/trace_profile/tracy/main.cpp new file mode 100644 index 0000000..62f7637 --- /dev/null +++ b/src/trace_profile/tracy/main.cpp @@ -0,0 +1,91 @@ +#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(); +} |