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