Blog

rust のベンチマーク取る時は `cargo build --release` しなくてはならない

[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]

[dependencies]
futures = "0.1.14"
hyper = "0.11"

extern crate hyper;
extern crate futures;
use futures::future::Future;

use hyper::header::ContentLength;
use hyper::server::{Http, Request, Response, Service};

struct HelloWorld;
const PHRASE: &'static str = "Hello, World!";

impl Service for HelloWorld {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;

    type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;

    fn call(&self, _req: Request) -> Self::Future {
        Box::new(futures::future::ok(
                    Response::new()
                    .with_header(ContentLength(PHRASE.len() as u64))
                    .with_body(PHRASE)
                    ))
    }
}

fn main() {
    let addr = "127.0.0.1:3000".parse().unwrap();
    let server = Http::new().bind(&addr, || Ok(HelloWorld)).unwrap();
    server.run().unwrap();
}

のようなシンプルな hyper の本家サイトから取ってきたコードを実行した場合について考える。

普通に cargo build すると依存ライブラリ含めてデバッグビルドされるのでとにかく遅い。

仮想マシンのローカルから適当にベンチマーク取った場合以下のようになる。

[tokuhirom@dev2 httpd]$ wrk --latency http://localhost:3000
Running 10s test @ http://localhost:3000
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.65ms    1.03ms  21.86ms   89.72%
    Req/Sec     3.16k   718.96     4.04k    61.50%
  Latency Distribution
     50%    1.33ms
     75%    1.61ms
     90%    2.70ms
     99%    5.65ms
  63230 requests in 10.05s, 5.37MB read
Requests/sec:   6293.04
Transfer/sec:    546.95KB

cargo build --release した Release ビルドだと以下のようになり、めちゃくちゃ差が出る。

[tokuhirom@dev2 httpd]$ wrk --latency http://localhost:3000
Running 10s test @ http://localhost:3000
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   353.40us  428.95us  12.69ms   98.36%
    Req/Sec    14.56k     4.55k   20.66k    45.77%
  Latency Distribution
     50%  249.00us
     75%  393.00us
     90%  538.00us
     99%    0.94ms
  291181 requests in 10.10s, 24.71MB read
Requests/sec:  28828.72
Transfer/sec:      2.45MB

C や C++ の場合には、ライブラリコードは yum で入れたものとかを使う事が多く、そこまでアプリケーションコードが debug build かどうかに神経質にならなくてもわりとそれなりにパフォーマンスに差は出にくいが、cargo の場合、依存ライブラリも debug build してるっぽいんでめっちゃ差がでるっぽさ。

ちなみに rust の http server 実装は実質的に hyper 一択かつ、hyper は express-worker 的な機構もないので自前でthread をなんとかしない限り CPU を使い切るのは難しそう。