blob: 4abdb17fb1e7a24e28b876ac019710f5bb441e42 [file] [log] [blame]
Matthew Maureraa861082020-04-01 14:15:18 -07001// This benchmark suite contains some benchmarks along a set of dimensions:
2// Hasher: std default (SipHash) and crate default (AHash).
3// Int key distribution: low bit heavy, top bit heavy, and random.
4// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter
5#![feature(test)]
6
7extern crate test;
8
9use test::{black_box, Bencher};
10
11use hashbrown::hash_map::DefaultHashBuilder;
12use hashbrown::HashMap;
13use std::collections::hash_map::RandomState;
14
15const SIZE: usize = 1000;
16
17// The default hashmap when using this crate directly.
18type AHashMap<K, V> = HashMap<K, V, DefaultHashBuilder>;
19// This uses the hashmap from this crate with the default hasher of the stdlib.
20type StdHashMap<K, V> = HashMap<K, V, RandomState>;
21
22// A random key iterator.
23#[derive(Clone, Copy)]
24struct RandomKeys {
25 state: usize,
26}
27
28impl RandomKeys {
29 fn new() -> Self {
30 RandomKeys { state: 0 }
31 }
32}
33
34impl Iterator for RandomKeys {
35 type Item = usize;
36 fn next(&mut self) -> Option<usize> {
37 // Add 1 then multiply by some 32 bit prime.
38 self.state = self.state.wrapping_add(1).wrapping_mul(3787392781);
39 Some(self.state)
40 }
41}
42
43macro_rules! bench_suite {
44 ($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident,
45 $bench_ahash_highbits:ident, $bench_std_highbits:ident,
46 $bench_ahash_random:ident, $bench_std_random:ident) => {
47 $bench_macro!($bench_ahash_serial, AHashMap, 0..);
48 $bench_macro!($bench_std_serial, StdHashMap, 0..);
49 $bench_macro!(
50 $bench_ahash_highbits,
51 AHashMap,
52 (0..).map(usize::swap_bytes)
53 );
54 $bench_macro!(
55 $bench_std_highbits,
56 StdHashMap,
57 (0..).map(usize::swap_bytes)
58 );
59 $bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new());
60 $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new());
61 };
62}
63
64macro_rules! bench_insert {
65 ($name:ident, $maptype:ident, $keydist:expr) => {
66 #[bench]
67 fn $name(b: &mut Bencher) {
68 let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default());
69 b.iter(|| {
70 m.clear();
71 for i in ($keydist).take(SIZE) {
72 m.insert(i, i);
73 }
74 black_box(&mut m);
75 })
76 }
77 };
78}
79
80bench_suite!(
81 bench_insert,
82 insert_ahash_serial,
83 insert_std_serial,
84 insert_ahash_highbits,
85 insert_std_highbits,
86 insert_ahash_random,
87 insert_std_random
88);
89
90macro_rules! bench_insert_erase {
91 ($name:ident, $maptype:ident, $keydist:expr) => {
92 #[bench]
93 fn $name(b: &mut Bencher) {
94 let mut base = $maptype::default();
95 for i in ($keydist).take(SIZE) {
96 base.insert(i, i);
97 }
98 let skip = $keydist.skip(SIZE);
99 b.iter(|| {
100 let mut m = base.clone();
101 let mut add_iter = skip.clone();
102 let mut remove_iter = $keydist;
103 // While keeping the size constant,
104 // replace the first keydist with the second.
105 for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) {
106 m.insert(add, add);
107 black_box(m.remove(&remove));
108 }
109 black_box(m);
110 })
111 }
112 };
113}
114
115bench_suite!(
116 bench_insert_erase,
117 insert_erase_ahash_serial,
118 insert_erase_std_serial,
119 insert_erase_ahash_highbits,
120 insert_erase_std_highbits,
121 insert_erase_ahash_random,
122 insert_erase_std_random
123);
124
125macro_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.take(SIZE) {
131 m.insert(i, i);
132 }
133
134 b.iter(|| {
135 for i in $keydist.take(SIZE) {
136 black_box(m.get(&i));
137 }
138 })
139 }
140 };
141}
142
143bench_suite!(
144 bench_lookup,
145 lookup_ahash_serial,
146 lookup_std_serial,
147 lookup_ahash_highbits,
148 lookup_std_highbits,
149 lookup_ahash_random,
150 lookup_std_random
151);
152
153macro_rules! bench_lookup_fail {
154 ($name:ident, $maptype:ident, $keydist:expr) => {
155 #[bench]
156 fn $name(b: &mut Bencher) {
157 let mut m = $maptype::default();
158 let mut iter = $keydist;
159 for i in (&mut iter).take(SIZE) {
160 m.insert(i, i);
161 }
162
163 b.iter(|| {
164 for i in (&mut iter).take(SIZE) {
165 black_box(m.get(&i));
166 }
167 })
168 }
169 };
170}
171
172bench_suite!(
173 bench_lookup_fail,
174 lookup_fail_ahash_serial,
175 lookup_fail_std_serial,
176 lookup_fail_ahash_highbits,
177 lookup_fail_std_highbits,
178 lookup_fail_ahash_random,
179 lookup_fail_std_random
180);
181
182macro_rules! bench_iter {
183 ($name:ident, $maptype:ident, $keydist:expr) => {
184 #[bench]
185 fn $name(b: &mut Bencher) {
186 let mut m = $maptype::default();
187 for i in ($keydist).take(SIZE) {
188 m.insert(i, i);
189 }
190
191 b.iter(|| {
192 for i in &m {
193 black_box(i);
194 }
195 })
196 }
197 };
198}
199
200bench_suite!(
201 bench_iter,
202 iter_ahash_serial,
203 iter_std_serial,
204 iter_ahash_highbits,
205 iter_std_highbits,
206 iter_ahash_random,
207 iter_std_random
208);