How Magic-Trace Integrates with Perf for Intel PT Decoding
Magic-Trace leverages Linux perf to record Intel Processor Trace (PT) streams and decodes the raw hardware data through a custom C decoder that translates machine-level instructions into structured function call events.
Magic-Trace is an open-source execution tracing tool developed by Jane Street that captures nanosecond-precision application behavior using Intel PT technology. The integration between magic-trace and the Linux perf subsystem follows a multi-stage pipeline: detecting hardware capabilities, constructing precise event configurations, recording binary trace data, and decoding the stream into symbolic execution events.
Detecting Intel PT Capabilities
Before recording, magic-trace verifies kernel support for Intel PT features by probing system files and querying the perf binary version. In src/perf_capabilities.ml, the detect_exn function orchestrates this discovery process.
The implementation reads capability flags from sysfs paths such as /sys/bus/event_source/devices/intel_pt/caps/psb_cyc through helper functions like supports_configurable_psb_period. This determines whether the kernel supports configurable PSB (Packet Stream Boundary) periods, kernel-level tracing, snapshot-on-exit, and other advanced features.
let detect_exn () =
let%bind perf_version_proc = Process.create_exn … in
…
empty
|> set_if (supports_configurable_psb_period ()) configurable_psb_period
|> set_if (supports_tracing_kernel ()) kernel_tracing
|> set_if (supports_kcore version) kcore
|> set_if (supports_snapshot_on_exit version) snapshot_on_exit
|> set_if (supports_last_branch_record ()) last_branch_record
|> set_if (supports_dlfilter version) dlfilter
|> set_if (supports_ctlfd version) ctlfd
;;
Constructing the Perf Command Line
Using the detected capabilities, magic-trace builds the specific intel_pt event specification in src/perf_tool_backend.ml. The perf_intel_pt_config_of_timer_resolution function translates user-selected timer resolutions (Low, Normal, High, or Custom) into kernel configuration strings.
let perf_intel_pt_config_of_timer_resolution ~capabilities timer_resolution =
match timer_resolution with
| Low -> Or_error.return ""
| Normal -> Or_error.return "cyc=1,cyc_thresh=1,mtc_period=0"
| High -> Or_error.return "cyc=1,cyc_thresh=1,mtc_period=0,noretcomp=1"
| Custom { … } -> … (* builds “cyc=…,mtc=…,psb_period=…” list *)
;;
The perf_args_of_collection_mode function assembles the final --event argument, combining the Intel PT configuration with a scope selector (u for userspace, k for kernel, or uk for both).
let%map.Or_error primary_event =
match collection_mode with
| Intel_processor_trace _ ->
let%map.Or_error intel_pt_config =
perf_intel_pt_config_of_timer_resolution ~capabilities timer_resolution
in
[%string "intel_pt/%{intel_pt_config}/%{selector}"]
…
let arg_string = String.concat ~sep:"," (primary_event :: extra_events) in
[ [%string "--event=%{arg_string}"] ]
This generates commands resembling:
perf record --event=intel_pt/cyc=1,cyc_thresh=1,mtc_period=0/uk …
Recording Raw Processor Trace Data
Magic-Trace invokes the perf binary through the attach_and_record function in src/perf_tool_backend.ml. This spawns a child process that executes perf record with the constructed arguments, writing the raw PT data to perf.data and auxiliary buffer files containing the actual hardware trace packets.
When the recording triggers (either by snapshot or continuous mode), the Intel PT hardware writes compressed branch trace packets to physical memory, which perf captures in the AUX buffer region alongside metadata about the traced process.
Decoding the PT Stream with the Direct Backend
After recording completes, magic-trace decodes the raw binary stream using the direct backend located in direct_backend/manual_perf.ml and direct_backend/decoding.ml. The process involves three distinct phases:
Setup Phase: The Tracing_state.attach function reads the current memory maps of the traced process via read_current_maps, then constructs a Setup_info.t record describing the process layout. This data serializes to a side-band file that the C decoder consumes.
let%map.Result () = Stub.attach state config trace_meta |> Errno.to_result in
Out_channel.write_all setup_file
~data:([%sexp ({ initial_maps = read_current_maps pid; … } : Setup_info.t)]
|> Sexp.to_string);
C Decoder Initialization: The OCaml code calls into native stubs such as magic_pt_init_decoder_stub and magic_pt_run_decoder_stub defined in decoding.ml. These functions interface with the Intel PT decoding library to parse the raw AUX buffer into discrete trace events (Call, Ret, Jump, Start_trace).
Event Conversion: The convert_trace_event function maps raw PT events to the Backend_intf.Event.t type, constructing high-level execution events suitable for the magic-trace viewer.
Resolving Symbols from Trace Data
Raw instruction pointers from the PT stream require translation to human-readable function names. In src/perf_decode.ml, functions like parse_symbol_and_offset and parse_location extract address information from perf's output.
Magic-Trace attempts symbol resolution through multiple sources:
- Perf-map files: For JIT-compiled code or dynamically generated symbols, the decoder checks
Perf_map.Table.symbolinsrc/perf_map.mlfor per-process symbol tables. - ELF side-band maps: When perf-map files are unavailable, the system falls back to the memory maps captured during the setup phase to resolve addresses against the binary's symbol tables.
Summary
-
Capability Detection: Magic-Trace probes
/sys/bus/event_source/devices/intel_pt/caps/psb_cycand other sysfs files viasrc/perf_capabilities.mlto determine available Intel PT features before recording. -
Command Construction: The
perf_intel_pt_config_of_timer_resolutionfunction insrc/perf_tool_backend.mltranslates timer settings into kernel event specifications likeintel_pt/cyc=1,cyc_thresh=1,mtc_period=0,noretcomp=1/uk. -
Hardware Recording: Magic-Trace forks the
perfbinary with constructed arguments, capturing raw PT packets toperf.dataand auxiliary buffer files. -
Binary Decoding: The direct backend in
direct_backend/manual_perf.mlinitializes a C decoder viamagic_pt_init_decoder_stub, converting raw packets to structured events throughconvert_trace_event. -
Symbol Resolution: Address-to-symbol translation occurs in
src/perf_decode.ml, utilizing perf-map files and side-band ELF data to attribute instructions to source functions.
Frequently Asked Questions
How does magic-trace detect if Intel PT is available on the system?
Magic-Trace checks for Intel PT support by reading kernel capability files in /sys/bus/event_source/devices/intel_pt/caps/, specifically probing psb_cyc for configurable PSB periods. The detect_exn function in src/perf_capabilities.ml aggregates these checks alongside version parsing of the perf binary to build a comprehensive capability profile before attempting recording.
What perf event configuration does magic-trace use for high-resolution tracing?
For high-resolution traces, magic-trace configures the event string as intel_pt/cyc=1,cyc_thresh=1,mtc_period=0,noretcomp=1/uk through the perf_intel_pt_config_of_timer_resolution function. This enables cycle-accurate timestamps with micro-time counter (MTC) packets while disabling return compression to ensure complete call stack reconstruction.
How does magic-trace convert raw Intel PT packets into function call events?
After perf records the raw data, magic-trace uses the direct backend to initialize a C decoder via magic_pt_init_decoder_stub in direct_backend/decoding.ml. The decoder processes the PT AUX buffer and emits low-level events that convert_trace_event translates into the Backend_intf.Event.t type, distinguishing between Call, Ret, and Jump operations with symbolic resolution.
Where does magic-trace store the recorded Intel PT trace data?
Magic-Trace writes the raw trace data to standard perf output files (perf.data) alongside auxiliary buffer files containing the compressed PT packets. During decoding, it generates side-band files (such as setup.sexp) in direct_backend/manual_perf.ml that describe the process memory maps, enabling accurate instruction pointer resolution during analysis.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →