基准测试
问题
如何对 Rust 代码进行可靠的基准测试?
答案
criterion(推荐)
benches/my_bench.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
fn fibonacci(n: u64) -> u64 {
match n {
0 | 1 => n,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn fibonacci_iter(n: u64) -> u64 {
let (mut a, mut b) = (0u64, 1u64);
for _ in 0..n {
let t = a + b;
a = b;
b = t;
}
a
}
fn bench_fibonacci(c: &mut Criterion) {
let mut group = c.benchmark_group("fibonacci");
for n in [10, 20, 30] {
group.bench_with_input(BenchmarkId::new("recursive", n), &n, |b, &n| {
b.iter(|| fibonacci(black_box(n)))
});
group.bench_with_input(BenchmarkId::new("iterative", n), &n, |b, &n| {
b.iter(|| fibonacci_iter(black_box(n)))
});
}
group.finish();
}
criterion_group!(benches, bench_fibonacci);
criterion_main!(benches);
cargo bench # 运行基准测试
cargo bench -- fibonacci/20 # 只运行特定测试
关键注意事项
| 陷阱 | 解决方案 |
|---|---|
| 编译器优化掉代码 | 使用 black_box() |
| 不稳定的结果 | criterion 自动统计(置信区间) |
| profile 不同 | bench 自动用 release |
| 系统噪声 | 多次运行取平均 |
black_box 的作用black_box 告诉编译器"这个值可能被外部使用",防止编译器优化掉整个计算。没有 black_box 的基准测试结果可能是 0ns(被优化掉了)。
常见面试问题
Q1: criterion 比标准库的 bench 好在哪?
答案:
| 特性 | criterion | #[bench](nightly) |
|---|---|---|
| Stable Rust | ✅ | ❌ 需要 nightly |
| 统计分析 | 置信区间、回归检测 | 仅平均值 |
| HTML 报告 | ✅ | ❌ |
| 对比基线 | ✅ 自动对比上次 | ❌ |