如何使用 criterion 检测回归?

解读

在国内 Rust 岗位面试中,性能回归检测是高频考点。面试官不仅想知道“会不会用”,更关注“如何落地到 CI”“如何设定阈值”“如何与 baseline 比对”。回答时要体现工程闭环:基准代码 → 持续采集 → 自动告警 → 根因定位,避免只讲 API 调用。

知识点

  1. criterion 设计哲学:采样统计(bootstrap 置信区间)、历史持久化(target/criterion 目录)、自动回归判定(±临界值)。
  2. 回归判定规则:默认 99.9% 置信区间重叠即“无回归”;若新区间整体偏移超过 ±3% 即判回归(可自定义 change 阈值)。
  3. baseline 管理cargo bench --save-baseline master 把主分支结果存为“真值”;PR 阶段 cargo bench --baseline master 自动比较。
  4. CI 集成要点
    • 自托管 runner 保证硬件一致;
    • 关闭 CPU 变频与超线程,绑定核隔离干扰;
    • 缓存 target/criterion 与 baseline,避免冷编译噪声。
  5. 统计显著性:criterion 输出 p-valueeffect size,若 p < 0.05effect size > 0.02高置信回归,需人工复核。
  6. 常见误用
    • 只跑单次测量,忽略采样误差;
    • black_box 放错位置,导致编译器优化掉核心路径;
    • 在虚拟机或容器里跑,未锁定 cpu-manager-policy=static,结果漂移。

答案

  1. benches/ 下编写基准:
use criterion::{criterion_group, criterion_main, Criterion, black_box};

fn fib(n: u64) -> u64 { if n < 2 { 1 } else { fib(n - 1) + fib(n - 2) } }

fn bench_fib(c: &mut Criterion) {
    c.bench_function("fib 20", |b| b.iter(|| fib(black_box(20))));
}

criterion_group!(benches, bench_fib);
criterion_main!(benches);
  1. 保存主分支 baseline:
cargo bench --bench fib --save-baseline master

结果持久化到 target/criterion/master

  1. 在功能分支检测回归:
cargo bench --bench fib --baseline master

若控制台出现 Performance has regressed. 且 HTML 报告 change 列红色箭头,即判定回归。

  1. 自定义阈值(例如 ±1%):
let mut c = Criterion::default()
    .measurement_time(Duration::from_secs(10))
    .confidence_level(0.99)
    .noise_threshold(0.01);
  1. CI 集成脚本(GitHub Actions 示例):
- name: Restore baseline
  uses: actions/cache@v3
  with:
    path: target/criterion
    key: criterion-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}

- name: Run benchmark
  run: |
    sudo cpupower frequency-set -g performance
    cargo bench --bench fib --baseline master --output-format bencher | tee result.txt
    if grep -q "Performance has regressed" result.txt; then
      echo "::error::检测到性能回归,请查看报告"
      exit 1
    fi
  1. 根因定位:
    • 打开 target/criterion/report/index.html,查看 ChangeDistribution 图;
    • 若新增分支引入额外 clone,火焰图会显示热点;
    • 使用 perf dso 对比汇编,确认是否生成多余内存屏障。

拓展思考

  1. 微基准 vs 端到端:criterion 适合微基准,对 IO 密集场景需配合 hyperfinelocust
  2. 跨平台一致性:ARM 与 x86 指令集差异大,建议分架构保存 baseline,避免误判。
  3. 二进制大小回归:结合 cargo-bloatcargo-audit,在 CI 中并行检查“性能+体积+安全”三维回归。
  4. 生产流量回放:把真实请求录制为 *.proto,用 criterionthroughput 模式重放,实现“真数据”防回归。
  5. Rust 1.83 起 cargo bench 原生支持 #[bench],但 criterion 仍是事实标准,因其统计模型更严谨;面试时可主动对比两者差异,体现社区演进敏感度。