我有一个评分函数来评估本地搜索算法,其结果因种子而异。该算法是任意的,其运行时间是固定的。尽管 Criterion 框架概括了
impl Measurement
,但我找不到一种方法让它使用分数函数来衡量。我想知道是否可以用 Criterion 来实现这个?
我无法实现
Measurement
的 API,来自 https://docs.rs/criterion/latest/criterion/measurement/trait.Measurement.html。准确地说,start(&self)
和end(&self, i)
不依赖于算法的输出。
MarcoXerox,这是正确的。标准并不是真正为您尝试做的事情而设计的。但是,我认为使用
iter_custom
应该相当容易实现,因为它可以让您提供测量结果,而不是调用 start
和 end
。首先为您的分数类型定义占位符测量值。
pub struct Points;
impl Measurement for Points {
type Intermediate = ();
type Value = f64;
fn start(&self) -> Self::Intermediate {
panic!("value should be manually created")
}
fn end(&self, i: Self::Intermediate) -> Self::Value {
panic!("value should be manually created")
}
fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value {
v1 + v2
}
fn zero(&self) -> Self::Value {
0.0
}
fn to_f64(&self, value: &Self::Value) -> f64 {
*value
}
fn formatter(&self) -> &dyn ValueFormatter {
&PointsFormatter
}
}
pub struct PointsFormatter;
impl ValueFormatter for PointsFormatter {
fn scale_values(&self, _typical_value: f64, _values: &mut [f64]) -> &'static str {
"points"
}
fn scale_throughputs(&self, _typical_value: f64, throughput: &Throughput, values: &mut [f64]) -> &'static str {
let (n, units) = match throughput {
Throughput::Bytes(x) => (*x as f64, "points/byte"),
Throughput::BytesDecimal(x) => (*x as f64, "points/byte"),
Throughput::Elements(x) => (*x as f64, "points/element"),
};
for value in values {
*value /= n;
}
units
}
fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str {
"points"
}
}
然后只需手动返回值作为
iter_custom
的一部分,而不是让标准执行测量。只需确保您正确考虑了所请求的迭代次数。
fn bench(c: &mut Criterion<Points>) {
c.bench_function("foo", move |b| {
b.iter_custom(|iters| {
let total_score: f64 = 0.0;
for _ in 0..iters {
let score = black_box(foo());
total_score += score;
}
total_score
})
});
}
我相信这应该可以解决您的问题。