Skip to content

Commit

Permalink
Issue 210: Fast path hardening take 2 (#215)
Browse files Browse the repository at this point in the history
* Reverts the basic fast path for u64 to be two folded multiplies.

Signed-off-by: Tom Kaitchuck <Tom.Kaitchuck@gmail.com>
  • Loading branch information
tkaitchuck committed Mar 3, 2024
1 parent e7481cd commit 7778357
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "ahash"
version = "0.8.8"
version = "0.8.10"
authors = ["Tom Kaitchuck <Tom.Kaitchuck@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "A non-cryptographic hash function using AES-NI for high performance"
Expand Down Expand Up @@ -100,6 +100,7 @@ rand = "0.8.5"
pcg-mwc = "0.2.1"
serde_json = "1.0.59"
hashbrown = "0.14.3"
smallvec = "1.13.1"

[package.metadata.docs.rs]
rustc-args = ["-C", "target-feature=+aes"]
Expand Down
3 changes: 3 additions & 0 deletions compare/Cargo.toml
Expand Up @@ -29,6 +29,9 @@ codegen-units = 1

[dependencies]
ahash = { path = "../", default-features = false }
pcg-mwc = "0.2.1"
rand = "0.8.5"
rand_core = "0.6.4"

[dev-dependencies]
criterion = "0.3.3"
Expand Down
32 changes: 32 additions & 0 deletions compare/src/main.rs
@@ -0,0 +1,32 @@
use std::io::Error;
use std::fs::File;
use std::io::Write;
use pcg_mwc::Mwc256XXA64;
use ahash::RandomState;
use std::io::BufWriter;
use std::path::Path;
use rand_core::SeedableRng;
use rand::Rng;
use std::time::Instant;


fn main() -> Result<(), Error> {
let mut r = Mwc256XXA64::seed_from_u64(0xe786_c22b_119c_1479);

let path = Path::new("hash_output");

let mut file = BufWriter::new(File::create(path)?);
let hasher = RandomState::with_seeds(r.gen(), r.gen(), r.gen(), r.gen());
let start = Instant::now();
let mut sum: u64 = 0;
for i in 0..i32::MAX {
let value = hasher.hash_one(i as u64);
sum = sum.wrapping_add(value);
let value: [u8; 8] = value.to_ne_bytes();
file.write_all(&value)?;
}
let elapsed = start.elapsed();
println!("Sum {} Elapsed time: {}", sum, elapsed.as_millis());
file.flush()?;
Ok(())
}
4 changes: 1 addition & 3 deletions src/aes_hash.rs
Expand Up @@ -225,8 +225,7 @@ pub(crate) struct AHasherU64 {
impl Hasher for AHasherU64 {
#[inline]
fn finish(&self) -> u64 {
let rot = (self.pad & 63) as u32;
self.buffer.rotate_left(rot)
folded_multiply(self.buffer, self.pad)
}

#[inline]
Expand All @@ -252,7 +251,6 @@ impl Hasher for AHasherU64 {
#[inline]
fn write_u64(&mut self, i: u64) {
self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE);
self.pad = self.pad.wrapping_add(i);
}

#[inline]
Expand Down
11 changes: 5 additions & 6 deletions src/fallback_hash.rs
Expand Up @@ -56,8 +56,8 @@ impl AHasher {
#[allow(dead_code)] // Is not called if non-fallback hash is used.
pub(crate) fn from_random_state(rand_state: &RandomState) -> AHasher {
AHasher {
buffer: rand_state.k0,
pad: rand_state.k1,
buffer: rand_state.k1,
pad: rand_state.k0,
extra_keys: [rand_state.k2, rand_state.k3],
}
}
Expand Down Expand Up @@ -117,7 +117,7 @@ impl AHasher {
#[inline]
#[cfg(feature = "specialize")]
fn short_finish(&self) -> u64 {
self.buffer.wrapping_add(self.pad)
folded_multiply(self.buffer, self.pad)
}
}

Expand Down Expand Up @@ -210,8 +210,8 @@ pub(crate) struct AHasherU64 {
impl Hasher for AHasherU64 {
#[inline]
fn finish(&self) -> u64 {
let rot = (self.pad & 63) as u32;
self.buffer.rotate_left(rot)
folded_multiply(self.buffer, self.pad)
//self.buffer
}

#[inline]
Expand All @@ -237,7 +237,6 @@ impl Hasher for AHasherU64 {
#[inline]
fn write_u64(&mut self, i: u64) {
self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE);
self.pad = self.pad.wrapping_add(i);
}

#[inline]
Expand Down
18 changes: 10 additions & 8 deletions src/hash_quality_test.rs
Expand Up @@ -338,22 +338,24 @@ fn test_length_extension<T: Hasher>(hasher: impl Fn(u128, u128) -> T) {
}

fn test_sparse<T: Hasher>(hasher: impl Fn() -> T) {
use smallvec::SmallVec;

let mut buf = [0u8; 256];
let mut hashes = HashMap::new();
for idx_1 in 0..256 {
for idx_2 in idx_1 + 1..256 {
for idx_1 in 0..255_u8 {
for idx_2 in idx_1 + 1..=255_u8 {
for value_1 in [1, 2, 4, 8, 16, 32, 64, 128] {
for value_2 in [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16, 17, 18, 20, 24, 31, 32, 33, 48, 64, 96, 127, 128, 129,
192, 254, 255,
] {
buf[idx_1] = value_1;
buf[idx_2] = value_2;
buf[idx_1 as usize] = value_1;
buf[idx_2 as usize] = value_2;
let hash_value = hash_with(&buf, &mut hasher());
let keys = hashes.entry(hash_value).or_insert(Vec::new());
keys.push((idx_1, value_1, idx_2, value_2));
buf[idx_1] = 0;
buf[idx_2] = 0;
let keys = hashes.entry(hash_value).or_insert(SmallVec::<[[u8; 4]; 1]>::new());
keys.push([idx_1, value_1, idx_2, value_2]);
buf[idx_1 as usize] = 0;
buf[idx_2 as usize] = 0;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/random_state.rs
Expand Up @@ -470,8 +470,8 @@ impl BuildHasherExt for RandomState {
#[inline]
fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = AHasherU64 {
buffer: self.k0,
pad: self.k1,
buffer: self.k1,
pad: self.k0,
};
value.hash(&mut hasher);
hasher.finish()
Expand Down
2 changes: 1 addition & 1 deletion tests/bench.rs
Expand Up @@ -75,7 +75,7 @@ fn gen_strings() -> Vec<String> {
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(2_000);
let size = BatchSize::NumIterations(50_000);

let mut rng = rand::thread_rng();
$group.bench_function("u8", |b| b.iter_batched(|| rng.gen::<u8>(), |v| $hash(&v), size));
Expand Down
2 changes: 1 addition & 1 deletion tests/map_tests.rs
Expand Up @@ -238,7 +238,7 @@ fn test_byte_dist() {
let mut table: [bool; 256 * 8] = [false; 256 * 8];
let hasher = RandomState::with_seeds(r.gen(), r.gen(), r.gen(), r.gen());
for i in 0..128 {
let mut keys: [u8; 8] = hasher.hash_one(i as u64).to_ne_bytes();
let mut keys: [u8; 8] = hasher.hash_one((i as u64) << 30).to_ne_bytes();
//let mut keys = r.next_u64().to_ne_bytes(); //This is a control to test assert sensitivity.
for idx in 0..8 {
while table[idx * 256 + keys[idx] as usize] {
Expand Down

0 comments on commit 7778357

Please sign in to comment.