Miri

repository·master·Indexed 27 days ago

https://github.com/rust-lang/miri

An experimental interpreter for Rust MIR. It includes cargo-miri for orchestrating the interpreter across build phases (setup, compilation, and running/testing) and Priroda, a step-through debugger providing source-level stepping, breakpoints, and local state inspection for programs running under Miri.

Tokens
14.6K
Snippets
41
Records
103
Agent score
88%

What's inside miri

  1. Generate a flamegraph using `perf`

    master

    If you want to identify functions that consume significant time but lack tracing coverage, you can generate a flamegraph using Linux's perf tool after compiling Miri.

    perf record  --call-graph dwarf -F 999 ./miri/target/debug/miri --edition 2021 --sysroot ~/.cache/miri ./tests/pass/hashmap.rs && perf script | inferno-collapse-perf | inferno-flamegraph > flamegraph.svg
  2. Analyze Miri trace files with Perfetto UI

    master

    To analyze Miri traces, use the Perfetto UI. Drag and drop your .json trace file into the browser to view the timeline.

    Timeline Structure

    • Process 1: Contains tracing spans for Miri components (e.g., borrow tracker, data race checker).
    • Global Legacy Events: Contains auxiliary spans to track execution context:
      • frame: The current stack frame in the interpreted program.
      • step: The current MIR statement/terminator being executed.

    Spans are colored boxes, while instantaneous events (like debug logs) are represented by tiny arrows.

  3. Obtain a Miri trace file from the Miri codebase

    master

    To generate a trace file for performance analysis, you must compile Miri with the tracing feature enabled and set the MIRI_TRACING environment variable to 1. The resulting .json trace file can be analyzed using Perfetto.

    WARNING

    Tracing in Miri is currently known to be broken due to bugs in external tracing libraries. See issue #4752 for details.

    MIRI_TRACING=1 ./miri run --features=tracing ./tests/pass/hello.rs
  4. Compute aggregate statistics for spans

    master

    To get a high-level overview of time distribution, select a time range by dragging along a trace line and check the "Current Selection" tab at the bottom. Use the "Slices", "Pivot Table", or "Slice Flamegraph" views.

    Note: These views include nested spans. To avoid double-counting durations when calculating percentages, use the enhanced SQL query method.

  5. Setup Priroda

    master

    To use Priroda, you must first install the pinned toolchain and the local cargo-miri command from the miri/ directory. You then need to build the Miri sysroot and export the MIRI_SYSROOT environment variable so Priroda can locate it.

    # From the miri/ directory
    ./miri toolchain
    ./miri install
    
    # Build sysroot and export for Priroda
    cargo +miri miri setup
    export MIRI_SYSROOT="$(cargo +miri miri setup --print-sysroot)"
  6. Visualize 'frame' or 'step' execution via SQL workaround

    master

    The standard "Visualize argument values" method may not work for frame or step spans under "Global Legacy Events". Use this SQL workaround to create a debug track:

    1. Enter SQL mode by typing : in the search bar.
    2. Run the following query, replacing SPAN_NAME with either frame or step:
    select slices.id, ts, dur, track_id, category, args.string_value as name, depth, stack_id, parent_stack_id, parent_id, slices.arg_set_id, thread_ts, thread_instruction_count, thread_instruction_delta, cat, slice_id
    from slices inner join args using (arg_set_id)
    where args.key = "args." || name and name = "SPAN_NAME"
    1. Click "Show debug track" at the top-right of the results box.
    2. Click "Show" in the popup.

    This creates a new track displaying the actual names of the steps or frames.

  7. Enhance the timeline with span subnames

    master

    Some spans in "Process 1" share the same name but represent different functions. Miri stores the specific function name as a "subname" in an argument. To visualize these subnames as a dedicated timeline line:

    1. Select a span with the target name (e.g., data_race).
    2. Click the dropdown next to the argument named $NAME (or args.$NAME).
    3. Click "Visualize argument values".

    A new timeline line will appear showing the specific subnames instead of the generic span name.

  8. Obtain a Miri trace file from the rustc codebase

    master

    If you are building Miri as part of the rustc tree, you must first enable the tracing feature in your bootstrap.toml file. Once configured, you can run Miri through x.py with the MIRI_TRACING environment variable set to 1 to produce a trace file.

    # Add this to bootstrap.toml
    build.tool.miri.features = ["tracing"]
    MIRI_TRACING=1 ./x.py run miri --stage 1 --args ./src/tools/miri/tests/pass/hello.rs
  9. Test Priroda CLI

    master

    Priroda's CLI tests require MIRI_SYSROOT to be set. Run them from the miri/priroda/ directory. If tests fail due to mismatched output, you can update the expected output files using the --bless flag or by setting the RUSTC_BLESS=1 environment variable.

    # From the miri/priroda/ directory
    cargo test
    
    # To update expected output files if tests fail due to mismatch
    cargo test -- --bless
    # OR
    RUSTC_BLESS=1 cargo test
  10. Use `cargo miri setup` to prepare a sysroot

    master

    The cargo miri setup command performs the necessary steps to make Miri work, primarily by building a custom libstd compatible with Miri.

    Key behaviors:

    • It requires the rust-src component to be installed (it will attempt to run rustup component add rust-src if missing).
    • It builds a sysroot with specific flags: -Cdebug-assertions=off and -Coverflow-checks=on to optimize performance while maintaining safety.
    • It uses the MIRI_CALLED_FROM_SETUP environment variable internally to manage the build process.

    If you only need the path to the prepared sysroot without the full setup output, you can use the --print-sysroot flag.

  11. Use cargo-miri via cargo miri

    master

    The cargo-miri binary is designed to be invoked through cargo miri rather than as a standalone command. When invoked correctly, it orchestrates the Miri interpreter across different phases of the Rust build process (setup, compilation, and running/testing).

    To use Miri with your Cargo project, ensure you have the cargo-miri tool installed and run:

    cargo miri <command>

    Common commands include cargo miri run or cargo miri test.