Search code examples
rustownershiprust-criterion

Benchmark function with input that doesn't implement the Copy trait


I am running benchmarks with Criterion but am facing issues with functions that have an input that does not implement the Copy trait.

For example, I have set up the following benchmark for a function with the signature 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)
        }),
    );
}

However, unlike with types that have the Copy trait, the compiler throws out the following ownership error.

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

How can non-copyable inputs be passed to the benchmarked function without running into ownership issues?


Solution

  • As suggested by @Stargateur, cloning the parameter solved the ownership issue.

    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())
            }),
        );
    }
    

    However, as proposed by @DenysSéguret and @Masklinn, changing the hash function to accept &[&str] avoids the ~50% overhead of cloning the vector.