なっぱ箱

ゲームとか読書の感想とか時々技術系の話とか

非nightlyなRustプロジェクトでベンチマークを使用する方法

概要

Rustには公式ベンチマークツールがあるが現状unstableなのでnightlyでしかコンパイルできない。 だからプロジェクトがstableだと使えないんかなー、と思って調べてみたらやり方があったのでメモしておく。

試してみる

プロジェクトを用意

$ cargo new --lib hello_bench
$ cd hello_bench

新規プロジェクトを作ったあとはベンチマーク対象のコードと、一応テストコードでも書いておく。 src/lib.rsを下記のように変更。

pub fn sum(x: u8, y: u8) -> u8 {
    x + y
}

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

    #[test]
    fn sum_test() {
        assert_eq!(sum(2, 3), 5);
    }
}

特にunstableな機能を使っていないので、stableでテストが通る。

$ cargo test
   Compiling hello_bench v0.1.0 (/Users/yamash723/Workspace/labo/rust/hello_bench)
    Finished dev [unoptimized + debuginfo] target(s) in 0.38s
     Running target/debug/deps/hello_bench-a775e998ab4d2775

running 1 test
test tests::sum_test ... ok

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

   Doc-tests hello_bench

running 0 tests

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

ベンチマークコードをプロジェクトに追加

もしもnightlyなプロジェクトであればsrc/lib.rsに追加すれば動くといえば動くんだけども、 #[bench]属性の関数であっても#[cfg(test)]配下であればcargo test時に実行されてしまうのでおすすめできない。

そこで、benchesというベンチマークコードを配置するためのオプショナルディレクトリがRustには用意されているので、そこにコードを配置する。

$ mkdir benches
$ touch benches/bench.rs

benchescargo bench実行時にのみビルドされるので、プロジェクトのメインコードと切り分けることができる。

とりあえず先程作成した関数をベンチマークするコードをbenches/bench.rsに追加する。

#![feature(test)]

extern crate test;

#[bench]
fn sum_bench(b: &mut test::Bencher) {
    b.iter(|| hello_bench::sum(2, 3))
}

評価対象の関数の呼び出しはhello_bench::sum(2, 3)のようにパッケージ名経由で行えばよい。

なおベンチマーク実行時、benches直下のファイルはすべてビルド対象になるのでファイル名に特に決まりはない。 コード量が多くなってきたら各ベンチマークコードをサブモジュール化してbench.rsで参照するような形にするとスッキリすると思う。

そしてベンチマークを実行する際、下記のようにnightly指定でcargoを実行すればベンチマークを実行することができる。

$ cargo +nightly bench]
   Compiling hello_bench v0.1.0 (/Users/yamash723/Workspace/labo/rust/hello_bench)
    Finished release [optimized] target(s) in 0.45s
     Running target/release/deps/hello_bench-c6eaba87c0013faa

running 1 test
test tests::sum_test ... ignored

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

     Running target/release/deps/bench-e4ecc1d2436f81bb

running 1 test
test sum_bench ... bench:           1 ns/iter (+/- 0)

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

これでプロジェクトのメインコードはstableのままベンチマークを実行することができるようになった。