Guide: profile a runtime benchmark
中文版:profiling_CN.md
Profile a runtime benchmark to find where time is spent. Two profilers are supported: Cachegrind (instruction-level, Valgrind-based) and perf-record (sampling-based, Linux perf). Cachegrind also supports diffing two rustc builds.
Prerequisites
- Everything in local-benchmarking prerequisites.
- For cachegrind:
valgrind,cg_annotate,cg_diffonPATH. Build a recent Valgrind; theprecise-cachegrindfeature additionally needsDEP_VALGRIND=<path-to-valgrind>/includeat build time. - For perf-record:
perfonPATH.
Verify:
valgrind --version && cg_annotate --version && perf --version
Step 1 — (optional) enable precise cachegrind
Precise cachegrind wraps the measured function with Valgrind client requests to start/stop instrumentation exactly around bench(env), removing the constructor/warm-up from the profile. Build the collector and benchmark crates with the feature:
DEP_VALGRIND=/usr/include cargo build --release --features precise-cachegrind
Step 2 — profile a single rustc
# Cachegrind (instruction-level)
./target/release/collector profile_runtime <RUSTC> cachegrind --group std
# perf-record (sampling)
./target/release/collector profile_runtime <RUSTC> perf-record --group std
# Profile more iterations so the profiler gathers more data
./target/release/collector profile_runtime <RUSTC> cachegrind --group std --iterations 20
<RUSTC> is a path or +toolchain (same as bench_runtime_local). The --iterations value (default 5) controls how many times the profiled function runs so the profiler has enough samples.
Profiling always uses cached (in-place) compilation and forces debug info so filenames and line numbers are available in the generated profiles.
Step 3 — find the output
Profiles are written to results-runtime/:
- Cachegrind:
cgout-<rustc_id>-<group>-<bench>.<N>(raw) andcgann-<rustc_id>-<group>-<bench>.<N>(annotated). - perf-record:
perf-<rustc_id>-<group>-<bench>.<N>(raw) andperfreport-<rustc_id>-<group>-<bench>.<N>(annotated).
The collector prints the path at the end:
Profiling complete, result can be found in `results-runtime/...`
Step 4 — diff two rustc builds (cachegrind only)
Compare a modified rustc against a baseline to see exactly where instructions changed:
./target/release/collector profile_runtime <rustc-modified> cachegrind --rustc2 <rustc-baseline> --group std
The collector profiles both toolchains, then runs cg_diff on each benchmark's pair of cachegrind outputs and annotates the diff. The diff is stored alongside the per-toolchain profiles, and the collector prints:
Diff stored in `results-runtime/...`
--rustc2withperf-recordis unsupported. Use cachegrind for diffs.
Step 5 — profile a single benchmark within a group
profile_runtime profiles every benchmark in the group. To narrow down, use the same filter flags as bench_runtime_local:
./target/release/collector profile_runtime <RUSTC> cachegrind --group std \
--include std_bench::hash --iterations 10
(--include/--exclude/--exclude_suffix/--exact_match are accepted here too.)
Troubleshooting
valgrindis not installed — installvalgrind(andcg_annotate/cg_diff, usually in the same package).- Empty profile — the benchmark may be too fast; raise
--iterations. --rustc2 perf-recorderrors — perf-record has no diff support; switch to cachegrind.- No line numbers in the annotation — profiling forces debug info; if you built a custom benchmark crate without debuginfo, rebuild it.
Next steps
- Interpret results → comparison-analysis
- Run benchmarks → local-benchmarking