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