use criterion::{criterion_group, criterion_main, Criterion, Fun}; use rand::distributions::{Distribution, Standard}; use rand::prelude::*; /** * This module benchmarks the performance of zipping unused arrays together. */ #[cfg(feature = "rayon")] use rayon::prelude::*; static SEED: [u8; 32] = [3; 32]; static BUF_SIZE: usize = 750_000; #[inline] fn make_random_vec() -> Vec where Standard: Distribution, { let n = BUF_SIZE; let mut rng: StdRng = SeedableRng::from_seed(SEED); let mut vec = Vec::new(); for _ in 0..n { vec.push(rng.gen::()); } vec } // Vanilla iteration over a single vector fn benchmark(v: &mut Vec, v1: &mut Vec) { let f = |x, y| x * 3.6321 + 42314.0 * y; for (a, b) in v.iter_mut().zip(v1.iter_mut()) { let (mut a2, mut b2) = (*a, *b); a2 = f(a2, b2); b2 = f(b2, a2); a2 += f(a2, b2); b2 += f(b2, a2); a2 += f(a2, b2); b2 += f(b2, a2); a2 += f(a2, b2); *a = a2; *b = b2; } } fn unnecessary_zipping( v: &mut Vec, v1: &mut Vec, v2: &mut Vec, v3: &mut Vec, v4: &mut Vec, v5: &mut Vec, v6: &mut Vec, ) { let f = |x, y| x * 3.6321 + 42314.0 * y; for ((((((a, b), _c), _d), _e), _f), _g) in v .iter_mut() .zip(v1.iter_mut()) .zip(v2.iter_mut()) .zip(v3.iter_mut()) .zip(v4.iter_mut()) .zip(v5.iter_mut()) .zip(v6.iter_mut()) { let (mut a2, mut b2) = (*a, *b); a2 = f(a2, b2); b2 = f(b2, a2); a2 += f(a2, b2); b2 += f(b2, a2); a2 += f(a2, b2); b2 += f(b2, a2); a2 += f(a2, b2); *a = a2; *b = b2; } } fn unnecessary_zipping_with_map( v: &mut Vec, v1: &mut Vec, v2: &mut Vec, v3: &mut Vec, v4: &mut Vec, v5: &mut Vec, v6: &mut Vec, ) { let f = |x, y| x * 3.6321 + 42314.0 * y; for (a, b, _c, _d, _e, _f, _g) in v .iter_mut() .zip(v1.iter_mut()) .zip(v2.iter_mut()) .zip(v3.iter_mut()) .zip(v4.iter_mut()) .zip(v5.iter_mut()) .zip(v6.iter_mut()) .map(|((((((a, b), c), d), e), f), g)| (a, b, c, d, e, f, g)) { let (mut a2, mut b2) = (*a, *b); a2 = f(a2, b2); b2 = f(b2, a2); a2 += f(a2, b2); b2 += f(b2, a2); a2 += f(a2, b2); b2 += f(b2, a2); a2 += f(a2, b2); *a = a2; *b = b2; } } #[allow(dead_code)] struct Group { a: f64, b: f64, c: f64, d: f64, e: f64, f: f64, g: f64, } fn unnecessary_zipping_with_struct( v: &mut Vec, v1: &mut Vec, v2: &mut Vec, v3: &mut Vec, v4: &mut Vec, v5: &mut Vec, v6: &mut Vec, ) { let fu = |x, y| x * 3.6321 + 42314.0 * y; for ((((((a, b), c), d), e), f), g) in v .iter_mut() .zip(v1.iter_mut()) .zip(v2.iter_mut()) .zip(v3.iter_mut()) .zip(v4.iter_mut()) .zip(v5.iter_mut()) .zip(v6.iter_mut()) { let mut group = Group { a: *a, b: *b, c: *c, d: *d, e: *e, f: *f, g: *g, }; group.a = fu(group.a, group.b); group.b = fu(group.b, group.a); group.a += fu(group.a, group.b); group.b += fu(group.b, group.a); group.a += fu(group.a, group.b); group.b += fu(group.b, group.a); group.a += fu(group.a, group.b); *a = group.a; *b = group.b; } } fn zipping( v: &mut Vec, v1: &mut Vec, v2: &mut Vec, v3: &mut Vec, v4: &mut Vec, v5: &mut Vec, v6: &mut Vec, ) { let f = |x, y| x * 3.6321 + 42314.0 * y; for ((((((a, b), c), d), e), f2), g) in v .iter_mut() .zip(v1.iter_mut()) .zip(v2.iter_mut()) .zip(v3.iter_mut()) .zip(v4.iter_mut()) .zip(v5.iter_mut()) .zip(v6.iter_mut()) { let (mut a2, mut b2) = (*a, *b); a2 = f(a2, b2); b2 = f(b2, a2); a2 += f(b2, *c); b2 += f(*c, *d); a2 += f(*d, *e); b2 += f(*e, *f2); a2 += f(*f2, *g); *a = a2; *b = b2; } } #[cfg(feature = "rayon")] fn zipping_with_rayon( v: &mut Vec, v1: &mut Vec, v2: &mut Vec, v3: &mut Vec, v4: &mut Vec, v5: &mut Vec, v6: &mut Vec, ) { let f = |x, y| x * 3.6321 + 42314.0 * y; v.par_iter_mut() .zip(v1.par_iter_mut()) .zip(v2.par_iter_mut()) .zip(v3.par_iter_mut()) .zip(v4.par_iter_mut()) .zip(v5.par_iter_mut()) .zip(v6.par_iter_mut()) .for_each(|((((((a, b), c), d), e), f2), g)| { let (mut a2, mut b2) = (*a, *b); a2 = f(a2, b2); b2 = f(b2, a2); a2 += f(b2, *c); b2 += f(*c, *d); a2 += f(*d, *e); b2 += f(*e, *f2); a2 += f(*f2, *g); *a = a2; *b = b2; }); } fn zip(c: &mut Criterion) { let bench = Fun::new("Benchmark", move |b, _| { let mut v = make_random_vec::(); let mut v1 = make_random_vec::(); b.iter(|| { benchmark(&mut v, &mut v1); }) }); let unnecessary_zipping = Fun::new("Unnecessary Zipping", move |b, _| { let mut v = make_random_vec::(); let mut v1 = make_random_vec::(); let mut v2 = make_random_vec::(); let mut v3 = make_random_vec::(); let mut v4 = make_random_vec::(); let mut v5 = make_random_vec::(); let mut v6 = make_random_vec::(); b.iter(|| { unnecessary_zipping(&mut v, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6); }) }); let unnecessary_zipping_with_map = Fun::new("Unnecessary Zipping With Map", move |b, _| { let mut v = make_random_vec::(); let mut v1 = make_random_vec::(); let mut v2 = make_random_vec::(); let mut v3 = make_random_vec::(); let mut v4 = make_random_vec::(); let mut v5 = make_random_vec::(); let mut v6 = make_random_vec::(); b.iter(|| { unnecessary_zipping_with_map( &mut v, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, ); }) }); let unnecessary_zipping_with_struct = Fun::new("Unnecessary Zipping With Struct", move |b, _| { let mut v = make_random_vec::(); let mut v1 = make_random_vec::(); let mut v2 = make_random_vec::(); let mut v3 = make_random_vec::(); let mut v4 = make_random_vec::(); let mut v5 = make_random_vec::(); let mut v6 = make_random_vec::(); b.iter(|| { unnecessary_zipping_with_struct( &mut v, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, ); }) }); let zipping = Fun::new("Zipping", move |b, _| { let mut v = make_random_vec::(); let mut v1 = make_random_vec::(); let mut v2 = make_random_vec::(); let mut v3 = make_random_vec::(); let mut v4 = make_random_vec::(); let mut v5 = make_random_vec::(); let mut v6 = make_random_vec::(); b.iter(|| { zipping(&mut v, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6); }) }); #[cfg(feature = "rayon")] let zipping_with_rayon = Fun::new("Zipping With Rayon", move |b, _| { let mut v = make_random_vec::(); let mut v1 = make_random_vec::(); let mut v2 = make_random_vec::(); let mut v3 = make_random_vec::(); let mut v4 = make_random_vec::(); let mut v5 = make_random_vec::(); let mut v6 = make_random_vec::(); b.iter(|| { zipping_with_rayon(&mut v, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6); }) }); let fns = vec![ bench, unnecessary_zipping, unnecessary_zipping_with_map, unnecessary_zipping_with_struct, zipping, #[cfg(feature = "rayon")] zipping_with_rayon, ]; c.bench_functions("zip", fns, ()); } criterion_group!(benches, zip); criterion_main!(benches);