输入未实现 Copy 特征的基准函数
Benchmark function with input that doesn't implement the Copy trait
我是运行 Criterion 的基准测试,但我面临着输入未实现 Copy 特征的函数的问题。
例如,我为签名为 pub fn hash(vector: Vec<&str>) -> u64
.
的函数设置了以下基准
pub fn criterion_benchmark(c: &mut Criterion) {
let s: String = String::from("Hello World!");
let tokens: Vec<&str> = hashing::tokenize(&s);
c.bench_function(
"hash",
|b| b.iter(|| {
hashing::hash(tokens)
}),
);
}
但是,与具有 Copy 特征的类型不同,编译器抛出以下所有权错误。
error[E0507]: cannot move out of `tokens`, a captured variable in an `FnMut` closure
--> benches/benchmark.rs:17:34
|
13 | let tokens: Vec<&str> = hashing::tokenize(&s);
| ------ captured outer variable
...
17 | hashing::hash(tokens)
| ^^^^^^ move occurs because `tokens` has type `Vec<&str>`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `tokens`, a captured variable in an `FnMut` closure
--> benches/benchmark.rs:16:20
|
13 | let tokens: Vec<&str> = hashing::tokenize(&s);
| ------ captured outer variable
...
16 | |b| b.iter(|| {
| ^^ move out of `tokens` occurs here
17 | hashing::hash(tokens)
| ------
| |
| move occurs because `tokens` has type `Vec<&str>`, which does not implement the `Copy` trait
| move occurs due to use in closure
如何将不可复制的输入传递给基准函数而不 运行 出现所有权问题?
按照@Stargateur 的建议,克隆参数解决了所有权问题。
pub fn criterion_benchmark(c: &mut Criterion) {
let s: String = String::from("Hello World!");
let tokens: Vec<&str> = hashing::tokenize(&s);
c.bench_function(
"hash",
|b| b.iter(|| {
hashing::hash(tokens.clone())
}),
);
}
但是,正如@DenysSéguret 和@Masklinn 所提议的那样,将 hash
函数更改为接受 &[&str]
可避免克隆向量的 ~50% 开销。
克隆输入可能会导致基准测试结果出现严重错误。
因此你应该使用iter_batched()
instead of iter()
use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
criterion_main!(benches);
criterion_group!(benches, criterion_benchmark);
fn criterion_benchmark(c: &mut Criterion) {
let input_data: String = String::from("Hello World!");
c.bench_function("bench_function", |bencher| {
bencher.iter_batched(
|| init_data(&input_data),
|input| {
let x = benchmark_me(input);
black_box(x);
},
BatchSize::SmallInput,
);
});
c.bench_function("bench_function+clone", |bencher| {
bencher.iter(|| {
let x = benchmark_me(init_data(&input_data));
black_box(x);
});
});
}
fn init_data(s: &str) -> Vec<&str> {
// it's intentionally slower than a plain copy, to make the difference more visible!
s.split_ascii_whitespace().collect()
}
fn benchmark_me(s: Vec<&str>) -> u64 {
let mut hasher = DefaultHasher::new();
s.hash(&mut hasher);
hasher.finish()
}
结果:
bench_function time: [99.520 ns 100.90 ns 102.23 ns]
bench_function+clone time: [210.41 ns 212.08 ns 213.77 ns] ```
我是运行 Criterion 的基准测试,但我面临着输入未实现 Copy 特征的函数的问题。
例如,我为签名为 pub fn hash(vector: Vec<&str>) -> u64
.
pub fn criterion_benchmark(c: &mut Criterion) {
let s: String = String::from("Hello World!");
let tokens: Vec<&str> = hashing::tokenize(&s);
c.bench_function(
"hash",
|b| b.iter(|| {
hashing::hash(tokens)
}),
);
}
但是,与具有 Copy 特征的类型不同,编译器抛出以下所有权错误。
error[E0507]: cannot move out of `tokens`, a captured variable in an `FnMut` closure
--> benches/benchmark.rs:17:34
|
13 | let tokens: Vec<&str> = hashing::tokenize(&s);
| ------ captured outer variable
...
17 | hashing::hash(tokens)
| ^^^^^^ move occurs because `tokens` has type `Vec<&str>`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `tokens`, a captured variable in an `FnMut` closure
--> benches/benchmark.rs:16:20
|
13 | let tokens: Vec<&str> = hashing::tokenize(&s);
| ------ captured outer variable
...
16 | |b| b.iter(|| {
| ^^ move out of `tokens` occurs here
17 | hashing::hash(tokens)
| ------
| |
| move occurs because `tokens` has type `Vec<&str>`, which does not implement the `Copy` trait
| move occurs due to use in closure
如何将不可复制的输入传递给基准函数而不 运行 出现所有权问题?
按照@Stargateur 的建议,克隆参数解决了所有权问题。
pub fn criterion_benchmark(c: &mut Criterion) {
let s: String = String::from("Hello World!");
let tokens: Vec<&str> = hashing::tokenize(&s);
c.bench_function(
"hash",
|b| b.iter(|| {
hashing::hash(tokens.clone())
}),
);
}
但是,正如@DenysSéguret 和@Masklinn 所提议的那样,将 hash
函数更改为接受 &[&str]
可避免克隆向量的 ~50% 开销。
克隆输入可能会导致基准测试结果出现严重错误。
因此你应该使用iter_batched()
instead of iter()
use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
criterion_main!(benches);
criterion_group!(benches, criterion_benchmark);
fn criterion_benchmark(c: &mut Criterion) {
let input_data: String = String::from("Hello World!");
c.bench_function("bench_function", |bencher| {
bencher.iter_batched(
|| init_data(&input_data),
|input| {
let x = benchmark_me(input);
black_box(x);
},
BatchSize::SmallInput,
);
});
c.bench_function("bench_function+clone", |bencher| {
bencher.iter(|| {
let x = benchmark_me(init_data(&input_data));
black_box(x);
});
});
}
fn init_data(s: &str) -> Vec<&str> {
// it's intentionally slower than a plain copy, to make the difference more visible!
s.split_ascii_whitespace().collect()
}
fn benchmark_me(s: Vec<&str>) -> u64 {
let mut hasher = DefaultHasher::new();
s.hash(&mut hasher);
hasher.finish()
}
结果:
bench_function time: [99.520 ns 100.90 ns 102.23 ns]
bench_function+clone time: [210.41 ns 212.08 ns 213.77 ns] ```