Skip to content

Latest commit

 

History

History
106 lines (84 loc) · 4.61 KB

File metadata and controls

106 lines (84 loc) · 4.61 KB

Profiling driftwm

driftwm is instrumented with Tracy behind the profile-with-tracy cargo feature. The feature compiles out completely when off — no runtime or binary cost in normal builds — so the instrumentation stays in the tree permanently.

1. Build the Tracy server (one time)

The GUI/CLI server must match the tracy-client crate version in Cargo.toml (currently 0.18.x → Tracy v0.13.x). Distro packages are often mismatched or ship no aarch64 GUI, so build from source:

git clone https://github.com/wolfpld/tracy ~/tracy
cd ~/tracy
git checkout v0.13.1          # match the tracy-client version table
# GUI (optional, needs GTK/wayland dev libs):
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
cmake --build profiler/build -j2     # -j2: template-heavy, ~1-2 GB/core
# CSV exporter (required for dev/scripts/tracy_analyze.py):
cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release
cmake --build csvexport/build -j2

If GCC rejects tracy_robin_hood.h (UINT64_C not declared), add #include <cstdint> near the top of ~/tracy/server/tracy_robin_hood.h.

2. Capture

cargo run --release --features profile-with-tracy            # udev (from a TTY)
cargo run --release --features profile-with-tracy -- ...     # winit (nested)

Connect the live GUI (~/tracy/profiler/build/tracy-profiler) before or during the run, then drive the interaction you want to measure (pan, zoom, a window animation). Save the capture to a .tracy file from the GUI.

Tips for a clean capture:

  • Profile one interaction at a time on an empty canvas when measuring the background, so the background dominates the frame.
  • Pan/animate continuously for several seconds — steady-state cadence matters more than one-off frames.
  • The render loop parks when nothing moves, so idle pauses appear as multi-second frame intervals. The analyzer filters these out (see below).

Cargo features:

  • profile-with-tracy — spans + frame marks.
  • profile-with-tracy-ondemand — only profiles while a server is connected.
  • profile-with-tracy-allocations — also profile the global allocator.

3. Analyze

dev/scripts/tracy_analyze.py CAPTURE.tracy

Reports per-zone exec times and the active frame cadence (idle gaps >100 ms removed), classified by vblank multiple (1 vblank ≈ 60 fps, 2 ≈ 30 fps).

The analyzer is generic: when a code path emits a Tracy plot, bucket frame times by it. The chunked tile-bg plots bg_chunks.target_lod, so:

dev/scripts/tracy_analyze.py CAPTURE.tracy --bucket-by bg_chunks.target_lod

gives per-LOD frame-time tables (both exec time and frame-to-frame interval — the interval table is the one that shows stutter). Any future plot works the same way — add the plot in the code, pass its name to --bucket-by, no script change needed. For the winit backend, pass --frame-zone winit::frame (the default is udev::render_frame).

Per-frame diagnostic plots emitted by the compositor:

  • frame.commits — wl_surface commits since the previous rendered frame (udev only; reset every render, so single-output sessions only). Bucketing intervals by this tests whether stutter correlates with client rendering activity (GPU contention from client work).
  • frame.visible_windows / frame.shadow_elems — composition load per frame, emitted from compose_frame (both backends). Bucketing by these tests whether stutter scales with window/shadow count.

--gpu adds GPU zone stats (smithay's tracy_gpu_profiling timer queries), split by proximity to slow frames. Reading it: if fixed-work zones (clear, draw_solid) stretch near slow frames while their calm medians stay normal, the whole GPU is intermittently stalled/contended — pointing at GPU contention (e.g. client rendering) or power-state dips rather than any one expensive shader.

The script finds tracy-csvexport via $TRACY_CSVEXPORT, then PATH, then ~/tracy/csvexport/build/.

Where instrumentation lives

  • src/main.rs — Tracy client startup + optional profiling allocator.
  • src/backend/udev.rs / src/backend/winit.rs — per-frame span + frame mark. udev render_frame splits into udev::build_cursor_elements, udev::compositor_render_frame, udev::queue_frame, udev::captures, udev::post_render.
  • src/render/mod.rscompose_frame span, split into compose::windows, compose::layers, compose::blur.
  • src/render/shader_chunks.rsShaderChunkCache::render_elements span, with a per-bake bake::alloc / bake::render split.
  • src/render/tile_chunks.rs — chunked tile-bg spans + bg_chunks.* plots.