diff --git a/test/perf/micro/Makefile b/test/perf/micro/Makefile index 480f3a3b76cec..799e472cf7f3d 100644 --- a/test/perf/micro/Makefile +++ b/test/perf/micro/Makefile @@ -123,6 +123,9 @@ benchmarks/java.csv: java/src/main/java/PerfBLAS.java benchmarks/scala.csv: scala/src/main/scala/perf.scala scala/build.sbt cd scala; for t in 1 2 3 4 5; do sbt run; done >../$@ +benchmarks/rust.csv: rust/src/main.rs rust/Cargo.toml rust/Cargo.lock + cd rust; for t in 1 2 3 4 5; do cargo run -q --release; done >../$@ + BENCHMARKS = \ benchmarks/c.csv \ benchmarks/fortran.csv \ @@ -135,7 +138,8 @@ BENCHMARKS = \ benchmarks/matlab.csv \ benchmarks/octave.csv \ benchmarks/python.csv \ - benchmarks/r.csv + benchmarks/r.csv \ + benchmarks/rust.csv # These were formerly listed in BENCHMARKS, but I can't get them to run # 2017-09-27 johnfgibson diff --git a/test/perf/micro/rust/.gitignore b/test/perf/micro/rust/.gitignore new file mode 100644 index 0000000000000..ea8c4bf7f35f6 --- /dev/null +++ b/test/perf/micro/rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/test/perf/micro/rust/Cargo.lock b/test/perf/micro/rust/Cargo.lock new file mode 100644 index 0000000000000..b534aba569fb9 --- /dev/null +++ b/test/perf/micro/rust/Cargo.lock @@ -0,0 +1,212 @@ +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "blas" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blas-sys 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "blas-sys" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "openblas-src 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "julia-bench" +version = "0.1.0" +dependencies = [ + "blas 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blas-sys 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mersenne_twister 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ndarray 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matrixmultiply" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mersenne_twister" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ndarray" +version = "0.10.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blas-sys 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "matrixmultiply 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-rational" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openblas-src" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rawpointer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum blas 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c994113e52889e188a01098afd9b8857a610635581a6171e0c7f8ca6dc05216b" +"checksum blas-sys 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d8f9828026cdd2441c52d1299842da7baff09d325a98f6e97df527ad8f29a095" +"checksum either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e311a7479512fbdf858fb54d91ec59f3b9f85bc0113659f46bba12b199d273ce" +"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" +"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" +"checksum itertools 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7cc0332eecf9269cc5e084ec9993e4d087776733cfb286cd77514030fee2716c" +"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" +"checksum matrixmultiply 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7ce012d2c43046267a74283eaa7e9a51941479901e2b86702be10f27e2779158" +"checksum mersenne_twister 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53c37a7b59c9c4b899cb52f7f7d92b7459bc62b2e3df1e7f57319a0b4a1eab8c" +"checksum ndarray 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "4081816658dbd5f219dc4ef1ec842496b7dc4987ad8d613c6eb8823a5f532ed8" +"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "8fd0f8dbb4c0960998958a796281d88c16fbe68d87b1baa6f31e2979e81fd0bd" +"checksum num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "503e668405c5492d67cf662a81e05be40efe2e6bcf10f7794a07bd9865e704e6" +"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" +"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +"checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum openblas-src 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "409b425320a6b63c6a0b9fa69bedf27c18038046c2e1df3b3f382b89fd68323e" +"checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" +"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" diff --git a/test/perf/micro/rust/Cargo.toml b/test/perf/micro/rust/Cargo.toml new file mode 100644 index 0000000000000..d8c6a723ec549 --- /dev/null +++ b/test/perf/micro/rust/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "julia-bench" +publish = false +version = "0.1.0" + +[dependencies] +itertools = "0.7.1" +mersenne_twister = "1.1.0" +num = "0.1.37" +rand = "0.3.15" + +[dependencies.blas] +features = ["openblas"] +version = "0.18.1" +optional = true + +[dependencies.blas-sys] +version = "0.6.9" +features = ["openblas"] + +[dependencies.ndarray] +features = ["blas"] +version = "0.10.12" + +[features] +default = [] +direct_blas = ["blas"] diff --git a/test/perf/micro/rust/rust-toolchain b/test/perf/micro/rust/rust-toolchain new file mode 100644 index 0000000000000..1cb7be17b1b46 --- /dev/null +++ b/test/perf/micro/rust/rust-toolchain @@ -0,0 +1 @@ +nightly-2017-10-28 diff --git a/test/perf/micro/rust/src/direct_blas.rs b/test/perf/micro/rust/src/direct_blas.rs new file mode 100644 index 0000000000000..700f284f3e6fc --- /dev/null +++ b/test/perf/micro/rust/src/direct_blas.rs @@ -0,0 +1,128 @@ +#![allow(unsafe_code)] + +use rand::Rng; +use std::iter::Sum; +use util::{gen_rng, fill_rand, myrand}; +use blas::c::{dgemm, Layout, Transpose}; +use itertools::Itertools; + +pub fn randmatstat(t: usize) -> (f64, f64) { + let mut rng = gen_rng(1234u64); + + let n = 5; + + let mut v = vec![0.; t]; + let mut w = vec![0.; t]; + + { + let mut a = vec![0.; n * n]; + let mut b = vec![0.; n * n]; + let mut c = vec![0.; n * n]; + let mut d = vec![0.; n * n]; + let mut p = vec![0.; (n) * (4 * n)]; + let mut q = vec![0.; (2 * n) * (2 * n)]; + + let mut pt_p1 = vec![0.; (4 * n) * (4 * n)]; + let mut pt_p2 = vec![0.; (4 * n) * (4 * n)]; + let mut qt_q1 = vec![0.; (2 * n) * (2 * n)]; + let mut qt_q2 = vec![0.; (2 * n) * (2 * n)]; + + for (ve, we) in v.iter_mut().zip(w.iter_mut()) { + fill_rand(&mut a, &mut rng); + fill_rand(&mut b, &mut rng); + fill_rand(&mut c, &mut rng); + fill_rand(&mut d, &mut rng); + + p[0 .. n * n].copy_from_slice(&a); + p[n * n .. 2 * n * n].copy_from_slice(&b); + p[2 * n * n .. 3 * n * n].copy_from_slice(&c); + p[3 * n * n .. 4 * n * n].copy_from_slice(&d); + + for j in 0..n { + for k in 0..n { + q[2 * n * j + k] = a[k]; + q[2 * n * j + n + k] = b[k]; + q[2 * n * (n + j) + k] = c[k]; + q[2 * n * (n + j) + n + k] = d[k]; + } + } + + unsafe { + let n = n as i32; + + dgemm(Layout::ColumnMajor, Transpose::Ordinary, Transpose::None, + n , n, 4 * n, 1., &p, 4 * n, &p, 4 * n, 0., + &mut pt_p1, 4 * n); + dgemm(Layout::ColumnMajor, Transpose::None, Transpose::None, + 4 * n, 4 * n, 4 * n, 1., &pt_p1, 4 * n, &pt_p1, 4 * n, 0., + &mut pt_p2, 4 * n); + dgemm(Layout::ColumnMajor, Transpose::None, Transpose::None, + 4 * n, 4 * n, 4 * n, 1., &pt_p2, 4 * n, &pt_p2, 4 * n, 0., + &mut pt_p1, 4 * n); + } + + *ve = trace(&pt_p1, n * 4); + + unsafe { + let n = n as i32; + + dgemm(Layout::ColumnMajor, Transpose::Ordinary, Transpose::None, + 2 * n, 2 * n, 2 * n, 1., &q, 2 * n, &q, 2 * n, 0., + &mut qt_q1, 2 * n); + dgemm(Layout::ColumnMajor, Transpose::None, Transpose::None, + 2 * n, 2 * n, 2 * n, 1., &qt_q1, 2 * n, &qt_q1, 2 * n, 0., + &mut qt_q2, 2 * n); + dgemm(Layout::ColumnMajor, Transpose::None, Transpose::None, + 2 * n, 2 * n, 2 * n, 1., &qt_q2, 2 * n, &qt_q2, 2 * n, 0., + &mut qt_q1, 2 * n); + } + + *we = trace(&qt_q1, 2 * n); + } + } + + let (v1, v2, w1, w2) = v.iter() + .zip(w.iter()) + .fold((0., 0., 0., 0.), |(v1, v2, w1, w2), (ve, we)| ( + v1 + *ve, + v2 + ve * ve, + w1 + *we, + w2 + we * we + )); + + let t = t as f64; + + ( + f64::sqrt((t * (t * v2 - v1 * v1)) / ((t - 1.) * v1 * v1)), + f64::sqrt((t * (t * w2 - w1 * w1)) / ((t - 1.) * w1 * w1)), + ) +} + +/// Calculate the trace of a square matrix +#[inline] +fn trace<'a, T>(m: &'a [T], n: usize) -> T +where + T: Sum<&'a T> +{ + debug_assert_eq!(m.len(), n * n); + m.into_iter().step(n + 1).sum() +} + +pub fn randmatmul(n: usize, mut rng: R) -> Vec { + let a = myrand(n * n, &mut rng); + let b = myrand(n * n, &mut rng); + let mut c = vec![0.; n * n]; + + unsafe { + let n = n as i32; + dgemm(Layout::ColumnMajor, Transpose::None, Transpose::None, + n, n, n, 1., &a, n, &b, n, 0., &mut c, n); + } + + c +} + +#[inline] +pub fn check_randmatmul(m: Vec) { + assert!(0. <= m[0]); +} diff --git a/test/perf/micro/rust/src/main.rs b/test/perf/micro/rust/src/main.rs new file mode 100644 index 0000000000000..b39c2314bb62a --- /dev/null +++ b/test/perf/micro/rust/src/main.rs @@ -0,0 +1,335 @@ +#![feature(test)] +#![deny(unsafe_code)] + +extern crate itertools; +extern crate mersenne_twister; +extern crate num; +extern crate rand; +extern crate test; + +// Use BLAS directly +#[cfg(feature = "direct_blas")] +extern crate blas; + +// Use ndarray (with BLAS implementation) +#[cfg(not(feature = "direct_blas"))] +#[macro_use(s)] +extern crate ndarray; + +use std::time::{Duration, Instant}; +use std::u32; +use std::fs::OpenOptions; +use std::io::{BufWriter, Write}; + +use test::black_box; +use num::complex::Complex64; +use rand::Rng; + +mod util; +use util::{gen_rng, myrand}; + +#[cfg(feature = "direct_blas")] +mod direct_blas; +#[cfg(feature = "direct_blas")] +use direct_blas::{randmatstat, randmatmul, check_randmatmul}; + +#[cfg(not(feature = "direct_blas"))] +use ndarray::Array2; +#[cfg(not(feature = "direct_blas"))] +use util::fill_rand; +#[cfg(not(feature = "direct_blas"))] +use num::Zero; + +const NITER: u32 = 5; + +#[cfg(not(feature = "direct_blas"))] +fn nrand(shape: (usize, usize), rng: &mut R) -> Array2 { + let mut m = Array2::zeros(shape); + fill_rand(&mut m, rng); + m +} + +fn fib(n: i32) -> i32 { + if n < 2 { + n + } else { + fib(black_box(n - 1)) + fib(black_box(n - 2)) + } +} + +fn mandel(z: Complex64) -> u32 { + use std::iter; + + iter::repeat(z) + .scan(z, |z, c| { + let current = *z; + *z = current * current + c; + Some(current) + }) + .take(80) + .take_while(|z| z.norm() <= 2.0) + .count() as u32 +} + +fn mandelperf() -> Vec { + let mut m: Vec = vec![0; 21 * 26]; + + for ((i, j), mut v) in (0..21) + .flat_map(|i| (0..26).map(move |j| (i, j))) + .zip(&mut m) + { + *v = mandel(Complex64::new((j - 20) as f64 / 10., + ((i - 10) as f64 / 10.))); + } + + m +} + +fn pisum() -> f64 { + let mut sum = 0.; + for _ in 0..500 { + sum = (1..10001) + .map(|k| { + let k = k as f64; + 1. / (k * k) + }) + .sum(); + } + sum +} + +#[cfg(not(feature = "direct_blas"))] +fn randmatstat(t: usize) -> (f64, f64) { + let mut rng = gen_rng(1234u64); + + let n = 5; + + let mut v = vec![0.; t]; + let mut w = vec![0.; t]; + + for (ve, we) in v.iter_mut().zip(w.iter_mut()) { + let a = nrand((n, n), &mut rng); + let b = nrand((n, n), &mut rng); + let c = nrand((n, n), &mut rng); + let d = nrand((n, n), &mut rng); + let p = { // P = [a b c d] + let mut p = Array2::::zeros((n, 4 * n)); + let n = n as isize; + p.slice_mut(s![.., 0..n]).assign(&a); + p.slice_mut(s![.., n..2*n]).assign(&b); + p.slice_mut(s![.., 2*n..3*n]).assign(&c); + p.slice_mut(s![.., 3*n..4*n]).assign(&d); + p + }; + let q = { // Q = [a b ; c d] + let mut q = Array2::::zeros((2 * n, 2 * n)); + let n = n as isize; + q.slice_mut(s![0..n, 0..n]).assign(&a); + q.slice_mut(s![0..n, n..2*n]).assign(&b); + q.slice_mut(s![n..2*n, 0..n]).assign(&c); + q.slice_mut(s![n..2*n, n..2*n]).assign(&d); + q + }; + + let pt = p.t(); + let ptp = pt.dot(&p); + let ptp2 = ptp.dot(&ptp); + let ptp4 = ptp2.dot(&ptp2); + *ve = trace_arr(&ptp4); + + let qt = q.t(); + let ptq = qt.dot(&q); + let ptq2 = ptq.dot(&ptq); + let ptq4 = ptq2.dot(&ptq2); + *we = trace_arr(&ptq4); + } + + let (v1, v2, w1, w2) = v.iter() + .zip(w.iter()) + .fold((0., 0., 0., 0.), |(v1, v2, w1, w2), (ve, we)| ( + v1 + *ve, + v2 + ve * ve, + w1 + *we, + w2 + we * we + )); + + let t = t as f64; + + ( + f64::sqrt((t * (t * v2 - v1 * v1)) / ((t - 1.) * v1 * v1)), + f64::sqrt((t * (t * w2 - w1 * w1)) / ((t - 1.) * w1 * w1)), + ) +} + +/// Calculate the trace of a square matrix +#[cfg(not(feature = "direct_blas"))] +#[inline] +fn trace_arr<'a, T: 'a>(m: &'a Array2) -> T +where + T: Zero + Clone +{ + m.diag().scalar_sum() +} + +#[cfg(not(feature = "direct_blas"))] +fn randmatmul(n: usize, mut rng: R) -> Array2 { + let a = nrand((n, n), &mut rng); + let b = nrand((n, n), &mut rng); + + a.dot(&b) +} + +#[cfg(not(feature = "direct_blas"))] +#[inline] +fn check_randmatmul(m: Array2) { + assert!(0. <= m[[0, 0]]); +} + +#[test] +fn test_quicksort() { + let mut a = [10., 9., 8., 7., 6., 5., 4., 3., 2., 1.]; + quicksort(a.as_mut(), 0); + assert_eq!(a, [1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]); + + let mut a = [8., 2., 10., 4., 7., 6., 9., 5., 1., 3.]; + quicksort(a.as_mut(), 0); + assert_eq!(a, [1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]); +} + +fn quicksort(a: &mut [f64], mut lo: usize) { + let hi = a.len() as usize - 1; + let mut i: usize = lo; + // j is isize because it can be -1 + let mut j: isize = hi as isize; + + while i < hi { + let pivot = a[(lo + hi) / 2]; + while i as isize <= j { + while a[i] < pivot { + i += 1; + } + while a[j as usize] > pivot { + j -= 1; + } + if i as isize <= j { + a.swap(i, j as usize); + i += 1; + j -= 1; + } + } + + let (l, _r) = a.split_at_mut((j + 1) as usize); + + if (lo as isize) < j { + quicksort(l, lo); + } + + lo = i; + j = hi as isize; + } +} + +fn printfd(n: usize) { + let f = OpenOptions::new() + .write(true).open("/dev/null").unwrap(); + let mut f = BufWriter::new(f); + for i in 0..n { + writeln!(f, "{} {}", i, i).unwrap(); + } +} + +fn print_perf(name: &str, t: f64) { + println!("rust,{},{:.6}", name, t * 1000.); +} + +/// convert duration to float in seconds +fn to_float(d: Duration) -> f64 { + d.as_secs() as f64 + d.subsec_nanos() as f64 / 1e9 +} + +#[inline] +fn measure_best(niters: u32, mut op: F) -> Duration { + (0..niters) + .map(move |_| { + let t = Instant::now(); + op(); + t.elapsed() + }).min().unwrap() +} + +fn main() { + // initialize RNG + let mut rng = gen_rng(0); + + // fib(20) + assert_eq!(fib(20), 6765); + let mut f = 0i32; + let fibarg = black_box(20); + let tmin = measure_best(NITER, || { + for _ in 0..1000 { + f = f.wrapping_add(fib(fibarg)); + } + }); + print_perf("fib", to_float(tmin) / 1000.0); + + // parse_int + let tmin = measure_best(NITER, || { + for _ in 0..1000 * 100 { + let n: u32 = rng.gen(); + let s = format!("{:x}", n); + let m = u32::from_str_radix(&s, 16).unwrap(); + assert_eq!(m, n); + } + }); + print_perf("parse_int", to_float(tmin) / 100.0); + + let mandel_sum_init = black_box(0u32); + let mut mandel_sum2 = mandel_sum_init; + let tmin = measure_best(NITER, || { + for j in 0..100 { + let m = mandelperf(); + if j == 0 { + let mandel_sum: u32 = m.iter().sum(); + assert_eq!(mandel_sum, 14791); + mandel_sum2 += mandel_sum; + } + } + }); + assert_eq!(mandel_sum2, 14791 * NITER); + print_perf("mandel", to_float(tmin) / 100.0); + + // sort + let tmin = measure_best(NITER, || { + let mut d = myrand(5000, &mut rng); + quicksort(&mut d, 0); + }); + print_perf("quicksort", to_float(tmin)); + + // pi sum + let mut pi = 0.; + let tmin = measure_best(NITER, || { + pi = pisum(); + }); + assert!(f64::abs(pi - 1.644834071848065) < 1e-12); + print_perf("pi_sum", to_float(tmin)); + + // rand mat stat + let mut r = (0., 0.); + let tmin = measure_best(NITER, || { + r = black_box(randmatstat(1000)); + }); + print_perf("rand_mat_stat", to_float(tmin)); + + // rand mat mul + let tmin = measure_best(NITER, || { + let c = randmatmul(1000, &mut rng); + check_randmatmul(c); + }); + print_perf("rand_mat_mul", to_float(tmin)); + + // printfd + let tmin = measure_best(NITER, || { + printfd(100000); + }); + print_perf("printfd", to_float(tmin)); +} diff --git a/test/perf/micro/rust/src/util.rs b/test/perf/micro/rust/src/util.rs new file mode 100644 index 0000000000000..cb02ce21c9e42 --- /dev/null +++ b/test/perf/micro/rust/src/util.rs @@ -0,0 +1,26 @@ +use rand::{Rand, Rng, SeedableRng}; + +use mersenne_twister::MT19937_64; +pub type MTRng = MT19937_64; + +#[inline] +pub fn gen_rng(seed: u64) -> MTRng { + MTRng::from_seed(seed) +} + +pub fn fill_rand<'a, I, T: 'a, R>(a: I, rng: &mut R) +where + I: IntoIterator, + T: Rand, + R: Rng, +{ + for v in a.into_iter() { + *v = rng.gen(); + } +} + +pub fn myrand(n: usize, rng: &mut R) -> Vec { + let mut d: Vec = vec![0.; n]; + fill_rand(&mut d, rng); + d +}