Skip to content

Commit

Permalink
find benchmark with blocks
Browse files Browse the repository at this point in the history
we could win big by adding more operations.
it is super nice to have the sequential iterator on all reduced values
of blocks.
we could then use the dumb_find on each block and use the sequential
find to find the first value.

this would be the best algorithm.

sadly we can't have it due to rayon's types encapsulation.
the next best thing would be a
try_fold_by_exponential_blocks method
it would take a closure on Self producing the reduced values
and a closure for the sequential try_fold
  • Loading branch information
frederic wagner committed Mar 30, 2021
1 parent d993b0b commit ddaf678
Showing 1 changed file with 190 additions and 9 deletions.
199 changes: 190 additions & 9 deletions rayon-demo/src/find/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// Simple benchmarks of `find_any()` performance
/// Simple benchmarks of `find_any()` and `find_first` performance

macro_rules! make_tests {
($n:expr, $m:ident) => {
Expand All @@ -22,56 +22,237 @@ macro_rules! make_tests {
};
}

// this is a very dumb find_first algorithm.
// no early aborts so we have a linear best case cost.
fn find_dumb<I: ParallelIterator, P: Fn(&I::Item) -> bool + Send + Sync>(
iter: I,
cond: P,
) -> Option<I::Item> {
iter.map(|e| if cond(&e) { Some(e) } else { None })
.reduce(|| None, |left, right| left.or(right))
}

#[bench]
fn parallel_find_any_start(b: &mut Bencher) {
let needle = HAYSTACK[0][0];
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_first(b: &mut Bencher) {
fn parallel_find_first_start(b: &mut Bencher) {
let needle = HAYSTACK[0][0];
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn serial_find_first(b: &mut Bencher) {
fn parallel_find_first_blocks_start(b: &mut Bencher) {
let needle = HAYSTACK[0][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.by_exponential_blocks()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn serial_find_start(b: &mut Bencher) {
let needle = HAYSTACK[0][0];
b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_last(b: &mut Bencher) {
fn parallel_find_any_end(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() - 1][0];
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_some()));
}
#[bench]
fn parallel_find_first_end(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() - 1][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}
#[bench]
fn parallel_find_first_blocks_end(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() - 1][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.by_exponential_blocks()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn serial_find_last(b: &mut Bencher) {
fn serial_find_end(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() - 1][0];
b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_middle(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
fn parallel_find_any_third(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3][0];
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_first_third(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn parallel_find_dumb_third(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3][0];
b.iter(
|| assert!(find_dumb(HAYSTACK.par_iter(), (|&&x| x[0] == needle)).is_some()),
);
}

#[bench]
fn parallel_find_first_blocks_third(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.by_exponential_blocks()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn serial_find_third(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3][0];
b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_any_middle(b: &mut Bencher) {
let needle = HAYSTACK[(HAYSTACK.len() / 2).saturating_sub(1)][0];
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_first_middle(b: &mut Bencher) {
let needle = HAYSTACK[(HAYSTACK.len() / 2).saturating_sub(1)][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn parallel_find_dumb_middle(b: &mut Bencher) {
let needle = HAYSTACK[(HAYSTACK.len() / 2).saturating_sub(1)][0];
b.iter(
|| assert!(find_dumb(HAYSTACK.par_iter(), (|&&x| x[0] == needle)).is_some()),
);
}

#[bench]
fn parallel_find_first_blocks_middle(b: &mut Bencher) {
let needle = HAYSTACK[(HAYSTACK.len() / 2).saturating_sub(1)][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.by_exponential_blocks()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn serial_find_middle(b: &mut Bencher) {
let needle = HAYSTACK[(HAYSTACK.len() / 2).saturating_sub(1)][0];
b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_any_two_thirds(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_first_two_thirds(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn parallel_find_first_blocks_two_thirds(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.by_exponential_blocks()
.find_first(|&&x| x[0] == needle)
.is_some())
});
}

#[bench]
fn serial_find_two_thirds(b: &mut Bencher) {
let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
}

#[bench]
fn parallel_find_missing(b: &mut Bencher) {
fn parallel_find_any_missing(b: &mut Bencher) {
let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
b.iter(|| assert!(HAYSTACK.par_iter().find_any(|&&x| x[0] == needle).is_none()));
}

#[bench]
fn parallel_find_first_missing(b: &mut Bencher) {
let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.find_first(|&&x| x[0] == needle)
.is_none())
});
}

#[bench]
fn parallel_find_first_blocks_missing(b: &mut Bencher) {
let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
b.iter(|| {
assert!(HAYSTACK
.par_iter()
.by_exponential_blocks()
.find_first(|&&x| x[0] == needle)
.is_none())
});
}

#[bench]
fn serial_find_missing(b: &mut Bencher) {
let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_none()));
}

#[bench]
fn parallel_find_common(b: &mut Bencher) {
fn parallel_find_any_common(b: &mut Bencher) {
b.iter(|| {
assert!(HAYSTACK
.par_iter()
Expand Down

0 comments on commit ddaf678

Please sign in to comment.