39
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rustその3Advent Calendar 2019

Day 16

Stable Rustでベンチマークを統計的に評価する

Last updated at Posted at 2019-12-15

Nightly Rustで有効化されるtest crateにはベンチマークを取る機能があります。

#![feature(test)]

extern crate test;

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[bench]
    fn bench_add_two(b: &mut Bencher) {
        b.iter(|| add_two(2));
    }
}

ベンチマークテストより抜粋)

$ cargo bench
   Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
     Running target/release/adder-91b3e234d4ed382a

running 2 tests
test tests::it_works ... ignored
test tests::bench_add_two ... bench:         1 ns/iter (+/- 0)

test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured

このように、cargo benchを実行するとベンチマークテストを実行してくれます。早すぎてベンチマークが上手くとれない場合は自動的に何回か実行して平均値を出してくれます。

しかしプログラムの実行では様々な要因で速度が変化するため、例えばmasterブランチから何か高速化を行ったブランチfeature/fasterでのベンチマーク結果が偶然早かっただけなのか、有意に性能向上が行われたのかを評価する必要があります

criterion.rs

それを自動的に行ってくれるのがbheisler/criterion.rsです。これはtest crateと違ってStable Rustで動作します。

Cargo.toml
[dev-dependencies]
criterion = "0.3"

[[bench]]
name = "my_benchmark"
harness = false

cargo benchコマンドにはCargo.tomlにある[[bench]]の設定を見てベンチマークを実行する機能があります。

Setting the keys autobins, autoexamples, autotests, or autobenches to false in the [package] section will disable auto-discovery of the corresponding target type.
https://doc.rust-lang.org/cargo/reference/manifest.html#target-auto-discovery

ちなみに自動検出機能は無効化する事も出来ます。harness = falseはテスト用のランタイムを使わない設定で、criterionが代わりに実行機能を提供してくれます。[[bench]]のように2重括弧になってるのはTOMLのテーブル記法で、JSONで言うと

{
  "bench": [
    { "name": "my_benchmark", "harness": false }
  ]
}

のような意味になります。これでbenches/my_benchmark.rsを実行してくれます。

benches/my_benchmark.rs
#[macro_use]
extern crate criterion;

use criterion::Criterion;
use criterion::black_box;

fn fibonacci(n: u64) -> u64 {
    match n {
        0 => 1,
        1 => 1,
        n => fibonacci(n-1) + fibonacci(n-2),
    }
}

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

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

test crateを意識して作ってるので使い方は概ね分かると思います。詳しくはドキュメントを見てください。

$ cargo bench
    Finished release [optimized] target(s) in 0.02s
     Running target/release/deps/bench_cri-5f525a32c3c684a8

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/release/deps/my_benchmark-37b634fc2faf7ab4
fib 20                  time:   [19.834 us 19.894 us 19.951 us]
                        change: [+0.7446% +1.9224% +3.1291%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 5 outliers among 100 measurements (5.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  1 (1.00%) high severe

また同時に target/criterion 以下にHTMLのレポートが生成されています。

image.png

39
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?