1 #![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))]
2 
3 use ahash::{AHasher, RandomState};
4 use criterion::*;
5 use fxhash::FxHasher;
6 use rand::Rng;
7 use std::collections::hash_map::DefaultHasher;
8 use std::hash::{BuildHasherDefault, Hash, Hasher};
9 
10 // Needs to be in sync with `src/lib.rs`
11 const AHASH_IMPL: &str = if cfg!(any(
12     all(
13         any(target_arch = "x86", target_arch = "x86_64"),
14         target_feature = "aes",
15         not(miri),
16     ),
17     all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)),
18     all(
19         feature = "nightly-arm-aes",
20         target_arch = "arm",
21         target_feature = "aes",
22         not(miri)
23     ),
24 )) {
25     "aeshash"
26 } else {
27     "fallbackhash"
28 };
29 
ahash<H: Hash>(b: &H) -> u6430 fn ahash<H: Hash>(b: &H) -> u64 {
31     let build_hasher = RandomState::with_seeds(1, 2, 3, 4);
32     build_hasher.hash_one(b)
33 }
34 
fnvhash<H: Hash>(b: &H) -> u6435 fn fnvhash<H: Hash>(b: &H) -> u64 {
36     let mut hasher = fnv::FnvHasher::default();
37     b.hash(&mut hasher);
38     hasher.finish()
39 }
40 
siphash<H: Hash>(b: &H) -> u6441 fn siphash<H: Hash>(b: &H) -> u64 {
42     let mut hasher = DefaultHasher::default();
43     b.hash(&mut hasher);
44     hasher.finish()
45 }
46 
fxhash<H: Hash>(b: &H) -> u6447 fn fxhash<H: Hash>(b: &H) -> u64 {
48     let mut hasher = FxHasher::default();
49     b.hash(&mut hasher);
50     hasher.finish()
51 }
52 
seahash<H: Hash>(b: &H) -> u6453 fn seahash<H: Hash>(b: &H) -> u64 {
54     let mut hasher = seahash::SeaHasher::default();
55     b.hash(&mut hasher);
56     hasher.finish()
57 }
58 
59 const STRING_LENGTHS: [u32; 12] = [1, 3, 4, 7, 8, 15, 16, 24, 33, 68, 132, 1024];
60 
gen_strings() -> Vec<String>61 fn gen_strings() -> Vec<String> {
62     STRING_LENGTHS
63         .iter()
64         .map(|len| {
65             let mut string = String::default();
66             for pos in 1..=*len {
67                 let c = (48 + (pos % 10) as u8) as char;
68                 string.push(c);
69             }
70             string
71         })
72         .collect()
73 }
74 
75 macro_rules! bench_inputs {
76     ($group:ident, $hash:ident) => {
77         // Number of iterations per batch should be high enough to hide timing overhead.
78         let size = BatchSize::NumIterations(50_000);
79 
80         let mut rng = rand::thread_rng();
81         $group.bench_function("u8", |b| b.iter_batched(|| rng.gen::<u8>(), |v| $hash(&v), size));
82         $group.bench_function("u16", |b| b.iter_batched(|| rng.gen::<u16>(), |v| $hash(&v), size));
83         $group.bench_function("u32", |b| b.iter_batched(|| rng.gen::<u32>(), |v| $hash(&v), size));
84         $group.bench_function("u64", |b| b.iter_batched(|| rng.gen::<u64>(), |v| $hash(&v), size));
85         $group.bench_function("u128", |b| b.iter_batched(|| rng.gen::<u128>(), |v| $hash(&v), size));
86         $group.bench_with_input("strings", &gen_strings(), |b, s| b.iter(|| $hash(black_box(s))));
87     };
88 }
89 
bench_ahash(c: &mut Criterion)90 fn bench_ahash(c: &mut Criterion) {
91     let mut group = c.benchmark_group(AHASH_IMPL);
92     bench_inputs!(group, ahash);
93 }
94 
bench_fx(c: &mut Criterion)95 fn bench_fx(c: &mut Criterion) {
96     let mut group = c.benchmark_group("fx");
97     bench_inputs!(group, fxhash);
98 }
99 
bench_fnv(c: &mut Criterion)100 fn bench_fnv(c: &mut Criterion) {
101     let mut group = c.benchmark_group("fnv");
102     bench_inputs!(group, fnvhash);
103 }
104 
bench_sea(c: &mut Criterion)105 fn bench_sea(c: &mut Criterion) {
106     let mut group = c.benchmark_group("sea");
107     bench_inputs!(group, seahash);
108 }
109 
bench_sip(c: &mut Criterion)110 fn bench_sip(c: &mut Criterion) {
111     let mut group = c.benchmark_group("sip");
112     bench_inputs!(group, siphash);
113 }
114 
bench_map(c: &mut Criterion)115 fn bench_map(c: &mut Criterion) {
116     #[cfg(feature = "std")]
117     {
118         let mut group = c.benchmark_group("map");
119         group.bench_function("aHash-alias", |b| {
120             b.iter(|| {
121                 let hm: ahash::HashMap<i32, i32> = (0..1_000_000).map(|i| (i, i)).collect();
122                 let mut sum = 0;
123                 for i in 0..1_000_000 {
124                     if let Some(x) = hm.get(&i) {
125                         sum += x;
126                     }
127                 }
128             })
129         });
130         group.bench_function("aHash-hashBrown", |b| {
131             b.iter(|| {
132                 let hm: hashbrown::HashMap<i32, i32> = (0..1_000_000).map(|i| (i, i)).collect();
133                 let mut sum = 0;
134                 for i in 0..1_000_000 {
135                     if let Some(x) = hm.get(&i) {
136                         sum += x;
137                     }
138                 }
139             })
140         });
141         group.bench_function("aHash-hashBrown-explicit", |b| {
142             b.iter(|| {
143                 let hm: hashbrown::HashMap<i32, i32, RandomState> = (0..1_000_000).map(|i| (i, i)).collect();
144                 let mut sum = 0;
145                 for i in 0..1_000_000 {
146                     if let Some(x) = hm.get(&i) {
147                         sum += x;
148                     }
149                 }
150             })
151         });
152         group.bench_function("aHash-wrapper", |b| {
153             b.iter(|| {
154                 let hm: ahash::AHashMap<i32, i32> = (0..1_000_000).map(|i| (i, i)).collect();
155                 let mut sum = 0;
156                 for i in 0..1_000_000 {
157                     if let Some(x) = hm.get(&i) {
158                         sum += x;
159                     }
160                 }
161             })
162         });
163         group.bench_function("aHash-rand", |b| {
164             b.iter(|| {
165                 let hm: std::collections::HashMap<i32, i32, RandomState> = (0..1_000_000).map(|i| (i, i)).collect();
166                 let mut sum = 0;
167                 for i in 0..1_000_000 {
168                     if let Some(x) = hm.get(&i) {
169                         sum += x;
170                     }
171                 }
172             })
173         });
174         group.bench_function("aHash-default", |b| {
175             b.iter(|| {
176                 let hm: std::collections::HashMap<i32, i32, BuildHasherDefault<AHasher>> =
177                     (0..1_000_000).map(|i| (i, i)).collect();
178                 let mut sum = 0;
179                 for i in 0..1_000_000 {
180                     if let Some(x) = hm.get(&i) {
181                         sum += x;
182                     }
183                 }
184             })
185         });
186     }
187 }
188 
189 criterion_main!(benches);
190 
191 criterion_group!(
192     benches,
193     bench_ahash,
194     bench_fx,
195     bench_fnv,
196     bench_sea,
197     bench_sip,
198     bench_map
199 );
200