123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877 |
- use criterion::{black_box, criterion_group, criterion_main, Criterion};
- use itertools::Itertools;
- use itertools::free::cloned;
- use itertools::iproduct;
- use std::iter::repeat;
- use std::cmp;
- use std::ops::{Add, Range};
- mod extra;
- use crate::extra::ZipSlices;
- fn slice_iter(c: &mut Criterion) {
- let xs: Vec<_> = repeat(1i32).take(20).collect();
- c.bench_function("slice iter", move |b| {
- b.iter(|| for elt in xs.iter() {
- black_box(elt);
- })
- });
- }
- fn slice_iter_rev(c: &mut Criterion) {
- let xs: Vec<_> = repeat(1i32).take(20).collect();
- c.bench_function("slice iter rev", move |b| {
- b.iter(|| for elt in xs.iter().rev() {
- black_box(elt);
- })
- });
- }
- fn zip_default_zip(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zip default zip", move |b| {
- b.iter(|| {
- for (&x, &y) in xs.iter().zip(&ys) {
- black_box(x);
- black_box(y);
- }
- })
- });
- }
- fn zipdot_i32_default_zip(c: &mut Criterion) {
- let xs = vec![2; 1024];
- let ys = vec![2; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot i32 default zip", move |b| {
- b.iter(|| {
- let mut s = 0;
- for (&x, &y) in xs.iter().zip(&ys) {
- s += x * y;
- }
- s
- })
- });
- }
- fn zipdot_f32_default_zip(c: &mut Criterion) {
- let xs = vec![2f32; 1024];
- let ys = vec![2f32; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot f32 default zip", move |b| {
- b.iter(|| {
- let mut s = 0.;
- for (&x, &y) in xs.iter().zip(&ys) {
- s += x * y;
- }
- s
- })
- });
- }
- fn zip_default_zip3(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let zs = vec![0; 766];
- let xs = black_box(xs);
- let ys = black_box(ys);
- let zs = black_box(zs);
- c.bench_function("zip default zip3", move |b| {
- b.iter(|| {
- for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) {
- black_box(x);
- black_box(y);
- black_box(z);
- }
- })
- });
- }
- fn zip_slices_ziptuple(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- c.bench_function("zip slices ziptuple", move |b| {
- b.iter(|| {
- let xs = black_box(&xs);
- let ys = black_box(&ys);
- for (&x, &y) in itertools::multizip((xs, ys)) {
- black_box(x);
- black_box(y);
- }
- })
- });
- }
- fn zipslices(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipslices", move |b| {
- b.iter(|| {
- for (&x, &y) in ZipSlices::new(&xs, &ys) {
- black_box(x);
- black_box(y);
- }
- })
- });
- }
- fn zipslices_mut(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let xs = black_box(xs);
- let mut ys = black_box(ys);
- c.bench_function("zipslices mut", move |b| {
- b.iter(|| {
- for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
- black_box(x);
- black_box(y);
- }
- })
- });
- }
- fn zipdot_i32_zipslices(c: &mut Criterion) {
- let xs = vec![2; 1024];
- let ys = vec![2; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot i32 zipslices", move |b| {
- b.iter(|| {
- let mut s = 0i32;
- for (&x, &y) in ZipSlices::new(&xs, &ys) {
- s += x * y;
- }
- s
- })
- });
- }
- fn zipdot_f32_zipslices(c: &mut Criterion) {
- let xs = vec![2f32; 1024];
- let ys = vec![2f32; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot f32 zipslices", move |b| {
- b.iter(|| {
- let mut s = 0.;
- for (&x, &y) in ZipSlices::new(&xs, &ys) {
- s += x * y;
- }
- s
- })
- });
- }
- fn zip_checked_counted_loop(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zip checked counted loop", move |b| {
- b.iter(|| {
- // Must slice to equal lengths, and then bounds checks are eliminated!
- let len = cmp::min(xs.len(), ys.len());
- let xs = &xs[..len];
- let ys = &ys[..len];
- for i in 0..len {
- let x = xs[i];
- let y = ys[i];
- black_box(x);
- black_box(y);
- }
- })
- });
- }
- fn zipdot_i32_checked_counted_loop(c: &mut Criterion) {
- let xs = vec![2; 1024];
- let ys = vec![2; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot i32 checked counted loop", move |b| {
- b.iter(|| {
- // Must slice to equal lengths, and then bounds checks are eliminated!
- let len = cmp::min(xs.len(), ys.len());
- let xs = &xs[..len];
- let ys = &ys[..len];
- let mut s = 0i32;
- for i in 0..len {
- s += xs[i] * ys[i];
- }
- s
- })
- });
- }
- fn zipdot_f32_checked_counted_loop(c: &mut Criterion) {
- let xs = vec![2f32; 1024];
- let ys = vec![2f32; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot f32 checked counted loop", move |b| {
- b.iter(|| {
- // Must slice to equal lengths, and then bounds checks are eliminated!
- let len = cmp::min(xs.len(), ys.len());
- let xs = &xs[..len];
- let ys = &ys[..len];
- let mut s = 0.;
- for i in 0..len {
- s += xs[i] * ys[i];
- }
- s
- })
- });
- }
- fn zipdot_f32_checked_counted_unrolled_loop(c: &mut Criterion) {
- let xs = vec![2f32; 1024];
- let ys = vec![2f32; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot f32 checked counted unrolled loop", move |b| {
- b.iter(|| {
- // Must slice to equal lengths, and then bounds checks are eliminated!
- let len = cmp::min(xs.len(), ys.len());
- let mut xs = &xs[..len];
- let mut ys = &ys[..len];
- let mut s = 0.;
- let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
- (0., 0., 0., 0., 0., 0., 0., 0.);
- // how to unroll and have bounds checks eliminated (by cristicbz)
- // split sum into eight parts to enable vectorization (by bluss)
- while xs.len() >= 8 {
- p0 += xs[0] * ys[0];
- p1 += xs[1] * ys[1];
- p2 += xs[2] * ys[2];
- p3 += xs[3] * ys[3];
- p4 += xs[4] * ys[4];
- p5 += xs[5] * ys[5];
- p6 += xs[6] * ys[6];
- p7 += xs[7] * ys[7];
- xs = &xs[8..];
- ys = &ys[8..];
- }
- s += p0 + p4;
- s += p1 + p5;
- s += p2 + p6;
- s += p3 + p7;
- for i in 0..xs.len() {
- s += xs[i] * ys[i];
- }
- s
- })
- });
- }
- fn zip_unchecked_counted_loop(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zip unchecked counted loop", move |b| {
- b.iter(|| {
- let len = cmp::min(xs.len(), ys.len());
- for i in 0..len {
- unsafe {
- let x = *xs.get_unchecked(i);
- let y = *ys.get_unchecked(i);
- black_box(x);
- black_box(y);
- }
- }
- })
- });
- }
- fn zipdot_i32_unchecked_counted_loop(c: &mut Criterion) {
- let xs = vec![2; 1024];
- let ys = vec![2; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot i32 unchecked counted loop", move |b| {
- b.iter(|| {
- let len = cmp::min(xs.len(), ys.len());
- let mut s = 0i32;
- for i in 0..len {
- unsafe {
- let x = *xs.get_unchecked(i);
- let y = *ys.get_unchecked(i);
- s += x * y;
- }
- }
- s
- })
- });
- }
- fn zipdot_f32_unchecked_counted_loop(c: &mut Criterion) {
- let xs = vec![2.; 1024];
- let ys = vec![2.; 768];
- let xs = black_box(xs);
- let ys = black_box(ys);
- c.bench_function("zipdot f32 unchecked counted loop", move |b| {
- b.iter(|| {
- let len = cmp::min(xs.len(), ys.len());
- let mut s = 0f32;
- for i in 0..len {
- unsafe {
- let x = *xs.get_unchecked(i);
- let y = *ys.get_unchecked(i);
- s += x * y;
- }
- }
- s
- })
- });
- }
- fn zip_unchecked_counted_loop3(c: &mut Criterion) {
- let xs = vec![0; 1024];
- let ys = vec![0; 768];
- let zs = vec![0; 766];
- let xs = black_box(xs);
- let ys = black_box(ys);
- let zs = black_box(zs);
- c.bench_function("zip unchecked counted loop3", move |b| {
- b.iter(|| {
- let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
- for i in 0..len {
- unsafe {
- let x = *xs.get_unchecked(i);
- let y = *ys.get_unchecked(i);
- let z = *zs.get_unchecked(i);
- black_box(x);
- black_box(y);
- black_box(z);
- }
- }
- })
- });
- }
- fn group_by_lazy_1(c: &mut Criterion) {
- let mut data = vec![0; 1024];
- for (index, elt) in data.iter_mut().enumerate() {
- *elt = index / 10;
- }
- let data = black_box(data);
- c.bench_function("group by lazy 1", move |b| {
- b.iter(|| {
- for (_key, group) in &data.iter().group_by(|elt| **elt) {
- for elt in group {
- black_box(elt);
- }
- }
- })
- });
- }
- fn group_by_lazy_2(c: &mut Criterion) {
- let mut data = vec![0; 1024];
- for (index, elt) in data.iter_mut().enumerate() {
- *elt = index / 2;
- }
- let data = black_box(data);
- c.bench_function("group by lazy 2", move |b| {
- b.iter(|| {
- for (_key, group) in &data.iter().group_by(|elt| **elt) {
- for elt in group {
- black_box(elt);
- }
- }
- })
- });
- }
- fn slice_chunks(c: &mut Criterion) {
- let data = vec![0; 1024];
- let data = black_box(data);
- let sz = black_box(10);
- c.bench_function("slice chunks", move |b| {
- b.iter(|| {
- for group in data.chunks(sz) {
- for elt in group {
- black_box(elt);
- }
- }
- })
- });
- }
- fn chunks_lazy_1(c: &mut Criterion) {
- let data = vec![0; 1024];
- let data = black_box(data);
- let sz = black_box(10);
- c.bench_function("chunks lazy 1", move |b| {
- b.iter(|| {
- for group in &data.iter().chunks(sz) {
- for elt in group {
- black_box(elt);
- }
- }
- })
- });
- }
- fn equal(c: &mut Criterion) {
- let data = vec![7; 1024];
- let l = data.len();
- let alpha = black_box(&data[1..]);
- let beta = black_box(&data[..l - 1]);
- c.bench_function("equal", move |b| {
- b.iter(|| {
- itertools::equal(alpha, beta)
- })
- });
- }
- fn merge_default(c: &mut Criterion) {
- let mut data1 = vec![0; 1024];
- let mut data2 = vec![0; 800];
- let mut x = 0;
- for (_, elt) in data1.iter_mut().enumerate() {
- *elt = x;
- x += 1;
- }
- let mut y = 0;
- for (i, elt) in data2.iter_mut().enumerate() {
- *elt += y;
- if i % 3 == 0 {
- y += 3;
- } else {
- y += 0;
- }
- }
- let data1 = black_box(data1);
- let data2 = black_box(data2);
- c.bench_function("merge default", move |b| {
- b.iter(|| {
- data1.iter().merge(&data2).count()
- })
- });
- }
- fn merge_by_cmp(c: &mut Criterion) {
- let mut data1 = vec![0; 1024];
- let mut data2 = vec![0; 800];
- let mut x = 0;
- for (_, elt) in data1.iter_mut().enumerate() {
- *elt = x;
- x += 1;
- }
- let mut y = 0;
- for (i, elt) in data2.iter_mut().enumerate() {
- *elt += y;
- if i % 3 == 0 {
- y += 3;
- } else {
- y += 0;
- }
- }
- let data1 = black_box(data1);
- let data2 = black_box(data2);
- c.bench_function("merge by cmp", move |b| {
- b.iter(|| {
- data1.iter().merge_by(&data2, PartialOrd::le).count()
- })
- });
- }
- fn merge_by_lt(c: &mut Criterion) {
- let mut data1 = vec![0; 1024];
- let mut data2 = vec![0; 800];
- let mut x = 0;
- for (_, elt) in data1.iter_mut().enumerate() {
- *elt = x;
- x += 1;
- }
- let mut y = 0;
- for (i, elt) in data2.iter_mut().enumerate() {
- *elt += y;
- if i % 3 == 0 {
- y += 3;
- } else {
- y += 0;
- }
- }
- let data1 = black_box(data1);
- let data2 = black_box(data2);
- c.bench_function("merge by lt", move |b| {
- b.iter(|| {
- data1.iter().merge_by(&data2, |a, b| a <= b).count()
- })
- });
- }
- fn kmerge_default(c: &mut Criterion) {
- let mut data1 = vec![0; 1024];
- let mut data2 = vec![0; 800];
- let mut x = 0;
- for (_, elt) in data1.iter_mut().enumerate() {
- *elt = x;
- x += 1;
- }
- let mut y = 0;
- for (i, elt) in data2.iter_mut().enumerate() {
- *elt += y;
- if i % 3 == 0 {
- y += 3;
- } else {
- y += 0;
- }
- }
- let data1 = black_box(data1);
- let data2 = black_box(data2);
- let its = &[data1.iter(), data2.iter()];
- c.bench_function("kmerge default", move |b| {
- b.iter(|| {
- its.iter().cloned().kmerge().count()
- })
- });
- }
- fn kmerge_tenway(c: &mut Criterion) {
- let mut data = vec![0; 10240];
- let mut state = 1729u16;
- fn rng(state: &mut u16) -> u16 {
- let new = state.wrapping_mul(31421) + 6927;
- *state = new;
- new
- }
- for elt in &mut data {
- *elt = rng(&mut state);
- }
- let mut chunks = Vec::new();
- let mut rest = &mut data[..];
- while rest.len() > 0 {
- let chunk_len = 1 + rng(&mut state) % 512;
- let chunk_len = cmp::min(rest.len(), chunk_len as usize);
- let (fst, tail) = {rest}.split_at_mut(chunk_len);
- fst.sort();
- chunks.push(fst.iter().cloned());
- rest = tail;
- }
- // println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len())));
- c.bench_function("kmerge tenway", move |b| {
- b.iter(|| {
- chunks.iter().cloned().kmerge().count()
- })
- });
- }
- fn fast_integer_sum<I>(iter: I) -> I::Item
- where I: IntoIterator,
- I::Item: Default + Add<Output=I::Item>
- {
- iter.into_iter().fold(<_>::default(), |x, y| x + y)
- }
- fn step_vec_2(c: &mut Criterion) {
- let v = vec![0; 1024];
- c.bench_function("step vec 2", move |b| {
- b.iter(|| {
- fast_integer_sum(cloned(v.iter().step_by(2)))
- })
- });
- }
- fn step_vec_10(c: &mut Criterion) {
- let v = vec![0; 1024];
- c.bench_function("step vec 10", move |b| {
- b.iter(|| {
- fast_integer_sum(cloned(v.iter().step_by(10)))
- })
- });
- }
- fn step_range_2(c: &mut Criterion) {
- let v = black_box(0..1024);
- c.bench_function("step range 2", move |b| {
- b.iter(|| {
- fast_integer_sum(v.clone().step_by(2))
- })
- });
- }
- fn step_range_10(c: &mut Criterion) {
- let v = black_box(0..1024);
- c.bench_function("step range 10", move |b| {
- b.iter(|| {
- fast_integer_sum(v.clone().step_by(10))
- })
- });
- }
- fn cartesian_product_iterator(c: &mut Criterion) {
- let xs = vec![0; 16];
- c.bench_function("cartesian product iterator", move |b| {
- b.iter(|| {
- let mut sum = 0;
- for (&x, &y, &z) in iproduct!(&xs, &xs, &xs) {
- sum += x;
- sum += y;
- sum += z;
- }
- sum
- })
- });
- }
- fn cartesian_product_fold(c: &mut Criterion) {
- let xs = vec![0; 16];
- c.bench_function("cartesian product fold", move |b| {
- b.iter(|| {
- let mut sum = 0;
- iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| {
- sum += x;
- sum += y;
- sum += z;
- });
- sum
- })
- });
- }
- fn multi_cartesian_product_iterator(c: &mut Criterion) {
- let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
- c.bench_function("multi cartesian product iterator", move |b| {
- b.iter(|| {
- let mut sum = 0;
- for x in xs.iter().multi_cartesian_product() {
- sum += x[0];
- sum += x[1];
- sum += x[2];
- }
- sum
- })
- });
- }
- fn multi_cartesian_product_fold(c: &mut Criterion) {
- let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
- c.bench_function("multi cartesian product fold", move |b| {
- b.iter(|| {
- let mut sum = 0;
- xs.iter().multi_cartesian_product().fold((), |(), x| {
- sum += x[0];
- sum += x[1];
- sum += x[2];
- });
- sum
- })
- });
- }
- fn cartesian_product_nested_for(c: &mut Criterion) {
- let xs = vec![0; 16];
- c.bench_function("cartesian product nested for", move |b| {
- b.iter(|| {
- let mut sum = 0;
- for &x in &xs {
- for &y in &xs {
- for &z in &xs {
- sum += x;
- sum += y;
- sum += z;
- }
- }
- }
- sum
- })
- });
- }
- fn all_equal(c: &mut Criterion) {
- let mut xs = vec![0; 5_000_000];
- xs.extend(vec![1; 5_000_000]);
- c.bench_function("all equal", move |b| {
- b.iter(|| xs.iter().all_equal())
- });
- }
- fn all_equal_for(c: &mut Criterion) {
- let mut xs = vec![0; 5_000_000];
- xs.extend(vec![1; 5_000_000]);
- c.bench_function("all equal for", move |b| {
- b.iter(|| {
- for &x in &xs {
- if x != xs[0] {
- return false;
- }
- }
- true
- })
- });
- }
- fn all_equal_default(c: &mut Criterion) {
- let mut xs = vec![0; 5_000_000];
- xs.extend(vec![1; 5_000_000]);
- c.bench_function("all equal default", move |b| {
- b.iter(|| xs.iter().dedup().nth(1).is_none())
- });
- }
- const PERM_COUNT: usize = 6;
- fn permutations_iter(c: &mut Criterion) {
- struct NewIterator(Range<usize>);
- impl Iterator for NewIterator {
- type Item = usize;
- fn next(&mut self) -> Option<Self::Item> {
- self.0.next()
- }
- }
- c.bench_function("permutations iter", move |b| {
- b.iter(|| {
- for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) {
- }
- })
- });
- }
- fn permutations_range(c: &mut Criterion) {
- c.bench_function("permutations range", move |b| {
- b.iter(|| {
- for _ in (0..PERM_COUNT).permutations(PERM_COUNT) {
- }
- })
- });
- }
- fn permutations_slice(c: &mut Criterion) {
- let v = (0..PERM_COUNT).collect_vec();
- c.bench_function("permutations slice", move |b| {
- b.iter(|| {
- for _ in v.as_slice().iter().permutations(PERM_COUNT) {
- }
- })
- });
- }
- criterion_group!(
- benches,
- slice_iter,
- slice_iter_rev,
- zip_default_zip,
- zipdot_i32_default_zip,
- zipdot_f32_default_zip,
- zip_default_zip3,
- zip_slices_ziptuple,
- zipslices,
- zipslices_mut,
- zipdot_i32_zipslices,
- zipdot_f32_zipslices,
- zip_checked_counted_loop,
- zipdot_i32_checked_counted_loop,
- zipdot_f32_checked_counted_loop,
- zipdot_f32_checked_counted_unrolled_loop,
- zip_unchecked_counted_loop,
- zipdot_i32_unchecked_counted_loop,
- zipdot_f32_unchecked_counted_loop,
- zip_unchecked_counted_loop3,
- group_by_lazy_1,
- group_by_lazy_2,
- slice_chunks,
- chunks_lazy_1,
- equal,
- merge_default,
- merge_by_cmp,
- merge_by_lt,
- kmerge_default,
- kmerge_tenway,
- step_vec_2,
- step_vec_10,
- step_range_2,
- step_range_10,
- cartesian_product_iterator,
- cartesian_product_fold,
- multi_cartesian_product_iterator,
- multi_cartesian_product_fold,
- cartesian_product_nested_for,
- all_equal,
- all_equal_for,
- all_equal_default,
- permutations_iter,
- permutations_range,
- permutations_slice,
- );
- criterion_main!(benches);
|