e-tipsmemo

ごった煮

Rust multithread 実行時間測定

multithreadが本当に効いているのかを確かめたいので
シングルスレッドとマルチスレッドで実行時間を測定したかった。

しかし、
ここのような
e-tipsmemo.hatenablog.com
cargo banchによる測定方法ではなんだかうまくいかなかったので
シンプルに実行前後の時間の差分をとる補法で比較した。

e-tipsmemo.hatenablog.com

time crateを使うのでCargo.tomlに追記する。

[dependencies]
time = "*"

main.rs

extern crate time;

use std::u32;
use std::thread;
use std::sync::{Arc, Mutex};

use test::test::Bencher;
use time::precise_time_ns;

#[derive(Debug, Copy, Clone)]
struct Fx {
    a: f64,
    b: f64,
    step: u64,
    f: fn(f64) -> f64,
}

impl Fx {
    fn new(a: f64, b: f64, step: u64, f: fn(f64) -> f64) -> Fx {
        Fx {
            a: a,
            b: b,
            step: step,
            f: f,
        }
    }
}

fn integral(p: &Fx) -> f64 {
    let dx = (p.b - p.a) / (p.step as f64);

    let mut sum = 0.0;

    for n in 0..p.step {
        let x = p.a + dx * (n as f64);
        let bar = ((p.f)(x) + (p.f)(x + dx)) * dx / 2.0;
        sum = sum + bar;
    }
    sum
}

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

    const a: f64 = 0.0;
    const b: f64 = 1.0;
    const thread: u64 = 4;
    const onestep: u64 = 100000000;

    fn f(x: f64) -> f64 {
        x * x + 1.0
    }

    #[test]
    fn int_test() {
        let prim = Fx::new(a, b, thread * onestep, f);
        let t0 = precise_time_ns();
        let ret = integral(&prim);
        let t1 = precise_time_ns();
        println!("single:{:?}", ret);
        println!("exec time:{}", t1 - t0);
    }

    #[test]
    fn int_thread_test() {
        let mut pvec = vec![];
        let x = (b - a) / (thread as f64);
        let ti = thread as usize;

        for t in 0..thread {
            let at = a + x * (t as f64);
            let bt = a + x * (t as f64) + x;
            let prim = Fx::new(at, bt, onestep, f);
            pvec.push(prim);
        }

        let mut children = vec![];
        let mut data = vec![];

        for i in 0..ti {
            let p = pvec[i];
            children.push(thread::spawn(move || integral(&p)));
        }

        let t0 = precise_time_ns();
        for child in children {
            data.push(child.join().unwrap());
        }

        let res = data.iter().fold(0.0, |s, &t| s + t);
        let t1 = precise_time_ns();

        println!("{:?}", data);
        println!("multi:{:?}", res);
        println!("exec time:{}", t1 - t0);
    }
}

fn main() {
    let handle = thread::spawn(|| {
        println!("Hello, thread World!");
    });

    let _ = handle.join();
}

実行結果

$ cargo test
running 2 tests
[0.255208333333325, 0.2864583333333229, 0.3489583333333, 0.44270833333330617]
multi:1.333333333333254
exec time:12128613000
.single:1.3333333333333182
exec time:30163525000
.
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured

速く。。なっている?気がする。
これは実行部分の時間しか測定しておらず、
ThreadHandleを取得するところも含めるとマルチスレッドを使用したほうが時間がかかることになる。
なのでトータルでの実行時間を速くするためにはThreadHandleを取得する時間が支配的にならないようなアプリで使ワなければ意味がない。

Programming Rust: Fast, Safe Systems Development

Programming Rust: Fast, Safe Systems Development

並行コンピューティング技法 ―実践マルチコア/マルチスレッドプログラミング

並行コンピューティング技法 ―実践マルチコア/マルチスレッドプログラミング