用途
Rust Profiling 是一个面向 Rust 性能剖析的技能,用于引导代理完成 Rust 程序的性能分析工作,涵盖火焰图生成、二进制体积分析、单态化膨胀测量、Criterion 微基准测试,以及解读包含内联 Rust 帧的剖析结果。
触发场景
该技能在以下问题出现时被触发:
- 如何为 Rust 程序生成火焰图
- Rust 二进制体积过大,如何定位原因
- 如何编写 Criterion 基准测试
- 如何测量单态化膨胀
- Rust 性能低于预期时如何剖析
- 如何在 Rust 中使用 perf
主要能力与工作流
1. 为剖析构建
使用带有调试符号的 release 配置,配置示例:
[profile.release-with-debug]
inherits = "release"
debug = true
cargo build --profile release-with-debug
或快速方式:
CARGO_PROFILE_RELEASE_DEBUG=true cargo build --release
2. 使用 cargo-flamegraph 生成火焰图
cargo install flamegraph
Linux 下使用 perf(要求 perf_event_paranoid ≤ 1):
sudo sh -c 'echo 1 > /proc/sys/kernel/perf_event_paranoid'
cargo flamegraph --bin myapp -- arg1 arg2
macOS 下使用 DTrace(需要 sudo):
sudo cargo flamegraph --bin myapp -- arg1 arg2
剖析测试与基准:
cargo flamegraph --test mytest -- test_filter
cargo flamegraph --bench mybench -- --bench
输出会在当前目录生成 flamegraph.svg,可在浏览器中打开。
自定义选项:
cargo flamegraph --freq 1000 --bin myapp
直接使用 perf 获得更多控制:
perf record -g -F 999 ./target/release-with-debug/myapp args
perf script | stackcollapse-perf.pl | flamegraph.pl > out.svg
3. 使用 cargo-bloat 进行二进制体积分析
cargo install cargo-bloat
cargo bloat --release -n 20
cargo bloat --release --crates
cargo bloat --release --filter myapp
可用于对比改动前后:
cargo bloat --release --crates > before.txt
# 进行修改
cargo bloat --release --crates > after.txt
diff before.txt after.txt
典型输出会列出文件占比、.text 占比、大小、crate 名称等。
4. 使用 cargo-llvm-lines 测量单态化膨胀
cargo install cargo-llvm-lines
cargo llvm-lines --release | head -40
cargo llvm-lines --release | grep '^myapp'
典型输出包含 Lines、Copies、Function name 三列。Copies 数量高代表单态化展开。可通过“薄泛型包装 + 具体内部函数”的方式优化:
fn process<T: AsRef<[u8]>>(data: T) -> usize {
fn inner(data: &[u8]) -> usize { do_work(data) }
inner(data.as_ref())
}
5. Criterion 微基准测试
依赖配置:
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
[[bench]]
name = "my_bench"
harness = false
基准代码示例:
use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
fn bench_process(c: &mut Criterion) {
c.bench_function("process 1000 items", |b| {
let data: Vec<i32> = (0..1000).collect();
b.iter(|| process(black_box(&data)))
});
}
fn bench_sizes(c: &mut Criterion) {
let mut group = c.benchmark_group("process_sizes");
for size in [100, 1000, 10000].iter() {
let data: Vec<i32> = (0..*size).collect();
group.bench_with_input(
BenchmarkId::from_parameter(size),
&data,
|b, data| b.iter(|| process(black_box(data))),
);
}
group.finish();
}
criterion_group!(benches, bench_process, bench_sizes);
criterion_main!(benches);
运行方式:
cargo bench
cargo bench --bench my_bench
cargo bench -- process_sizes
cargo bench -- --save-baseline before
cargo bench -- --baseline before
open target/criterion/report/index.html
6. 在 Linux 上使用 perf 配合 Rust
perf record -g ./target/release-with-debug/myapp args
perf record -g -F 999 ./target/release-with-debug/myapp args
perf report
perf report --stdio --no-call-graph | head -40
perf annotate myapp::hot_function
perf stat ./target/release/myapp args
Rust 相关建议:
- 使用 debug = 1(仅行表)加快构建并保留行级归属
- 使用 RUSTFLAGS="-C force-frame-pointers=yes" 改善调用图
- 关闭 ASLR 以获得可复现地址:setarch $(uname -m) -R ./myapp
7. 使用 heaptrack / DHAT 分析内存分配
heaptrack(Linux):
heaptrack ./target/release/myapp args
heaptrack_print heaptrack.myapp.*.zst | head -50
DHAT(通过 Valgrind):
valgrind --tool=dhat ./target/debug/myapp args
使用 dh_view.html 打开 dhat-out.* 文件查看结果。
相关技能
- skills/rust/rustc-basics:构建配置(调试符号、profile)
- skills/profilers/linux-perf:perf 基础知识
- skills/profilers/flamegraphs:读取与解读火焰图 SVG
- skills/profilers/valgrind:使用 massif/DHAT 进行分配剖析
限制
部分操作依赖系统权限与平台工具:Linux 下 perf 需要 perf_event_paranoid ≤ 1,macOS 下 DTrace 需要 sudo。其他限制信息暂未提供。