#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] use ahash::{AHasher, RandomState}; use criterion::*; use fxhash::FxHasher; use rand::Rng; use std::collections::hash_map::DefaultHasher; use std::hash::{BuildHasherDefault, Hash, Hasher}; // Needs to be in sync with `src/lib.rs` const AHASH_IMPL: &str = if cfg!(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri), ), all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all( feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri) ), )) { "aeshash" } else { "fallbackhash" }; fn ahash(b: &H) -> u64 { let build_hasher = RandomState::with_seeds(1, 2, 3, 4); build_hasher.hash_one(b) } fn fnvhash(b: &H) -> u64 { let mut hasher = fnv::FnvHasher::default(); b.hash(&mut hasher); hasher.finish() } fn siphash(b: &H) -> u64 { let mut hasher = DefaultHasher::default(); b.hash(&mut hasher); hasher.finish() } fn fxhash(b: &H) -> u64 { let mut hasher = FxHasher::default(); b.hash(&mut hasher); hasher.finish() } fn seahash(b: &H) -> u64 { let mut hasher = seahash::SeaHasher::default(); b.hash(&mut hasher); hasher.finish() } const STRING_LENGTHS: [u32; 12] = [1, 3, 4, 7, 8, 15, 16, 24, 33, 68, 132, 1024]; fn gen_strings() -> Vec { STRING_LENGTHS .iter() .map(|len| { let mut string = String::default(); for pos in 1..=*len { let c = (48 + (pos % 10) as u8) as char; string.push(c); } string }) .collect() } macro_rules! bench_inputs { ($group:ident, $hash:ident) => { // Number of iterations per batch should be high enough to hide timing overhead. let size = BatchSize::NumIterations(50_000); let mut rng = rand::thread_rng(); $group.bench_function("u8", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); $group.bench_function("u16", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); $group.bench_function("u32", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); $group.bench_function("u64", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); $group.bench_function("u128", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); $group.bench_with_input("strings", &gen_strings(), |b, s| b.iter(|| $hash(black_box(s)))); }; } fn bench_ahash(c: &mut Criterion) { let mut group = c.benchmark_group(AHASH_IMPL); bench_inputs!(group, ahash); } fn bench_fx(c: &mut Criterion) { let mut group = c.benchmark_group("fx"); bench_inputs!(group, fxhash); } fn bench_fnv(c: &mut Criterion) { let mut group = c.benchmark_group("fnv"); bench_inputs!(group, fnvhash); } fn bench_sea(c: &mut Criterion) { let mut group = c.benchmark_group("sea"); bench_inputs!(group, seahash); } fn bench_sip(c: &mut Criterion) { let mut group = c.benchmark_group("sip"); bench_inputs!(group, siphash); } fn bench_map(c: &mut Criterion) { #[cfg(feature = "std")] { let mut group = c.benchmark_group("map"); group.bench_function("aHash-alias", |b| { b.iter(|| { let hm: ahash::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); let mut sum = 0; for i in 0..1_000_000 { if let Some(x) = hm.get(&i) { sum += x; } } }) }); group.bench_function("aHash-hashBrown", |b| { b.iter(|| { let hm: hashbrown::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); let mut sum = 0; for i in 0..1_000_000 { if let Some(x) = hm.get(&i) { sum += x; } } }) }); group.bench_function("aHash-hashBrown-explicit", |b| { b.iter(|| { let hm: hashbrown::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); let mut sum = 0; for i in 0..1_000_000 { if let Some(x) = hm.get(&i) { sum += x; } } }) }); group.bench_function("aHash-wrapper", |b| { b.iter(|| { let hm: ahash::AHashMap = (0..1_000_000).map(|i| (i, i)).collect(); let mut sum = 0; for i in 0..1_000_000 { if let Some(x) = hm.get(&i) { sum += x; } } }) }); group.bench_function("aHash-rand", |b| { b.iter(|| { let hm: std::collections::HashMap = (0..1_000_000).map(|i| (i, i)).collect(); let mut sum = 0; for i in 0..1_000_000 { if let Some(x) = hm.get(&i) { sum += x; } } }) }); group.bench_function("aHash-default", |b| { b.iter(|| { let hm: std::collections::HashMap> = (0..1_000_000).map(|i| (i, i)).collect(); let mut sum = 0; for i in 0..1_000_000 { if let Some(x) = hm.get(&i) { sum += x; } } }) }); } } criterion_main!(benches); criterion_group!( benches, bench_ahash, bench_fx, bench_fnv, bench_sea, bench_sip, bench_map );