Factored benchmarks apart in a reasonable way.
This commit is contained in:
parent
227e2c548e
commit
fa353df41a
66
Cargo.toml
66
Cargo.toml
@ -5,9 +5,69 @@ authors = ["Donald S. Black <trurl@freeshell.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[dev_dependencies]
|
||||
criterion = "0.1.2"
|
||||
rand = "0.3"
|
||||
rand = "0.6.1"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
benchmark-definitions = ["criterion", "rand", "num-bigint"]
|
||||
|
||||
# Build with "cargo bench --features=benchmark-definitions".
|
||||
[profile.bench]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
rpath = false
|
||||
debug-assertions = false
|
||||
lto = true
|
||||
|
||||
[dependencies.criterion]
|
||||
version = "0.2.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.6.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.num-bigint]
|
||||
version = "0.2.2"
|
||||
optional = true
|
||||
features = ["rand"]
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
name = "tiny-i32-sort-binary"
|
||||
path = "benches/tiny_i32_sort_binary.rs"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tiny-i32-sort-weak"
|
||||
path = "benches/tiny_i32_sort_weak.rs"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tiny-i128-sort-binary"
|
||||
path = "benches/tiny_i128_sort_binary.rs"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tiny-i128-sort-weak"
|
||||
path = "benches/tiny_i128_sort_weak.rs"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tiny-u32768-sort-binary"
|
||||
path = "benches/tiny_u32768_sort_binary.rs"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tiny-u32768-sort-weak"
|
||||
path = "benches/tiny_u32768_sort_weak.rs"
|
||||
harness = false
|
||||
|
||||
# [[bench]]
|
||||
# name = "small"
|
||||
# path = "benches/small.rs"
|
||||
# harness = false
|
||||
|
||||
# [[bench]]
|
||||
# name = "medium"
|
||||
# path = "benches/medium.rs"
|
||||
# harness = false
|
||||
|
373
benches/bench.rs
373
benches/bench.rs
@ -1,373 +0,0 @@
|
||||
#[macro_use] extern crate criterion;
|
||||
extern crate rand;
|
||||
extern crate weak_heap;
|
||||
|
||||
use criterion::Criterion;
|
||||
use rand::{Rng, SeedableRng, StdRng};
|
||||
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::collections::{BinaryHeap, HashMap};
|
||||
use std::mem;
|
||||
use std::ops::Add;
|
||||
use std::sync::atomic;
|
||||
use weak_heap::WeakHeap;
|
||||
|
||||
static TINY_SIZES: &[usize] = &[1, 2, 7, 8, 9, 10, 20, 30, 31, 32, 33];
|
||||
// static SMALL_SIZES: &[usize] = &[100, 127, 128, 129, 150, 200, 254, 255, 256, 257, 258];
|
||||
// static MEDIUM_SIZES: &[usize] = &[10000, 20000, 32767, 32768, 32769, 50000];
|
||||
// static LARGE_SIZES: &[usize] = &[1048575, 1048576, 1048577];
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct ComparisonCountedI32(i32);
|
||||
|
||||
static PARTIAL_ORD_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
impl PartialOrd for ComparisonCountedI32 {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
PARTIAL_ORD_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
static ORD_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
impl Ord for ComparisonCountedI32 {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
ORD_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
static PARTIAL_EQ_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
static PARTIAL_NEQ_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
impl PartialEq for ComparisonCountedI32 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
PARTIAL_EQ_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.eq(&other.0)
|
||||
}
|
||||
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
PARTIAL_NEQ_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.ne(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ComparisonCountedI32 {}
|
||||
|
||||
impl From<i32> for ComparisonCountedI32 {
|
||||
fn from(x: i32) -> Self {
|
||||
ComparisonCountedI32(x)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
|
||||
struct ComparisonCounts {
|
||||
partial_ord: usize,
|
||||
ord: usize,
|
||||
eq: usize,
|
||||
neq: usize,
|
||||
}
|
||||
|
||||
impl ComparisonCounts {
|
||||
fn now() -> Self {
|
||||
ComparisonCounts {
|
||||
partial_ord: PARTIAL_ORD_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
ord: ORD_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
eq: PARTIAL_EQ_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
neq: PARTIAL_NEQ_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
}
|
||||
}
|
||||
|
||||
fn take_difference(&mut self) {
|
||||
let mut now = ComparisonCounts::now();
|
||||
assert!(now.partial_ord >= self.partial_ord);
|
||||
now.partial_ord -= self.partial_ord;
|
||||
assert!(now.ord >= self.ord);
|
||||
now.ord -= self.ord;
|
||||
assert!(now.eq >= self.eq);
|
||||
now.eq -= self.eq;
|
||||
assert!(now.neq >= self.neq);
|
||||
now.neq -= self.neq;
|
||||
mem::swap(&mut now, self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for ComparisonCounts {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
ComparisonCounts {
|
||||
partial_ord: self.partial_ord + rhs.partial_ord,
|
||||
ord: self.ord + rhs.ord,
|
||||
eq: self.eq + rhs.eq,
|
||||
neq: self.neq + rhs.neq,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_values(size: usize) -> Vec<i32> {
|
||||
let seed: &[_] = &[1, 2, 3, 4];
|
||||
let mut rng: StdRng = SeedableRng::from_seed(seed);
|
||||
(0..size).map(|_| rng.gen::<i32>()).map(|x| x.into()).collect()
|
||||
}
|
||||
|
||||
macro_rules! do_bench {
|
||||
($bencher: ident, $heap_factory: expr, $sizes: ident) => ({
|
||||
let sizes = $sizes;
|
||||
let mut all_values = HashMap::new();
|
||||
let mut all_sorted = HashMap::new();
|
||||
for size in sizes {
|
||||
let values: Vec<ComparisonCountedI32> =
|
||||
get_values(*size).into_iter().map(|x| x.into()).collect();
|
||||
let sorted = {
|
||||
let mut v = values.clone();
|
||||
v.sort_by(|x, y| y.cmp(x));
|
||||
v
|
||||
};
|
||||
all_values.insert(*size, values);
|
||||
all_sorted.insert(*size, sorted);
|
||||
}
|
||||
|
||||
$bencher.bench_function_over_inputs(
|
||||
&format!("sort {}", stringify!($heap_factory)),
|
||||
|b: &mut criterion::Bencher, &&size: &&usize| {
|
||||
let mut all_counts = Vec::new();
|
||||
let mut iterations = 0;
|
||||
let values = all_values.get(&size).unwrap();
|
||||
let sorted = all_sorted.get(&size).unwrap();
|
||||
b.iter(|| {
|
||||
iterations += 1;
|
||||
let mut counts = ComparisonCounts::now();
|
||||
let mut heap = $heap_factory();
|
||||
for v in values {
|
||||
heap.push(*v);
|
||||
}
|
||||
let mut heap_sorted = Vec::with_capacity(heap.len());
|
||||
while let Some(x) = heap.pop() {
|
||||
heap_sorted.push(x);
|
||||
}
|
||||
counts.take_difference();
|
||||
all_counts.push(counts);
|
||||
assert_eq!(heap_sorted, *sorted);
|
||||
});
|
||||
let total_counts = all_counts.into_iter().fold(
|
||||
ComparisonCounts::default(), |acc, x| acc + x);
|
||||
// println!("\ndo_bench({}, {}) partial_ord {:.2}, ord {:.2}, eq {:.2}, ne {:.2}",
|
||||
// stringify!($heap_factory), size,
|
||||
// (total_counts.partial_ord as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.ord as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.eq as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.neq as f32) / ((size * iterations) as f32));
|
||||
}, sizes);
|
||||
})
|
||||
}
|
||||
|
||||
fn bench_tiny(c: &mut Criterion) {
|
||||
do_bench!(c, BinaryHeap::new, TINY_SIZES);
|
||||
do_bench!(c, WeakHeap::new, TINY_SIZES);
|
||||
}
|
||||
|
||||
// macro_rules! do_bench_inserts {
|
||||
// ($bencher: ident, $heap_factory: expr, $size: expr) => ({
|
||||
// let size: usize = $size;
|
||||
// let values: Vec<ComparisonCountedI32> =
|
||||
// get_values(size).into_iter().map(|x| x.into()).collect();
|
||||
|
||||
// let mut all_counts = Vec::new();
|
||||
// let mut iterations = 0;
|
||||
// $bencher.iter(|| {
|
||||
// iterations += 1;
|
||||
// let mut counts = ComparisonCounts::now();
|
||||
// let mut heap = $heap_factory();
|
||||
// for v in &values {
|
||||
// heap.push(*v);
|
||||
// }
|
||||
// counts.take_difference();
|
||||
// all_counts.push(counts);
|
||||
// });
|
||||
// let total_counts = all_counts.into_iter().fold(
|
||||
// ComparisonCounts::default(), |acc, x| acc + x);
|
||||
// println!("\ndo_bench_inserts({}, {}) partial_ord {:.2}, ord {:.2}, eq {:.2}, ne {:.2}",
|
||||
// stringify!($heap_factory), size,
|
||||
// (total_counts.partial_ord as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.ord as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.eq as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.neq as f32) / ((size * iterations) as f32));
|
||||
// total_counts
|
||||
// })
|
||||
// }
|
||||
|
||||
// macro_rules! do_bench_removals {
|
||||
// ($bencher: ident, $heap_factory: expr, $size: expr) => ({
|
||||
// let size: usize = $size;
|
||||
// let values: Vec<ComparisonCountedI32> =
|
||||
// get_values(size).into_iter().map(|x| x.into()).collect();
|
||||
// let sorted = {
|
||||
// let mut v = values.clone();
|
||||
// v.sort_by(|x, y| y.cmp(x));
|
||||
// v
|
||||
// };
|
||||
|
||||
// let mut all_counts = Vec::new();
|
||||
// let mut iterations = 0;
|
||||
// $bencher.iter(|| {
|
||||
// iterations += 1;
|
||||
// let mut heap = $heap_factory();
|
||||
// for v in &values {
|
||||
// heap.push(*v);
|
||||
// }
|
||||
// let mut receptacle = Vec::with_capacity(size);
|
||||
// let mut counts = ComparisonCounts::now();
|
||||
// while let Some(x) = heap.pop() {
|
||||
// receptacle.push(x);
|
||||
// }
|
||||
// counts.take_difference();
|
||||
// assert_eq!(receptacle, sorted);
|
||||
// all_counts.push(counts);
|
||||
// });
|
||||
// let total_counts = all_counts.into_iter().fold(
|
||||
// ComparisonCounts::default(), |acc, x| acc + x);
|
||||
// println!("\ndo_bench_removals({}, {}) partial_ord {:.2}, ord {:.2}, eq {:.2}, ne {:.2}",
|
||||
// stringify!($heap_factory), size,
|
||||
// (total_counts.partial_ord as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.ord as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.eq as f32) / ((size * iterations) as f32),
|
||||
// (total_counts.neq as f32) / ((size * iterations) as f32));
|
||||
// total_counts
|
||||
// })
|
||||
// }
|
||||
|
||||
// fn bench_01_weak_small(c: &mut Criterion) {
|
||||
// // for size in SMALL_SIZES {
|
||||
// do_bench!(c, WeakHeap::new, 128);
|
||||
// // }
|
||||
// }
|
||||
|
||||
// fn bench_02_weak_medium(c: &mut Criterion) {
|
||||
// // for size in MEDIUM_SIZES {
|
||||
// do_bench!(c, WeakHeap::new, 32768);
|
||||
// // }
|
||||
// }
|
||||
|
||||
// fn bench_03_weak_large(c: &mut Criterion) {
|
||||
// // for size in LARGE_SIZES {
|
||||
// do_bench!(c, WeakHeap::new, 1048576);
|
||||
// // }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_00_weak_tiny(c: &mut Criterion) {
|
||||
// for size in TINY_SIZES {
|
||||
// do_bench_inserts!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_01_weak_small(c: &mut Criterion) {
|
||||
// for size in SMALL_SIZES {
|
||||
// do_bench_inserts!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_02_weak_medium(c: &mut Criterion) {
|
||||
// for size in MEDIUM_SIZES {
|
||||
// do_bench_inserts!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_03_weak_large(c: &mut Criterion) {
|
||||
// for size in LARGE_SIZES {
|
||||
// do_bench_inserts!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_00_weak_tiny(c: &mut Criterion) {
|
||||
// for size in TINY_SIZES {
|
||||
// do_bench_removals!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_01_weak_small(c: &mut Criterion) {
|
||||
// for size in SMALL_SIZES {
|
||||
// do_bench_removals!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_02_weak_medium(c: &mut Criterion) {
|
||||
// for size in MEDIUM_SIZES {
|
||||
// do_bench_removals!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_03_weak_large(c: &mut Criterion) {
|
||||
// for size in LARGE_SIZES {
|
||||
// do_bench_removals!(c, WeakHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_01_builtin_small(c: &mut Criterion) {
|
||||
// // for size in SMALL_SIZES {
|
||||
// do_bench!(c, BinaryHeap::new, 128);
|
||||
// // }
|
||||
// }
|
||||
|
||||
// fn bench_02_builtin_medium(c: &mut Criterion) {
|
||||
// // for size in MEDIUM_SIZES {
|
||||
// do_bench!(c, BinaryHeap::new, 32768);
|
||||
// // }
|
||||
// }
|
||||
|
||||
// fn bench_03_builtin_large(c: &mut Criterion) {
|
||||
// // for size in LARGE_SIZES {
|
||||
// do_bench!(c, BinaryHeap::new, 1048576);
|
||||
// // }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_00_binary_tiny(c: &mut Criterion) {
|
||||
// for size in TINY_SIZES {
|
||||
// do_bench_inserts!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_01_binary_small(c: &mut Criterion) {
|
||||
// for size in SMALL_SIZES {
|
||||
// do_bench_inserts!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_02_binary_medium(c: &mut Criterion) {
|
||||
// for size in MEDIUM_SIZES {
|
||||
// do_bench_inserts!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_inserts_03_builtin_large(c: &mut Criterion) {
|
||||
// for size in LARGE_SIZES {
|
||||
// do_bench_inserts!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_00_binary_tiny(c: &mut Criterion) {
|
||||
// for size in TINY_SIZES {
|
||||
// do_bench_removals!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_01_binary_small(c: &mut Criterion) {
|
||||
// for size in SMALL_SIZES {
|
||||
// do_bench_removals!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_02_binary_medium(c: &mut Criterion) {
|
||||
// for size in MEDIUM_SIZES {
|
||||
// do_bench_removals!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn bench_removals_03_builtin_large(c: &mut Criterion) {
|
||||
// for size in LARGE_SIZES {
|
||||
// do_bench_removals!(c, BinaryHeap::new, *size);
|
||||
// }
|
||||
// }
|
||||
|
||||
criterion_group!(tiny, bench_tiny);
|
||||
// criterion_group!(small, bench_01_builtin_small, bench_01_weak_small);
|
||||
// criterion_group!(medium, bench_02_builtin_medium, bench_02_weak_medium);
|
||||
// criterion_group!(large, bench_03_builtin_large, bench_03_weak_large);
|
||||
criterion_main!(tiny);
|
4
benches/tiny_i128_sort_binary.rs
Normal file
4
benches/tiny_i128_sort_binary.rs
Normal file
@ -0,0 +1,4 @@
|
||||
use criterion::criterion_main;
|
||||
use weak_heap::benches::tiny;
|
||||
|
||||
criterion_main!(tiny::i128_sort_binary);
|
4
benches/tiny_i128_sort_weak.rs
Normal file
4
benches/tiny_i128_sort_weak.rs
Normal file
@ -0,0 +1,4 @@
|
||||
use criterion::criterion_main;
|
||||
use weak_heap::benches::tiny;
|
||||
|
||||
criterion_main!(tiny::i128_sort_weak);
|
4
benches/tiny_i32_sort_binary.rs
Normal file
4
benches/tiny_i32_sort_binary.rs
Normal file
@ -0,0 +1,4 @@
|
||||
use criterion::criterion_main;
|
||||
use weak_heap::benches::tiny;
|
||||
|
||||
criterion_main!(tiny::i32_sort_binary);
|
4
benches/tiny_i32_sort_weak.rs
Normal file
4
benches/tiny_i32_sort_weak.rs
Normal file
@ -0,0 +1,4 @@
|
||||
use criterion::criterion_main;
|
||||
use weak_heap::benches::tiny;
|
||||
|
||||
criterion_main!(tiny::i32_sort_weak);
|
4
benches/tiny_u32768_sort_binary.rs
Normal file
4
benches/tiny_u32768_sort_binary.rs
Normal file
@ -0,0 +1,4 @@
|
||||
use criterion::criterion_main;
|
||||
use weak_heap::benches::tiny;
|
||||
|
||||
criterion_main!(tiny::u32768_sort_binary);
|
4
benches/tiny_u32768_sort_weak.rs
Normal file
4
benches/tiny_u32768_sort_weak.rs
Normal file
@ -0,0 +1,4 @@
|
||||
use criterion::criterion_main;
|
||||
use weak_heap::benches::tiny;
|
||||
|
||||
criterion_main!(tiny::u32768_sort_weak);
|
259
src/benches.rs
Normal file
259
src/benches.rs
Normal file
@ -0,0 +1,259 @@
|
||||
use num_bigint::{BigUint, ToBigUint};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::distributions::Standard;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::distributions::Distribution;
|
||||
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::mem;
|
||||
use std::ops::Add;
|
||||
use std::sync::atomic;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ComparisonCountedI32(i32);
|
||||
|
||||
static PARTIAL_ORD_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
impl PartialOrd for ComparisonCountedI32 {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
PARTIAL_ORD_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
static ORD_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
impl Ord for ComparisonCountedI32 {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
ORD_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
static PARTIAL_EQ_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
static PARTIAL_NEQ_COMPARISON_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
impl PartialEq for ComparisonCountedI32 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
PARTIAL_EQ_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.eq(&other.0)
|
||||
}
|
||||
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
PARTIAL_NEQ_COMPARISON_COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.0.ne(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ComparisonCountedI32 {}
|
||||
|
||||
impl From<i32> for ComparisonCountedI32 {
|
||||
fn from(x: i32) -> Self {
|
||||
ComparisonCountedI32(x)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StandardComparisonCountedI32Distribution {}
|
||||
|
||||
impl Distribution<ComparisonCountedI32> for StandardComparisonCountedI32Distribution {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ComparisonCountedI32 {
|
||||
return rng.sample::<i32, rand::distributions::Standard>(rand::distributions::Standard).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ComparisonCounts {
|
||||
pub partial_ord: usize,
|
||||
pub ord: usize,
|
||||
pub eq: usize,
|
||||
pub neq: usize,
|
||||
}
|
||||
|
||||
impl ComparisonCounts {
|
||||
pub fn now() -> Self {
|
||||
ComparisonCounts {
|
||||
partial_ord: PARTIAL_ORD_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
ord: ORD_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
eq: PARTIAL_EQ_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
neq: PARTIAL_NEQ_COMPARISON_COUNTER.load(atomic::Ordering::SeqCst),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_difference(&mut self) {
|
||||
let mut now = ComparisonCounts::now();
|
||||
assert!(now.partial_ord >= self.partial_ord);
|
||||
now.partial_ord -= self.partial_ord;
|
||||
assert!(now.ord >= self.ord);
|
||||
now.ord -= self.ord;
|
||||
assert!(now.eq >= self.eq);
|
||||
now.eq -= self.eq;
|
||||
assert!(now.neq >= self.neq);
|
||||
now.neq -= self.neq;
|
||||
mem::swap(&mut now, self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for ComparisonCounts {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
ComparisonCounts {
|
||||
partial_ord: self.partial_ord + rhs.partial_ord,
|
||||
ord: self.ord + rhs.ord,
|
||||
eq: self.eq + rhs.eq,
|
||||
neq: self.neq + rhs.neq,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasDistribution: Sized {
|
||||
type Dist: rand::distributions::Distribution<Self>;
|
||||
|
||||
fn distribution() -> Self::Dist;
|
||||
}
|
||||
|
||||
impl HasDistribution for i32 {
|
||||
type Dist = Standard;
|
||||
|
||||
fn distribution() -> Standard { Standard }
|
||||
}
|
||||
|
||||
impl HasDistribution for i128 {
|
||||
type Dist = Standard;
|
||||
|
||||
fn distribution() -> Standard { Standard }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct U32768 {
|
||||
value: BigUint,
|
||||
}
|
||||
|
||||
pub struct U32768Distribution {}
|
||||
|
||||
impl rand::distributions::Distribution<U32768> for U32768Distribution {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> U32768 {
|
||||
let mut result = BigUint::default();
|
||||
for _ in 0..256 {
|
||||
result <<= 128;
|
||||
result += rng.sample::<u128, Standard>(Standard).to_biguint().unwrap();
|
||||
}
|
||||
U32768 { value: result, }
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDistribution for U32768 {
|
||||
type Dist = U32768Distribution;
|
||||
|
||||
fn distribution() -> U32768Distribution { U32768Distribution{} }
|
||||
}
|
||||
|
||||
/// Returns a sequence of `size` elements generated deterministically from an
|
||||
/// RNG with a fixed seed.
|
||||
pub fn get_values<T: HasDistribution>(size: usize) -> Vec<T> {
|
||||
let seed: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31];
|
||||
let mut rng: StdRng = SeedableRng::from_seed(seed);
|
||||
rng.sample_iter(&T::distribution()).take(size).collect()
|
||||
}
|
||||
|
||||
// /// Runs benchmarks over sequences of size `$sizes`. For example:
|
||||
// ///
|
||||
// /// ```rust,noexec
|
||||
// /// fn bench_something(c: &mut Criterion) {
|
||||
// /// do_comparison_counted_i32_bench!(c, WeakHeap::new, 1..127);
|
||||
// /// }
|
||||
// /// ```
|
||||
// ///
|
||||
// /// Benchmarks will be run using a customized version of `i32` that counts the
|
||||
// /// number of comparison operations performed.
|
||||
// #[macro_export]
|
||||
// macro_rules! do_comparison_counted_i32_bench {
|
||||
// ($bencher: ident, $heap_factory: expr, $sizes: expr) => ({
|
||||
// use $crate::benches::{ComparisonCountedI32/*, ComparisonCounts*/};
|
||||
// use std::collections::HashMap;
|
||||
// let mut all_values = HashMap::new();
|
||||
// let mut all_sorted = HashMap::new();
|
||||
// for size in $sizes {
|
||||
// let values: Vec<ComparisonCountedI32> =
|
||||
// $crate::benches::get_values::<i32>(size).into_iter().map(|x| x.into()).collect();
|
||||
// let sorted = {
|
||||
// let mut v = values.clone();
|
||||
// v.sort_by(|x, y| y.cmp(x));
|
||||
// v
|
||||
// };
|
||||
// all_values.insert(size, values);
|
||||
// all_sorted.insert(size, sorted);
|
||||
// }
|
||||
|
||||
// $bencher.bench_function_over_inputs(
|
||||
// &format!("sort (counting comparisons) {}", stringify!($heap_factory)),
|
||||
// move |b: &mut criterion::Bencher, size: &usize| {
|
||||
// // let mut all_counts = Vec::new();
|
||||
// // let mut iterations = 0;
|
||||
// let values = all_values.get(size).unwrap();
|
||||
// let sorted = all_sorted.get(size).unwrap();
|
||||
// b.iter(|| {
|
||||
// // iterations += 1;
|
||||
// // let mut counts = ComparisonCounts::now();
|
||||
// let mut heap = $heap_factory();
|
||||
// for v in values {
|
||||
// heap.push(*v);
|
||||
// }
|
||||
// let mut heap_sorted = Vec::with_capacity(heap.len());
|
||||
// while let Some(x) = heap.pop() {
|
||||
// heap_sorted.push(x);
|
||||
// }
|
||||
// // counts.take_difference();
|
||||
// // all_counts.push(counts);
|
||||
// assert_eq!(heap_sorted, *sorted);
|
||||
// });
|
||||
// // let total_counts = all_counts.into_iter().fold(
|
||||
// // ComparisonCounts::default(), |acc, x| acc + x);
|
||||
// // println!("\ndo_comparison_counted_bench({}, {}) partial_ord {:.2}, ord {:.2}, eq {:.2}, ne {:.2}",
|
||||
// // stringify!($heap_factory), size,
|
||||
// // (total_counts.partial_ord as f32) / ((size * iterations) as f32),
|
||||
// // (total_counts.ord as f32) / ((size * iterations) as f32),
|
||||
// // (total_counts.eq as f32) / ((size * iterations) as f32),
|
||||
// // (total_counts.neq as f32) / ((size * iterations) as f32));
|
||||
// }, $sizes);
|
||||
// })
|
||||
// }
|
||||
|
||||
/// Runs benchmarks over sequences of size `$sizes`.
|
||||
#[macro_export]
|
||||
macro_rules! do_bench {
|
||||
($bencher: ident, $type: ty, $heap_factory: expr, $sizes: expr) => ({
|
||||
use std::collections::HashMap;
|
||||
let mut all_values = HashMap::new();
|
||||
let mut all_sorted = HashMap::new();
|
||||
for size in $sizes {
|
||||
let values: Vec<$type> = $crate::benches::get_values(size);
|
||||
let sorted = {
|
||||
let mut v = values.clone();
|
||||
v.sort_by(|x, y| y.cmp(x));
|
||||
v
|
||||
};
|
||||
all_values.insert(size, values);
|
||||
all_sorted.insert(size, sorted);
|
||||
}
|
||||
|
||||
$bencher.bench_function_over_inputs(
|
||||
&format!("sort ({}) {}", stringify!($type), stringify!($heap_factory)),
|
||||
move |b: &mut criterion::Bencher, size: &usize| {
|
||||
let values = all_values.get(&size).unwrap();
|
||||
let sorted = all_sorted.get(size).unwrap();
|
||||
b.iter(|| {
|
||||
let mut heap = $heap_factory();
|
||||
for v in values {
|
||||
heap.push(v.clone());
|
||||
}
|
||||
let mut heap_sorted = Vec::with_capacity(heap.len());
|
||||
while let Some(x) = heap.pop() {
|
||||
heap_sorted.push(x);
|
||||
}
|
||||
assert_eq!(heap_sorted, *sorted);
|
||||
});
|
||||
}, $sizes);
|
||||
})
|
||||
}
|
||||
|
||||
pub mod tiny;
|
||||
// pub mod small;
|
||||
// pub mod medium;
|
||||
// pub mod large;
|
32
src/benches/large.rs
Normal file
32
src/benches/large.rs
Normal file
@ -0,0 +1,32 @@
|
||||
/// Criterion group definitions for large tests.
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use crate::WeakHeap;
|
||||
|
||||
fn sizes() -> Range<usize> { 1024..4096 }
|
||||
|
||||
fn bench_i32_sort_binary(c: &mut Criterion) {
|
||||
do_bench!(c, i32, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_binary, bench_i32_sort_binary);
|
||||
|
||||
fn bench_i32_sort_weak(c: &mut Criterion) {
|
||||
do_bench!(c, i32, WeakHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_weak, bench_i32_sort_weak);
|
||||
|
||||
fn bench_comparison_counted_i32_sort_binary(c: &mut Criterion) {
|
||||
do_comparison_counted_bench!(c, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(comparison_counted_i32_sort_weak,
|
||||
bench_comparison_counted_i32_sort_weak);
|
||||
|
||||
fn bench_comparison_counted_i32_sort_weak(c: &mut Criterion) {
|
||||
do_comparison_counted_bench!(c, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(comparison_counted_i32_sort_weak,
|
||||
bench_comparison_counted_i32_sort_weak);
|
32
src/benches/medium.rs
Normal file
32
src/benches/medium.rs
Normal file
@ -0,0 +1,32 @@
|
||||
/// Criterion group definitions for medium tests.
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use crate::WeakHeap;
|
||||
|
||||
fn sizes() -> Range<usize> { 256..1024 }
|
||||
|
||||
fn bench_i32_sort_binary(c: &mut Criterion) {
|
||||
do_bench!(c, i32, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_binary, bench_i32_sort_binary);
|
||||
|
||||
fn bench_i32_sort_weak(c: &mut Criterion) {
|
||||
do_bench!(c, i32, WeakHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_weak, bench_i32_sort_weak);
|
||||
|
||||
fn bench_comparison_counted_i32_sort_binary(c: &mut Criterion) {
|
||||
do_comparison_counted_bench!(c, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(comparison_counted_i32_sort_weak,
|
||||
bench_comparison_counted_i32_sort_weak);
|
||||
|
||||
fn bench_comparison_counted_i32_sort_weak(c: &mut Criterion) {
|
||||
do_comparison_counted_bench!(c, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(comparison_counted_i32_sort_weak,
|
||||
bench_comparison_counted_i32_sort_weak);
|
32
src/benches/small.rs
Normal file
32
src/benches/small.rs
Normal file
@ -0,0 +1,32 @@
|
||||
/// Criterion group definitions for small tests.
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use crate::WeakHeap;
|
||||
|
||||
fn sizes() -> Range<usize> { 128..256 }
|
||||
|
||||
fn bench_i32_sort_binary(c: &mut Criterion) {
|
||||
do_bench!(c, i32, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_binary, bench_i32_sort_binary);
|
||||
|
||||
fn bench_i32_sort_weak(c: &mut Criterion) {
|
||||
do_bench!(c, i32, WeakHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_weak, bench_i32_sort_weak);
|
||||
|
||||
fn bench_comparison_counted_i32_sort_binary(c: &mut Criterion) {
|
||||
do_comparison_counted_bench!(c, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(comparison_counted_i32_sort_weak,
|
||||
bench_comparison_counted_i32_sort_weak);
|
||||
|
||||
fn bench_comparison_counted_i32_sort_weak(c: &mut Criterion) {
|
||||
do_comparison_counted_bench!(c, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(comparison_counted_i32_sort_weak,
|
||||
bench_comparison_counted_i32_sort_weak);
|
59
src/benches/tiny.rs
Normal file
59
src/benches/tiny.rs
Normal file
@ -0,0 +1,59 @@
|
||||
/// Criterion group definitions for tiny tests.
|
||||
|
||||
use criterion::{Criterion, criterion_group};
|
||||
use std::collections::BinaryHeap;
|
||||
use std::ops::Range;
|
||||
use crate::WeakHeap;
|
||||
use crate::benches::U32768;
|
||||
|
||||
fn sizes() -> Range<usize> { 1..128 }
|
||||
|
||||
fn bench_i32_sort_binary(c: &mut Criterion) {
|
||||
do_bench!(c, i32, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_binary, bench_i32_sort_binary);
|
||||
|
||||
fn bench_i32_sort_weak(c: &mut Criterion) {
|
||||
do_bench!(c, i32, WeakHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i32_sort_weak, bench_i32_sort_weak);
|
||||
|
||||
fn bench_i128_sort_binary(c: &mut Criterion) {
|
||||
do_bench!(c, i128, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i128_sort_binary, bench_i128_sort_binary);
|
||||
|
||||
fn bench_i128_sort_weak(c: &mut Criterion) {
|
||||
do_bench!(c, i128, WeakHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(i128_sort_weak, bench_i128_sort_weak);
|
||||
|
||||
fn bench_u32768_sort_binary(c: &mut Criterion) {
|
||||
do_bench!(c, U32768, BinaryHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(u32768_sort_binary, bench_u32768_sort_binary);
|
||||
|
||||
fn bench_u32768_sort_weak(c: &mut Criterion) {
|
||||
do_bench!(c, U32768, WeakHeap::new, sizes())
|
||||
}
|
||||
|
||||
criterion_group!(u32768_sort_weak, bench_u32768_sort_weak);
|
||||
|
||||
// fn bench_comparison_counted_i32_sort_binary(c: &mut Criterion) {
|
||||
// do_comparison_counted_i32_bench!(c, BinaryHeap::new, sizes())
|
||||
// }
|
||||
|
||||
// criterion_group!(comparison_counted_i32_sort_binary,
|
||||
// bench_comparison_counted_i32_sort_binary);
|
||||
|
||||
// fn bench_comparison_counted_i32_sort_weak(c: &mut Criterion) {
|
||||
// do_comparison_counted_i32_bench!(c, BinaryHeap::new, sizes())
|
||||
// }
|
||||
|
||||
// criterion_group!(comparison_counted_i32_sort_weak,
|
||||
// bench_comparison_counted_i32_sort_weak);
|
@ -27,6 +27,8 @@ use std::cmp::Ord;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(feature = "benchmark-definitions")] pub mod benches;
|
||||
|
||||
/// An entry in the heap, consisting of a bit that indicates whether the roles
|
||||
/// of its left and right children are swapped, and the actual value being
|
||||
/// stored in the heap.
|
||||
@ -191,10 +193,11 @@ impl<T: fmt::Debug + Ord> WeakHeap<T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::WeakHeap;
|
||||
use rand::{Rng, SeedableRng, StdRng};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
pub fn get_values(size: usize) -> Vec<i32> {
|
||||
let seed: &[_] = &[1, 2, 3, 4];
|
||||
let seed: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31];
|
||||
let mut rng: StdRng = SeedableRng::from_seed(seed);
|
||||
(0..size).map(|_| rng.gen::<i32>()).map(|x| x.into()).collect()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user