diff --git a/test/perf/micro/rust/Cargo.lock b/test/perf/micro/rust/Cargo.lock index a75cd943b9dab..b534aba569fb9 100644 --- a/test/perf/micro/rust/Cargo.lock +++ b/test/perf/micro/rust/Cargo.lock @@ -1,141 +1,212 @@ -[root] -name = "julia-bench" -version = "0.1.0" -dependencies = [ - "blas 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mersenne_twister 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blas" -version = "0.15.4" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "blas-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "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.7" +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 = [ - "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", - "openblas-src 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "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.24" +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.15 (registry+https://github.com/rust-lang/crates.io-index)", + "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.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "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.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (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)", + "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.38" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 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)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 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-iter" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.39 (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)", ] [[package]] name = "num-rational" -version = "0.1.38" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "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.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openblas-src" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "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 blas 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5eb258fe599f994e73fdc6d2992f65b6f5c0d53a8a1ded01b5f534c8ce863b1b" -"checksum blas-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbb0aa755ad397cfcfb82ce50edcdf4f93eacc2697fc40f9723354d616d97d7" -"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc" +"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 num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "2c3a3dc9f30bf824141521b30c908a859ab190b76e20435fcd89f35eb6583887" -"checksum num-bigint 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "6361748d02e5291c72a422dc8ed4d8464a80cb1e618971f6fffe6d52d97e3286" -"checksum num-complex 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "412dfc143c56579aa6a22c574e38ddbf724522f1280ae2b257498cccff3fb6af" -"checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37" -"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" -"checksum num-rational 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "33c881e104a26e1accc09449374c095ff2312c8e0c27fab7bbefe16eac7c776d" -"checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6" -"checksum openblas-src 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a83675723211745cf3b08eedf276a7b7b4c6d58f9a2b41cb06a9164329e0b89" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"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 index 6360ac924ac8b..d8c6a723ec549 100644 --- a/test/perf/micro/rust/Cargo.toml +++ b/test/perf/micro/rust/Cargo.toml @@ -1,11 +1,27 @@ [package] name = "julia-bench" publish = false -description = "Rust implementation of the micro benchmark" version = "0.1.0" [dependencies] -blas = { version = "0.15.4", features = ["openblas"] } +itertools = "0.7.1" mersenne_twister = "1.1.0" -num = "0.1.39" +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 index 0f33c5746db33..b39c2314bb62a 100644 --- a/test/perf/micro/rust/src/main.rs +++ b/test/perf/micro/rust/src/main.rs @@ -1,51 +1,52 @@ -//! This is a Rust implementation of the Julia micro benchmark. -//! -//! This program is based on the C implementation, but it's still mostly -//! idiomatic Rust, and does not have unsafe code blocks. -//! -//! This project requires a **nightly** version of the Rust compiler and -//! its package manager, Cargo. When using `rustup`, installing the -//! nightly toolchain and executing `rustup override set nightly` on -//! this directory is sufficient. #![feature(test)] #![deny(unsafe_code)] -extern crate blas; -extern crate test; +extern crate itertools; +extern crate mersenne_twister; extern crate num; extern crate rand; -extern crate mersenne_twister; +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 blas::c::{dgemm, Layout, Transpose}; use test::black_box; use num::complex::Complex64; -use rand::{SeedableRng, Rng}; -use mersenne_twister::MT19937_64; +use rand::Rng; -type MTRng = MT19937_64; +mod util; +use util::{gen_rng, myrand}; -#[inline] -fn gen_rng(seed: u64) -> MTRng { - MTRng::from_seed(seed) -} +#[cfg(feature = "direct_blas")] +mod direct_blas; +#[cfg(feature = "direct_blas")] +use direct_blas::{randmatstat, randmatmul, check_randmatmul}; -const NITER: u32 = 5; +#[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; -fn fill_rand(a: &mut [f64], rng: &mut R) { - for v in a { - *v = rng.gen(); - } -} +const NITER: u32 = 5; -fn myrand(n: usize, rng: &mut R) -> Vec { - let mut d: Vec = vec![0.; n]; - fill_rand(&mut d, rng); - d +#[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 { @@ -56,17 +57,18 @@ fn fib(n: i32) -> i32 { } } -fn mandel(mut z: Complex64) -> u32 { - let maxiter = 80; - let c = z.clone(); - for n in 0..maxiter { - if z.norm() > 2.0 { - return n; - } - z = z * z + c; - } - - maxiter +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 { @@ -96,6 +98,7 @@ fn pisum() -> f64 { sum } +#[cfg(not(feature = "direct_blas"))] fn randmatstat(t: usize) -> (f64, f64) { let mut rng = gen_rng(1234u64); @@ -104,83 +107,51 @@ fn randmatstat(t: usize) -> (f64, f64) { 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]; - } - } - - { - 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); - } - - for j in 0..n { - *ve += pt_p1[(n + 1) * j]; - } - - { - 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); - } - - for j in 0..n { - *we += qt_q1[(2 * n + 1) * j]; - } - } + 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 (mut v1, mut v2, mut w1, mut w2) = (0., 0., 0., 0.); - - for (ve, we) in v.iter().zip(w.iter()) { - v1 += *ve; v2 += ve * ve; - w1 += *we; w2 += we * we; - } + 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; @@ -190,16 +161,28 @@ fn randmatstat(t: usize) -> (f64, f64) { ) } -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]; +/// 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); - let n = n as i32; - dgemm(Layout::ColumnMajor, Transpose::None, Transpose::None, - n, n, n, 1., &a, n, &b, n, 0., &mut c, n); + a.dot(&b) +} - c +#[cfg(not(feature = "direct_blas"))] +#[inline] +fn check_randmatmul(m: Array2) { + assert!(0. <= m[[0, 0]]); } #[test] @@ -213,7 +196,7 @@ fn test_quicksort() { assert_eq!(a, [1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]); } -fn quicksort(mut a: &mut [f64], mut lo: usize) { +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 @@ -294,7 +277,7 @@ fn main() { for _ in 0..1000 * 100 { let n: u32 = rng.gen(); let s = format!("{:x}", n); - let m: u32 = u32::from_str_radix(&s, 16).unwrap(); + let m = u32::from_str_radix(&s, 16).unwrap(); assert_eq!(m, n); } }); @@ -340,7 +323,7 @@ fn main() { // rand mat mul let tmin = measure_best(NITER, || { let c = randmatmul(1000, &mut rng); - assert!(0. <= c[0]); + check_randmatmul(c); }); print_perf("rand_mat_mul", 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 +}