Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QEMU guest tracing with Tracy

This repository is an experimental bridge between a RISC-V bare-metal guest, QEMU, and the Tracy profiler. The guest emits non-trapping RISC-V HINT instructions. The modified QEMU decodes those hints and publishes events, ranges, interrupt activity, and CPU-state plots to Tracy using the guest's virtual clock.

The project was built to inspect the VIMIX hobby OS, but the transport is not tied to its kernel architecture. Another RISC-V firmware, kernel, or bare-metal program can use it by providing the shared protocol definitions and emitting the same HINT encodings.

Note: This tools was AI coded, use at your own risk.

Qtracy screenshot

Repository layout

  • qemu/ is the modified QEMU submodule. Its featqtracy branch contains the RISC-V decoder hooks and Tracy client integration.
  • tracy/ is the modified Tracy submodule. Its featqtracy branch adds APIs for events with caller-supplied timestamps.
  • build.sh configures and builds QEMU plus Tracy's profiler, capture tool, and CSV exporter.
  • docs/technical-details.md describes the instruction protocol, time model, QEMU and Tracy changes, range handling, and current limitations.

This is a local experiment build by AI and is not intended as an upstream QEMU or Tracy change.

Prerequisites

Use a Linux development environment capable of building QEMU and Tracy. At a minimum, the build expects:

  • a C and C++ toolchain, make, and pkg-config;
  • Python and QEMU's normal Meson/Ninja build dependencies;
  • CMake 3.25 or newer;
  • the development libraries required by the Tracy GUI on the host; and
  • Git with submodule support.

The configured QEMU target is riscv64-softmmu. QEMU's virt machine, TCG, virtio block support, and the bundled generic RISC-V OpenSBI firmware are part of that build, so this repository does not build OpenSBI separately.

Checkout and build

Initialize both modified upstream projects after cloning the superproject:

git submodule update --init --recursive

The build needs a guest/QEMU protocol header named hint_defs.h. Supply its absolute path as the first argument:

./build.sh "$(pwd)/path/to/hint_defs.h"

For the original VIMIX layout, invoking ./build.sh without an argument uses:

../vimixos/kernel/include/kernel/hint_defs.h

Set JOBS to override the detected parallelism:

JOBS=8 ./build.sh "$(pwd)/path/to/hint_defs.h"

The script configures missing build directories and then rebuilds all four targets. It does not build the instrumented guest. Outputs are kept outside the submodules:

build/qtracy/qemu-system-riscv64
build/qtracy-profiler/tracy-profiler
build/qtracy-capture/tracy-capture
build/qtracy-csvexport/tracy-csvexport

The selected header path is stored in build/qtracy/qtracy-hint-defs-path. Changing the path reconfigures QEMU; changing the header contents causes system/qtracy.c to be recompiled. Use an absolute path because the value is passed to the compiler as QTRACY_HINT_DEFS_HEADER.

Supplying a custom hint_defs.h

The header is the protocol definition shared by the guest and QEMU. It defines the 17-bit packet layout, packet and control enums, the bounded data payload, and X-macro tables for named events and range classes. It must also define the three range symbols that currently receive special hart-local treatment: QTRACY_RANGE_PROCESS, QTRACY_RANGE_SCHEDULER, and QTRACY_RANGE_WFI.

Keep the header usable by both environments: avoid guest-only includes and types unless they are conditional. Numeric IDs must be nonzero, no greater than QTRACY_PACKET_ID_MAX (currently 16383), and unique within the relevant event or range namespace. QEMU consumes these definition tables at compile time, so rebuild it after every change.

The complete required interface and a description of each definition table are in Custom hint definitions.

Capture a guest run

Start the Tracy GUI, then launch the guest with the modified QEMU using the usual arguments for that guest image:

build/qtracy-profiler/tracy-profiler
build/qtracy/qemu-system-riscv64 -machine virt [guest options]

The QEMU client is built in Tracy's on-demand mode and appears as a profiling target while it runs. Automatic host sampling, context-switch tracing, callstacks, crash handling, frame images, system tracing, and vsync capture are disabled so the capture primarily contains guest-originated data.

Short-lived guests can finish before Tracy completes its connection handshake. Start QEMU with -S, connect the profiler, and resume the virtual CPUs from the QEMU monitor in that case (or from an attached gdb).

A headless capture can be recorded and exported with:

build/qtracy-capture/tracy-capture -o guest.tracy -s 10
build/qtracy-csvexport/tracy-csvexport --messages guest.tracy

Use --unwrap for individual zones and combine it with --plot to export plot data. Run either tool with --help for all options.

Instrumenting another guest

Guest instrumentation has two pieces:

  1. Share a compatible hint_defs.h with this build.
  2. Emit SLTI x0, rs1, imm12 HINT words with the packet split across the instruction's 12-bit immediate and five-bit rs1 field. Data-bearing packets place their XLEN-sized value or guest physical address in a0.

These instructions behave as no-ops on an implementation that does not recognize this private protocol because their destination is x0. The guest can therefore compile instrumentation into an image without requiring every RISC-V implementation to support qtracy. The current QEMU integration is in the TCG decoder; it does not add KVM support.

See Guest packet transport before implementing the guest-side macros, especially the physical-address, range-nesting, and execution-context rules.

About

Integrating Tracy into qemu.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages