Skip to content

Commit 143609d

Browse files
committed
Auto merge of #83 - edre:bench, r=Amanieu
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
2 parents 987b962 + 2025fb4 commit 143609d

File tree

1 file changed

+200
-116
lines changed

1 file changed

+200
-116
lines changed

benches/bench.rs

Lines changed: 200 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,234 @@
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

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

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

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-
}
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>;
3721

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-
})
43+
}
8044
}
8145

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);
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))
57+
}
8758
}
59+
}
8860

89-
b.iter(|| {
90-
for i in 1..1001 {
91-
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+
})
9272
}
93-
})
73+
};
9474
}
9575

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));
76+
bench_insert!(insert_fx_serial, FxHashMap, 0..SIZE);
77+
bench_insert!(insert_std_serial, StdHashMap, 0..SIZE);
78+
bench_insert!(
79+
insert_fx_highbits,
80+
FxHashMap,
81+
(0..SIZE).map(usize::swap_bytes)
82+
);
83+
bench_insert!(
84+
insert_std_highbits,
85+
StdHashMap,
86+
(0..SIZE).map(usize::swap_bytes)
87+
);
88+
bench_insert!(insert_fx_random, FxHashMap, RandomKeys::new(SIZE));
89+
bench_insert!(insert_std_random, StdHashMap, RandomKeys::new(SIZE));
90+
91+
macro_rules! bench_insert_erase {
92+
($name:ident, $maptype:ident, $keydist:expr) => {
93+
#[bench]
94+
fn $name(b: &mut Bencher) {
95+
b.iter(|| {
96+
let mut m = $maptype::default();
97+
for i in $keydist {
98+
m.insert(i, i);
99+
}
100+
black_box(&mut m);
101+
for i in $keydist {
102+
m.remove(&i);
103+
}
104+
black_box(m);
105+
})
106106
}
107-
})
107+
};
108108
}
109109

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);
115-
}
116-
117-
b.iter(|| {
118-
for i in 1001..2001 {
119-
black_box(m.get(&i));
110+
bench_insert_erase!(insert_erase_fx_serial, FxHashMap, 0..SIZE);
111+
bench_insert_erase!(insert_erase_std_serial, StdHashMap, 0..SIZE);
112+
bench_insert_erase!(
113+
insert_erase_fx_highbits,
114+
FxHashMap,
115+
(0..SIZE).map(usize::swap_bytes)
116+
);
117+
bench_insert_erase!(
118+
insert_erase_std_highbits,
119+
StdHashMap,
120+
(0..SIZE).map(usize::swap_bytes)
121+
);
122+
bench_insert_erase!(insert_erase_fx_random, FxHashMap, RandomKeys::new(SIZE));
123+
bench_insert_erase!(insert_erase_std_random, StdHashMap, RandomKeys::new(SIZE));
124+
125+
macro_rules! bench_lookup {
126+
($name:ident, $maptype:ident, $keydist:expr) => {
127+
#[bench]
128+
fn $name(b: &mut Bencher) {
129+
let mut m = $maptype::default();
130+
for i in $keydist {
131+
m.insert(i, i);
132+
}
133+
134+
b.iter(|| {
135+
for i in $keydist {
136+
black_box(m.get(&i));
137+
}
138+
})
120139
}
121-
})
140+
};
122141
}
123142

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);
129-
}
130-
131-
b.iter(|| {
132-
for i in &m {
133-
black_box(i);
143+
bench_lookup!(lookup_fx_serial, FxHashMap, 0..SIZE);
144+
bench_lookup!(lookup_std_serial, StdHashMap, 0..SIZE);
145+
bench_lookup!(
146+
lookup_fx_highbits,
147+
FxHashMap,
148+
(0..SIZE).map(usize::swap_bytes)
149+
);
150+
bench_lookup!(
151+
lookup_std_highbits,
152+
StdHashMap,
153+
(0..SIZE).map(usize::swap_bytes)
154+
);
155+
bench_lookup!(lookup_fx_random, FxHashMap, RandomKeys::new(SIZE));
156+
bench_lookup!(lookup_std_random, StdHashMap, RandomKeys::new(SIZE));
157+
158+
macro_rules! bench_lookup_fail {
159+
($name:ident, $maptype:ident, $keydist:expr, $keydist2:expr) => {
160+
#[bench]
161+
fn $name(b: &mut Bencher) {
162+
let mut m = $maptype::default();
163+
for i in $keydist {
164+
m.insert(i, i);
165+
}
166+
167+
b.iter(|| {
168+
for i in $keydist2 {
169+
black_box(m.get(&i));
170+
}
171+
})
134172
}
135-
})
173+
};
136174
}
137175

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);
143-
}
144-
145-
b.iter(|| {
146-
for i in &m {
147-
black_box(i);
176+
bench_lookup_fail!(lookup_fail_fx_serial, FxHashMap, 0..SIZE, SIZE..SIZE * 2);
177+
bench_lookup_fail!(lookup_fail_std_serial, StdHashMap, 0..SIZE, SIZE..SIZE * 2);
178+
bench_lookup_fail!(
179+
lookup_fail_fx_highbits,
180+
FxHashMap,
181+
(0..SIZE).map(usize::swap_bytes),
182+
(SIZE..SIZE * 2).map(usize::swap_bytes)
183+
);
184+
bench_lookup_fail!(
185+
lookup_fail_std_highbits,
186+
StdHashMap,
187+
(0..SIZE).map(usize::swap_bytes),
188+
(SIZE..SIZE * 2).map(usize::swap_bytes)
189+
);
190+
bench_lookup_fail!(
191+
lookup_fail_fx_random,
192+
FxHashMap,
193+
RandomKeys::new(SIZE),
194+
RandomKeys::new2(SIZE)
195+
);
196+
bench_lookup_fail!(
197+
lookup_fail_std_random,
198+
StdHashMap,
199+
RandomKeys::new(SIZE),
200+
RandomKeys::new2(SIZE)
201+
);
202+
203+
macro_rules! bench_iter {
204+
($name:ident, $maptype:ident, $keydist:expr) => {
205+
#[bench]
206+
fn $name(b: &mut Bencher) {
207+
let mut m = $maptype::default();
208+
for i in $keydist {
209+
m.insert(i, i);
210+
}
211+
212+
b.iter(|| {
213+
for i in &m {
214+
black_box(i);
215+
}
216+
})
148217
}
149-
})
218+
};
150219
}
220+
221+
bench_iter!(iter_fx_serial, FxHashMap, 0..SIZE);
222+
bench_iter!(iter_std_serial, StdHashMap, 0..SIZE);
223+
bench_iter!(
224+
iter_fx_highbits,
225+
FxHashMap,
226+
(0..SIZE).map(usize::swap_bytes)
227+
);
228+
bench_iter!(
229+
iter_std_highbits,
230+
StdHashMap,
231+
(0..SIZE).map(usize::swap_bytes)
232+
);
233+
bench_iter!(iter_fx_random, FxHashMap, RandomKeys::new(SIZE));
234+
bench_iter!(iter_std_random, StdHashMap, RandomKeys::new(SIZE));

0 commit comments

Comments
 (0)