如何用Criterion基准测试Rust随机局部搜索算法的分数?
用Criterion评估随机局部搜索算法的分数函数方案
核心思路
Criterion默认侧重时间测量,但你可以通过自定义Measurement适配分数评估需求——关键是忽略start/end的时间逻辑,转而在基准测试流程中主动捕获算法输出并计算分数。
实现步骤
- 定义自定义Measurement类型
创建空结构体实现Measurementtrait,其中start/end仅做占位实现:
use criterion::{Measurement, Throughput}; use std::time::Instant; #[derive(Clone, Default)] struct ScoreMeasurement; impl Measurement for ScoreMeasurement { type Intermediate = Instant; type Value = f64; // 可根据你的分数类型调整 fn start(&self) -> Self::Intermediate { Instant::now() // 按Trait要求实现,后续不使用该值 } fn end(&self, _start: Self::Intermediate) -> Self::Value { 0.0 // 占位返回值,实际分数会在后续替换 } fn add(&self, _v1: &Self::Value, _v2: &Self::Value) -> Self::Value { unimplemented!("无需累加分数,将手动计算统计值") } fn zero(&self) -> Self::Value { 0.0 } fn to_f64(&self, value: &Self::Value) -> f64 { *value } fn formatter(&self) -> &dyn criterion::measurement::ValueFormatter { &criterion::measurement::ValueFormatter::default() } fn throughput(&self, _throughput: &Throughput) -> Option<Self::Value> { None } }
- 手动控制迭代流程计算分数
使用iter_custom替代默认的iter,直接在闭包中运行算法、计算分数,绕开start/end的限制:
use criterion::{Criterion, BenchmarkId}; // 示例:你的随机局部搜索算法,输入种子返回分数 fn random_local_search(seed: u64) -> f64 { (seed as f64).sin().abs() * 100.0 } fn bench_rls(c: &mut Criterion<ScoreMeasurement>) { let test_seeds = vec![42, 123, 456, 789]; // 测试不同随机种子 for seed in test_seeds { c.bench_with_input(BenchmarkId::new("random_local_search", seed), &seed, |b, &s| { b.iter_custom(|iters| { let mut total_score = 0.0; // 运行指定次数,收集分数 for _ in 0..iters { total_score += random_local_search(s); } // 返回平均分数(或你需要的统计指标) total_score / iters as f64 }); }); } } criterion_group!(benches, bench_rls); criterion_main!(benches);
- 适配固定时长的Anytime算法
如果算法运行时长固定,可在iter_custom中确保每次调用严格遵循时长要求,或直接按固定次数执行——Criterion会自动处理多轮运行的统计分析,生成分数分布、均值等可视化结果。
关键说明
start和end仅为满足Trait约束的占位实现,实际测量逻辑完全由iter_custom控制,无需依赖这两个方法的返回值。- Criterion的统计分析和图表生成功能可直接用于评估随机种子带来的分数波动,适配随机算法的评估需求。
内容的提问来源于stack exchange,提问作者MarcoXerox
相关产品推荐
相关产品推荐

