|  | #![allow(deprecated)] | 
|  |  | 
|  | use criterion::{criterion_group, criterion_main, Criterion}; | 
|  | use itertools::{cloned, Itertools}; | 
|  |  | 
|  | trait IterEx: Iterator { | 
|  | // Another efficient implementation against which to compare, | 
|  | // but needs `std` so is less desirable. | 
|  | fn tree_reduce_vec<F>(self, mut f: F) -> Option<Self::Item> | 
|  | where | 
|  | F: FnMut(Self::Item, Self::Item) -> Self::Item, | 
|  | Self: Sized, | 
|  | { | 
|  | let hint = self.size_hint().0; | 
|  | let cap = std::mem::size_of::<usize>() * 8 - hint.leading_zeros() as usize; | 
|  | let mut stack = Vec::with_capacity(cap); | 
|  | self.enumerate().for_each(|(mut i, mut x)| { | 
|  | while (i & 1) != 0 { | 
|  | x = f(stack.pop().unwrap(), x); | 
|  | i >>= 1; | 
|  | } | 
|  | stack.push(x); | 
|  | }); | 
|  | stack.into_iter().fold1(f) | 
|  | } | 
|  | } | 
|  | impl<T: Iterator> IterEx for T {} | 
|  |  | 
|  | macro_rules! def_benchs { | 
|  | ($N:expr, | 
|  | $FUN:ident, | 
|  | $BENCH_NAME:ident, | 
|  | ) => { | 
|  | mod $BENCH_NAME { | 
|  | use super::*; | 
|  |  | 
|  | pub fn sum(c: &mut Criterion) { | 
|  | let v: Vec<u32> = (0..$N).collect(); | 
|  |  | 
|  | c.bench_function( | 
|  | &(stringify!($BENCH_NAME).replace('_', " ") + " sum"), | 
|  | move |b| b.iter(|| cloned(&v).$FUN(|x, y| x + y)), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub fn complex_iter(c: &mut Criterion) { | 
|  | let u = (3..).take($N / 2); | 
|  | let v = (5..).take($N / 2); | 
|  | let it = u.chain(v); | 
|  |  | 
|  | c.bench_function( | 
|  | &(stringify!($BENCH_NAME).replace('_', " ") + " complex iter"), | 
|  | move |b| b.iter(|| it.clone().map(|x| x as f32).$FUN(f32::atan2)), | 
|  | ); | 
|  | } | 
|  |  | 
|  | pub fn string_format(c: &mut Criterion) { | 
|  | // This goes quadratic with linear `fold1`, so use a smaller | 
|  | // size to not waste too much time in travis.  The allocations | 
|  | // in here are so expensive anyway that it'll still take | 
|  | // way longer per iteration than the other two benchmarks. | 
|  | let v: Vec<u32> = (0..($N / 4)).collect(); | 
|  |  | 
|  | c.bench_function( | 
|  | &(stringify!($BENCH_NAME).replace('_', " ") + " string format"), | 
|  | move |b| { | 
|  | b.iter(|| { | 
|  | cloned(&v) | 
|  | .map(|x| x.to_string()) | 
|  | .$FUN(|x, y| format!("{} + {}", x, y)) | 
|  | }) | 
|  | }, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | criterion_group!( | 
|  | $BENCH_NAME, | 
|  | $BENCH_NAME::sum, | 
|  | $BENCH_NAME::complex_iter, | 
|  | $BENCH_NAME::string_format, | 
|  | ); | 
|  | }; | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 10_000, | 
|  | fold1, | 
|  | fold1_10k, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 10_000, | 
|  | tree_reduce, | 
|  | tree_reduce_stack_10k, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 10_000, | 
|  | tree_reduce_vec, | 
|  | tree_reduce_vec_10k, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 100, | 
|  | fold1, | 
|  | fold1_100, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 100, | 
|  | tree_reduce, | 
|  | tree_reduce_stack_100, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 100, | 
|  | tree_reduce_vec, | 
|  | tree_reduce_vec_100, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 8, | 
|  | fold1, | 
|  | fold1_08, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 8, | 
|  | tree_reduce, | 
|  | tree_reduce_stack_08, | 
|  | } | 
|  |  | 
|  | def_benchs! { | 
|  | 8, | 
|  | tree_reduce_vec, | 
|  | tree_reduce_vec_08, | 
|  | } | 
|  |  | 
|  | criterion_main!( | 
|  | fold1_10k, | 
|  | tree_reduce_stack_10k, | 
|  | tree_reduce_vec_10k, | 
|  | fold1_100, | 
|  | tree_reduce_stack_100, | 
|  | tree_reduce_vec_100, | 
|  | fold1_08, | 
|  | tree_reduce_stack_08, | 
|  | tree_reduce_vec_08, | 
|  | ); |