From 594a2a766f47e95255f750d530174887eed064b3 Mon Sep 17 00:00:00 2001 From: Eric Roshan-Eisner Date: Fri, 31 May 2019 15:59:44 -0700 Subject: [PATCH 1/2] Add the std hasher and different key distributions to benchmarks. Also remove the i32/i64 duplication, as those differences were in the noise compared to the other dimensions. I would have liked to reduce some of the macro duplication, but it looks like that's still not easy. https://github.com/rust-lang/rust/issues/29599 --- benches/bench.rs | 266 ++++++++++++++++++++++++++--------------------- 1 file changed, 150 insertions(+), 116 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 9c1542a40b..9a6838c7e1 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,150 +1,184 @@ +// This benchmark suite contains some benchmarks along a set of dimensions: +// Hasher: std default (SipHash) and crate default (FxHash). +// Int key distribution: low bit heavy, top bit heavy, and random. +// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter #![feature(test)] extern crate test; -use std::hash::Hash; use test::{black_box, Bencher}; use hashbrown::HashMap; -//use rustc_hash::FxHashMap as HashMap; -//use std::collections::HashMap; +use hashbrown::hash_map::DefaultHashBuilder; +use std::collections::hash_map::RandomState; -fn new_map() -> HashMap { - HashMap::default() -} +const SIZE: usize = 1000; -#[bench] -fn insert_i32(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); - } - black_box(m); - }) -} +// The default hashmap when using this crate directly. +type FxHashMap = HashMap; +// This uses the hashmap from this crate with the default hasher of the stdlib. +type StdHashMap = HashMap; -#[bench] -fn insert_i64(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); - } - black_box(m); - }) -} - -#[bench] -fn insert_erase_i32(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); - } - black_box(&mut m); - for i in 1..1001 { - m.remove(&i); - } - black_box(m); - }) +// A random key iterator. +#[derive(Clone, Copy)] +struct RandomKeys { + remaining: usize, + state: usize, } -#[bench] -fn insert_erase_i64(b: &mut Bencher) { - b.iter(|| { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); - } - black_box(&mut m); - for i in 1..1001 { - m.remove(&i); +impl RandomKeys { + fn new(size: usize) -> Self { + RandomKeys{ + remaining: size, + state: 1, } - black_box(m); - }) -} - -#[bench] -fn lookup_i32(b: &mut Bencher) { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); } - b.iter(|| { - for i in 1..1001 { - black_box(m.get(&i)); + // Produce a different set of random values. + fn new2(size: usize) -> Self { + RandomKeys{ + remaining: size, + state: 2, } - }) -} - -#[bench] -fn lookup_i64(b: &mut Bencher) { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); } - - b.iter(|| { - for i in 1..1001 { - black_box(m.get(&i)); - } - }) } -#[bench] -fn lookup_fail_i32(b: &mut Bencher) { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); - } - - b.iter(|| { - for i in 1001..2001 { - black_box(m.get(&i)); +impl Iterator for RandomKeys { + type Item = usize; + fn next(&mut self) -> Option { + if self.remaining == 0 { + None + } else { + self.remaining -= 1; + // Multiply by some 32 bit prime. + self.state = self.state.wrapping_mul(3787392781); + // Mix in to the bottom bits which are constant mod powers of 2. + Some(self.state ^ (self.state >> 4)) } - }) -} - -#[bench] -fn lookup_fail_i64(b: &mut Bencher) { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); } +} - b.iter(|| { - for i in 1001..2001 { - black_box(m.get(&i)); +macro_rules! bench_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut m = $maptype::default(); + for i in $keydist { + m.insert(i, i); + } + black_box(m); + }) } - }) + } } -#[bench] -fn iter_i32(b: &mut Bencher) { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); +bench_insert!(insert_fx_serial, FxHashMap, 0..SIZE); +bench_insert!(insert_std_serial, StdHashMap, 0..SIZE); +bench_insert!(insert_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_insert!(insert_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_insert!(insert_fx_random, FxHashMap, RandomKeys::new(SIZE)); +bench_insert!(insert_std_random, StdHashMap, RandomKeys::new(SIZE)); + +macro_rules! bench_insert_erase { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut m = $maptype::default(); + for i in $keydist { + m.insert(i, i); + } + black_box(&mut m); + for i in $keydist { + m.remove(&i); + } + black_box(m); + }) + } } +} - b.iter(|| { - for i in &m { - black_box(i); +bench_insert_erase!(insert_erase_fx_serial, FxHashMap, 0..SIZE); +bench_insert_erase!(insert_erase_std_serial, StdHashMap, 0..SIZE); +bench_insert_erase!(insert_erase_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_insert_erase!(insert_erase_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_insert_erase!(insert_erase_fx_random, FxHashMap, RandomKeys::new(SIZE)); +bench_insert_erase!(insert_erase_std_random, StdHashMap, RandomKeys::new(SIZE)); + +macro_rules! bench_lookup { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist { + m.insert(i, i); + } + + b.iter(|| { + for i in $keydist { + black_box(m.get(&i)); + } + }) } - }) + } } -#[bench] -fn iter_i64(b: &mut Bencher) { - let mut m: HashMap = new_map(); - for i in 1..1001 { - m.insert(i, i); +bench_lookup!(lookup_fx_serial, FxHashMap, 0..SIZE); +bench_lookup!(lookup_std_serial, StdHashMap, 0..SIZE); +bench_lookup!(lookup_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_lookup!(lookup_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_lookup!(lookup_fx_random, FxHashMap, RandomKeys::new(SIZE)); +bench_lookup!(lookup_std_random, StdHashMap, RandomKeys::new(SIZE)); + +macro_rules! bench_lookup_fail { + ($name:ident, $maptype:ident, $keydist:expr, $keydist2:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist { + m.insert(i, i); + } + + b.iter(|| { + for i in $keydist2 { + black_box(m.get(&i)); + } + }) + } } +} - b.iter(|| { - for i in &m { - black_box(i); +bench_lookup_fail!(lookup_fail_fx_serial, FxHashMap, 0..SIZE, SIZE..SIZE*2); +bench_lookup_fail!(lookup_fail_std_serial, StdHashMap, 0..SIZE, SIZE..SIZE*2); +bench_lookup_fail!(lookup_fail_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes), + (SIZE..SIZE*2).map(usize::swap_bytes)); +bench_lookup_fail!(lookup_fail_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes), + (SIZE..SIZE*2).map(usize::swap_bytes)); +bench_lookup_fail!(lookup_fail_fx_random, FxHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE)); +bench_lookup_fail!(lookup_fail_std_random, StdHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE)); + +macro_rules! bench_iter { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist { + m.insert(i, i); + } + + b.iter(|| { + for i in &m { + black_box(i); + } + }) } - }) + } } + +bench_iter!(iter_fx_serial, FxHashMap, 0..SIZE); +bench_iter!(iter_std_serial, StdHashMap, 0..SIZE); +bench_iter!(iter_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_iter!(iter_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_iter!(iter_fx_random, FxHashMap, RandomKeys::new(SIZE)); +bench_iter!(iter_std_random, StdHashMap, RandomKeys::new(SIZE)); From 2025fb4b2445cc6e1d5ce4ce4e4121b3b37e10fc Mon Sep 17 00:00:00 2001 From: Eric Roshan-Eisner Date: Sat, 1 Jun 2019 08:33:29 -0700 Subject: [PATCH 2/2] rustfmt macros --- benches/bench.rs | 98 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 24 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 9a6838c7e1..1db351942d 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -8,8 +8,8 @@ extern crate test; use test::{black_box, Bencher}; -use hashbrown::HashMap; use hashbrown::hash_map::DefaultHashBuilder; +use hashbrown::HashMap; use std::collections::hash_map::RandomState; const SIZE: usize = 1000; @@ -28,7 +28,7 @@ struct RandomKeys { impl RandomKeys { fn new(size: usize) -> Self { - RandomKeys{ + RandomKeys { remaining: size, state: 1, } @@ -36,7 +36,7 @@ impl RandomKeys { // Produce a different set of random values. fn new2(size: usize) -> Self { - RandomKeys{ + RandomKeys { remaining: size, state: 2, } @@ -70,13 +70,21 @@ macro_rules! bench_insert { black_box(m); }) } - } + }; } bench_insert!(insert_fx_serial, FxHashMap, 0..SIZE); bench_insert!(insert_std_serial, StdHashMap, 0..SIZE); -bench_insert!(insert_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); -bench_insert!(insert_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_insert!( + insert_fx_highbits, + FxHashMap, + (0..SIZE).map(usize::swap_bytes) +); +bench_insert!( + insert_std_highbits, + StdHashMap, + (0..SIZE).map(usize::swap_bytes) +); bench_insert!(insert_fx_random, FxHashMap, RandomKeys::new(SIZE)); bench_insert!(insert_std_random, StdHashMap, RandomKeys::new(SIZE)); @@ -96,13 +104,21 @@ macro_rules! bench_insert_erase { black_box(m); }) } - } + }; } bench_insert_erase!(insert_erase_fx_serial, FxHashMap, 0..SIZE); bench_insert_erase!(insert_erase_std_serial, StdHashMap, 0..SIZE); -bench_insert_erase!(insert_erase_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); -bench_insert_erase!(insert_erase_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_insert_erase!( + insert_erase_fx_highbits, + FxHashMap, + (0..SIZE).map(usize::swap_bytes) +); +bench_insert_erase!( + insert_erase_std_highbits, + StdHashMap, + (0..SIZE).map(usize::swap_bytes) +); bench_insert_erase!(insert_erase_fx_random, FxHashMap, RandomKeys::new(SIZE)); bench_insert_erase!(insert_erase_std_random, StdHashMap, RandomKeys::new(SIZE)); @@ -121,13 +137,21 @@ macro_rules! bench_lookup { } }) } - } + }; } bench_lookup!(lookup_fx_serial, FxHashMap, 0..SIZE); bench_lookup!(lookup_std_serial, StdHashMap, 0..SIZE); -bench_lookup!(lookup_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); -bench_lookup!(lookup_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_lookup!( + lookup_fx_highbits, + FxHashMap, + (0..SIZE).map(usize::swap_bytes) +); +bench_lookup!( + lookup_std_highbits, + StdHashMap, + (0..SIZE).map(usize::swap_bytes) +); bench_lookup!(lookup_fx_random, FxHashMap, RandomKeys::new(SIZE)); bench_lookup!(lookup_std_random, StdHashMap, RandomKeys::new(SIZE)); @@ -146,17 +170,35 @@ macro_rules! bench_lookup_fail { } }) } - } + }; } -bench_lookup_fail!(lookup_fail_fx_serial, FxHashMap, 0..SIZE, SIZE..SIZE*2); -bench_lookup_fail!(lookup_fail_std_serial, StdHashMap, 0..SIZE, SIZE..SIZE*2); -bench_lookup_fail!(lookup_fail_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes), - (SIZE..SIZE*2).map(usize::swap_bytes)); -bench_lookup_fail!(lookup_fail_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes), - (SIZE..SIZE*2).map(usize::swap_bytes)); -bench_lookup_fail!(lookup_fail_fx_random, FxHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE)); -bench_lookup_fail!(lookup_fail_std_random, StdHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE)); +bench_lookup_fail!(lookup_fail_fx_serial, FxHashMap, 0..SIZE, SIZE..SIZE * 2); +bench_lookup_fail!(lookup_fail_std_serial, StdHashMap, 0..SIZE, SIZE..SIZE * 2); +bench_lookup_fail!( + lookup_fail_fx_highbits, + FxHashMap, + (0..SIZE).map(usize::swap_bytes), + (SIZE..SIZE * 2).map(usize::swap_bytes) +); +bench_lookup_fail!( + lookup_fail_std_highbits, + StdHashMap, + (0..SIZE).map(usize::swap_bytes), + (SIZE..SIZE * 2).map(usize::swap_bytes) +); +bench_lookup_fail!( + lookup_fail_fx_random, + FxHashMap, + RandomKeys::new(SIZE), + RandomKeys::new2(SIZE) +); +bench_lookup_fail!( + lookup_fail_std_random, + StdHashMap, + RandomKeys::new(SIZE), + RandomKeys::new2(SIZE) +); macro_rules! bench_iter { ($name:ident, $maptype:ident, $keydist:expr) => { @@ -173,12 +215,20 @@ macro_rules! bench_iter { } }) } - } + }; } bench_iter!(iter_fx_serial, FxHashMap, 0..SIZE); bench_iter!(iter_std_serial, StdHashMap, 0..SIZE); -bench_iter!(iter_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes)); -bench_iter!(iter_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes)); +bench_iter!( + iter_fx_highbits, + FxHashMap, + (0..SIZE).map(usize::swap_bytes) +); +bench_iter!( + iter_std_highbits, + StdHashMap, + (0..SIZE).map(usize::swap_bytes) +); bench_iter!(iter_fx_random, FxHashMap, RandomKeys::new(SIZE)); bench_iter!(iter_std_random, StdHashMap, RandomKeys::new(SIZE));