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