Skip to content

Commit 594a2a7

Browse files
committed
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. rust-lang/rust#29599
1 parent 987b962 commit 594a2a7

File tree

1 file changed

+150
-116
lines changed

1 file changed

+150
-116
lines changed

benches/bench.rs

Lines changed: 150 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,184 @@
1+
// This benchmark suite contains some benchmarks along a set of dimensions:
2+
// Hasher: std default (SipHash) and crate default (FxHash).
3+
// Int key distribution: low bit heavy, top bit heavy, and random.
4+
// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter
15
#![feature(test)]
26

37
extern crate test;
48

5-
use std::hash::Hash;
69
use test::{black_box, Bencher};
710

811
use hashbrown::HashMap;
9-
//use rustc_hash::FxHashMap as HashMap;
10-
//use std::collections::HashMap;
12+
use hashbrown::hash_map::DefaultHashBuilder;
13+
use std::collections::hash_map::RandomState;
1114

12-
fn new_map<K: Eq + Hash, V>() -> HashMap<K, V> {
13-
HashMap::default()
14-
}
15+
const SIZE: usize = 1000;
1516

16-
#[bench]
17-
fn insert_i32(b: &mut Bencher) {
18-
b.iter(|| {
19-
let mut m: HashMap<i32, i32> = new_map();
20-
for i in 1..1001 {
21-
m.insert(i, i);
22-
}
23-
black_box(m);
24-
})
25-
}
17+
// The default hashmap when using this crate directly.
18+
type FxHashMap<K, V> = HashMap<K, V, DefaultHashBuilder>;
19+
// This uses the hashmap from this crate with the default hasher of the stdlib.
20+
type StdHashMap<K, V> = HashMap<K, V, RandomState>;
2621

