#![cfg(feature = "rayon")] #![feature(test)] use ndarray::parallel::prelude::*; use ndarray::prelude::*; extern crate test; use test::Bencher; use ndarray::Zip; const EXP_N: usize = 256; const ADDN: usize = 512; fn set_threads() { // Consider setting a fixed number of threads here, for example to avoid // oversubscribing on hyperthreaded cores. // let n = 4; // let _ = rayon::ThreadPoolBuilder::new().num_threads(n).build_global(); } #[bench] fn map_exp_regular(bench: &mut Bencher) { let mut a = Array2::::zeros((EXP_N, EXP_N)); a.swap_axes(0, 1); bench.iter(|| { a.mapv_inplace(|x| x.exp()); }); } #[bench] fn rayon_exp_regular(bench: &mut Bencher) { set_threads(); let mut a = Array2::::zeros((EXP_N, EXP_N)); a.swap_axes(0, 1); bench.iter(|| { a.view_mut().into_par_iter().for_each(|x| *x = x.exp()); }); } const FASTEXP: usize = EXP_N; #[inline] fn fastexp(x: f64) -> f64 { let x = 1. + x / 1024.; x.powi(1024) } #[bench] fn map_fastexp_regular(bench: &mut Bencher) { let mut a = Array2::::zeros((FASTEXP, FASTEXP)); bench.iter(|| a.mapv_inplace(|x| fastexp(x))); } #[bench] fn rayon_fastexp_regular(bench: &mut Bencher) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); bench.iter(|| { a.view_mut().into_par_iter().for_each(|x| *x = fastexp(*x)); }); } #[bench] fn map_fastexp_cut(bench: &mut Bencher) { let mut a = Array2::::zeros((FASTEXP, FASTEXP)); let mut a = a.slice_mut(s![.., ..-1]); bench.iter(|| a.mapv_inplace(|x| fastexp(x))); } #[bench] fn rayon_fastexp_cut(bench: &mut Bencher) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); let mut a = a.slice_mut(s![.., ..-1]); bench.iter(|| { a.view_mut().into_par_iter().for_each(|x| *x = fastexp(*x)); }); } #[bench] fn map_fastexp_by_axis(bench: &mut Bencher) { let mut a = Array2::::zeros((FASTEXP, FASTEXP)); bench.iter(|| { for mut sheet in a.axis_iter_mut(Axis(0)) { sheet.mapv_inplace(fastexp) } }); } #[bench] fn rayon_fastexp_by_axis(bench: &mut Bencher) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); bench.iter(|| { a.axis_iter_mut(Axis(0)) .into_par_iter() .for_each(|mut sheet| sheet.mapv_inplace(fastexp)); }); } #[bench] fn rayon_fastexp_zip(bench: &mut Bencher) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); bench.iter(|| { Zip::from(&mut a) .into_par_iter() .for_each(|(elt,)| *elt = fastexp(*elt)); }); } #[bench] fn add(bench: &mut Bencher) { let mut a = Array2::::zeros((ADDN, ADDN)); let b = Array2::::zeros((ADDN, ADDN)); let c = Array2::::zeros((ADDN, ADDN)); let d = Array2::::zeros((ADDN, ADDN)); bench.iter(|| { azip!((a in &mut a, &b in &b, &c in &c, &d in &d) { *a += b.exp() + c.exp() + d.exp(); }); }); } #[bench] fn rayon_add(bench: &mut Bencher) { set_threads(); let mut a = Array2::::zeros((ADDN, ADDN)); let b = Array2::::zeros((ADDN, ADDN)); let c = Array2::::zeros((ADDN, ADDN)); let d = Array2::::zeros((ADDN, ADDN)); bench.iter(|| { par_azip!((a in &mut a, b in &b, c in &c, d in &d) { *a += b.exp() + c.exp() + d.exp(); }); }); } const COLL_STRING_N: usize = 64; const COLL_F64_N: usize = 128; #[bench] fn vec_string_collect(bench: &mut test::Bencher) { let v = vec![""; COLL_STRING_N * COLL_STRING_N]; bench.iter(|| v.iter().map(|s| s.to_owned()).collect::>()); } #[bench] fn array_string_collect(bench: &mut test::Bencher) { let v = Array::from_elem((COLL_STRING_N, COLL_STRING_N), ""); bench.iter(|| Zip::from(&v).par_map_collect(|s| s.to_owned())); } #[bench] fn vec_f64_collect(bench: &mut test::Bencher) { let v = vec![1.; COLL_F64_N * COLL_F64_N]; bench.iter(|| v.iter().map(|s| s + 1.).collect::>()); } #[bench] fn array_f64_collect(bench: &mut test::Bencher) { let v = Array::from_elem((COLL_F64_N, COLL_F64_N), 1.); bench.iter(|| Zip::from(&v).par_map_collect(|s| s + 1.)); }