27-
#[bench]
28-
fn insert_i64(b: &mut Bencher) {
29-
b.iter(|| {
30-
let mut m: HashMap<i64, i64> = new_map();
31-
for i in 1..1001 {
32-
m.insert(i, i);
33-
}
34-
black_box(m);
35-
})
36-
}
37-
38-
#[bench]
39-
fn insert_erase_i32(b: &mut Bencher) {
40-
b.iter(|| {
41-
let mut m: HashMap<i32, i32> = new_map();
42-
for i in 1..1001 {
43-
m.insert(i, i);
44-
}
45-
black_box(&mut m);
46-
for i in 1..1001 {
47-
m.remove(&i);
48-
}
49-
black_box(m);
50-
})
22+
// A random key iterator.
23+
#[derive(Clone, Copy)]
24+
struct RandomKeys {
25+
remaining: usize,
26+
state: usize,
5127
}
5228

53-
#[bench]
54-
fn insert_erase_i64(b: &mut Bencher) {
55-
b.iter(|| {
56-
let mut m: HashMap<i64, i64> = new_map();
57-
for i in 1..1001 {
58-
m.insert(i, i);
59-
}
60-
black_box(&mut m);
61-
for i in 1..1001 {
62-
m.remove(&i);
29+
impl RandomKeys {
30+
fn new(size: usize) -> Self {
31+
RandomKeys{
32+
remaining: size,
33+
state: 1,
6334
}
64-
black_box(m);
65-
})
66-
}
67-
68-
#[bench]
69-
fn lookup_i32(b: &mut Bencher) {
70-
let mut m: HashMap<i32, i32> = new_map();
71-
for i in 1..1001 {
72-
m.insert(i, i);
7335
}
7436

75-
b.iter(|| {
76-
for i in 1..1001 {
77-
black_box(m.get(&i));
37+
// Produce a different set of random values.
38+
fn new2(size: usize) -> Self {
39+
RandomKeys{
40+
remaining: size,
41+
state: 2,
7842
}
79-
})
80-
}
81-
82-
#[bench]
83-
fn lookup_i64(b: &mut Bencher) {
84-
let mut m: HashMap<i64, i64> = new_map();
85-
for i in 1..1001 {
86-
m.insert(i, i);
8743
}
88-
89-
b.iter(|| {
90-
for i in 1..1001 {
91-
black_box(m.get(&i));
92-
}
93-
})
9444
}
9545

96-
#[bench]
97-
fn lookup_fail_i32(b: &mut Bencher) {
98-
let mut m: HashMap<i32, i32> = new_map();
99-
for i in 1..1001 {
100-
m.insert(i, i);
101-
}
102-
103-
b.iter(|| {
104-
for i in 1001..2001 {
105-
black_box(m.get(&i));
46+
impl Iterator for RandomKeys {
47+
type Item = usize;
48+
fn next(&mut self) -> Option<usize> {
49+
if self.remaining == 0 {
50+
None
51+
} else {
52+
self.remaining -= 1;
53+
// Multiply by some 32 bit prime.
54+
self.state = self.state.wrapping_mul(3787392781);
55+
// Mix in to the bottom bits which are constant mod powers of 2.
56+
Some(self.state ^ (self.state >> 4))
10657
}
107-
})
108-
}
109-
110-
#[bench]
111-
fn lookup_fail_i64(b: &mut Bencher) {
112-
let mut m: HashMap<i64, i64> = new_map();
113-
for i in 1..1001 {
114-
m.insert(i, i);
11558
}
59+
}
11660

117-
b.iter(|| {
118-
for i in 1001..2001 {
119-
black_box(m.get(&i));
61+
macro_rules! bench_insert {
62+
($name:ident, $maptype:ident, $keydist:expr) => {
63+
#[bench]
64+
fn $name(b: &mut Bencher) {
65+
b.iter(|| {
66+
let mut m = $maptype::default();
67+
for i in $keydist {
68+
m.insert(i, i);
69+
}
70+
black_box(m);
71+
})
12072
}
121-
})
73+
}
12274
}
12375

124-
#[bench]
125-
fn iter_i32(b: &mut Bencher) {
126-
let mut m: HashMap<i32, i32> = new_map();
127-
for i in 1..1001 {
128-
m.insert(i, i);
76+
bench_insert!(insert_fx_serial, FxHashMap, 0..SIZE);
77+
bench_insert!(insert_std_serial, StdHashMap, 0..SIZE);
78+
bench_insert!(insert_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
79+
bench_insert!(insert_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
80+
bench_insert!(insert_fx_random, FxHashMap, RandomKeys::new(SIZE));
81+
bench_insert!(insert_std_random, StdHashMap, RandomKeys::new(SIZE));
82+
83+
macro_rules! bench_insert_erase {
84+
($name:ident, $maptype:ident, $keydist:expr) => {
85+
#[bench]
86+
fn $name(b: &mut Bencher) {
87+
b.iter(|| {
88+
let mut m = $maptype::default();
89+
for i in $keydist {
90+
m.insert(i, i);
91+
}
92+
black_box(&mut m);
93+
for i in $keydist {
94+
m.remove(&i);
95+
}
96+
black_box(m);
97+
})
98+
}
12999
}
100+
}
130101

131-
b.iter(|| {
132-
for i in &m {
133-
black_box(i);
102+
bench_insert_erase!(insert_erase_fx_serial, FxHashMap, 0..SIZE);
103+
bench_insert_erase!(insert_erase_std_serial, StdHashMap, 0..SIZE);
104+
bench_insert_erase!(insert_erase_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
105+
bench_insert_erase!(insert_erase_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
106+
bench_insert_erase!(insert_erase_fx_random, FxHashMap, RandomKeys::new(SIZE));
107+
bench_insert_erase!(insert_erase_std_random, StdHashMap, RandomKeys::new(SIZE));
108+
109+
macro_rules! bench_lookup {
110+
($name:ident, $maptype:ident, $keydist:expr) => {
111+
#[bench]
112+
fn $name(b: &mut Bencher) {
113+
let mut m = $maptype::default();
114+
for i in $keydist {
115+
m.insert(i, i);
116+
}
117+
118+
b.iter(|| {
119+
for i in $keydist {
120+
black_box(m.get(&i));
121+
}
122+
})
134123
}
135-
})
124+
}
136125
}
137126

138-
#[bench]
139-
fn iter_i64(b: &mut Bencher) {
140-
let mut m: HashMap<i64, i64> = new_map();
141-
for i in 1..1001 {
142-
m.insert(i, i);
127+
bench_lookup!(lookup_fx_serial, FxHashMap, 0..SIZE);
128+
bench_lookup!(lookup_std_serial, StdHashMap, 0..SIZE);
129+
bench_lookup!(lookup_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
130+
bench_lookup!(lookup_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
131+
bench_lookup!(lookup_fx_random, FxHashMap, RandomKeys::new(SIZE));
132+
bench_lookup!(lookup_std_random, StdHashMap, RandomKeys::new(SIZE));
133+
134+
macro_rules! bench_lookup_fail {
135+
($name:ident, $maptype:ident, $keydist:expr, $keydist2:expr) => {
136+
#[bench]
137+
fn $name(b: &mut Bencher) {
138+
let mut m = $maptype::default();
139+
for i in $keydist {
140+
m.insert(i, i);
141+
}
142+
143+
b.iter(|| {
144+
for i in $keydist2 {
145+
black_box(m.get(&i));
146+
}
147+
})
148+
}
143149
}
150+
}
144151

145-
b.iter(|| {
146-
for i in &m {
147-
black_box(i);
152+
bench_lookup_fail!(lookup_fail_fx_serial, FxHashMap, 0..SIZE, SIZE..SIZE*2);
153+
bench_lookup_fail!(lookup_fail_std_serial, StdHashMap, 0..SIZE, SIZE..SIZE*2);
154+
bench_lookup_fail!(lookup_fail_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes),
155+
(SIZE..SIZE*2).map(usize::swap_bytes));
156+
bench_lookup_fail!(lookup_fail_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes),
157+
(SIZE..SIZE*2).map(usize::swap_bytes));
158+
bench_lookup_fail!(lookup_fail_fx_random, FxHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE));
159+
bench_lookup_fail!(lookup_fail_std_random, StdHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE));
160+
161+
macro_rules! bench_iter {
162+
($name:ident, $maptype:ident, $keydist:expr) => {
163+
#[bench]
164+
fn $name(b: &mut Bencher) {
165+
let mut m = $maptype::default();
166+
for i in $keydist {
167+
m.insert(i, i);
168+
}
169+
170+
b.iter(|| {
171+
for i in &m {
172+
black_box(i);
173+
}
174+
})
148175
}
149-
})
176+
}
150177
}
178+
179+
bench_iter!(iter_fx_serial, FxHashMap, 0..SIZE);
180+
bench_iter!(iter_std_serial, StdHashMap, 0..SIZE);
181+
bench_iter!(iter_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
182+
bench_iter!(iter_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
183+
bench_iter!(iter_fx_random, FxHashMap, RandomKeys::new(SIZE));
184+
bench_iter!(iter_std_random, StdHashMap, RandomKeys::new(SIZE));

0 commit comments

Comments
 (0)