Skip to content

Commit

Permalink
Add csv and markdown exports in benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
ogxd committed Nov 4, 2023
1 parent bf7644d commit 103a493
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 30 deletions.
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
[package]
name = "gxhash"
author = "Olivier Giniaux"
version = "0.1.0"
version = "1.0.0"
edition = "2021"

[features]
# The 256-bit state GxHash is faster for large inputs than the default 128-bit state implementation, but faster on smaller hashes.
# Please not however that the 256-bit GxHash and the 128-bit GxHash don't generate the same hashes for a same input.
# Requires AVX2 and VAES (X86).
avx2 = []
# Only relevant for throughput benchmarks
bench-csv = []
bench-md = []

[dependencies]
rand = "0.8"
Expand All @@ -24,11 +27,11 @@ twox-hash = "1.6.3"
highway = "1.1.0"

[[bench]]
name = "throughput2"
name = "throughput"
harness = false

[[bench]]
name = "throughput"
name = "throughput_criterion"
harness = false

[[bench]]
Expand Down
39 changes: 18 additions & 21 deletions benches/throughput2.rs → benches/throughput/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
include!("../fnv.rs");

mod result_processor;

use result_processor::*;

use std::hint::black_box;
use std::time::{Instant, Duration};
use std::alloc::{alloc, dealloc, Layout};
Expand All @@ -6,7 +12,6 @@ use std::slice;
use rand::Rng;

use gxhash::*;
mod fnv;

const ITERATIONS: u32 = 1000;
const MAX_RUN_DURATION: Duration = Duration::from_millis(500);
Expand All @@ -23,57 +28,49 @@ fn main() {
// Fill with random bytes
rng.fill(slice);

print!("Input size (bytes), ");
for i in 2.. {
let len = usize::pow(2, i);
if len > slice.len() {
break;
}
print!("{}, ", len);
}
println!();
let mut processor = ResultProcessor::default();

// GxHash
let algo_name = if cfg!(feature = "avx2") { "gxhash-avx2" } else { "gxhash" };
benchmark(slice, algo_name, |data: &[u8], seed: i32| -> u64 {
benchmark(&mut processor, slice, algo_name, |data: &[u8], seed: i32| -> u64 {
gxhash64(data, seed)
});

// AHash
let ahash_hasher = ahash::RandomState::with_seeds(0, 0, 0, 0);
benchmark(slice, "ahash", |data: &[u8], _: i32| -> u64 {
benchmark(&mut processor, slice, "ahash", |data: &[u8], _: i32| -> u64 {
ahash_hasher.hash_one(data)
});

// T1ha0
benchmark(slice, "t1ha0", |data: &[u8], seed: i32| -> u64 {
benchmark(&mut processor, slice, "t1ha0", |data: &[u8], seed: i32| -> u64 {
t1ha::t1ha0(data, seed as u64)
});

// XxHash (twox-hash)
benchmark(slice, "xxhash", |data: &[u8], seed: i32| -> u64 {
benchmark(&mut processor, slice, "xxhash", |data: &[u8], seed: i32| -> u64 {
twox_hash::xxh3::hash64_with_seed(data, seed as u64)
});

// HighwayHash
benchmark(slice, "highwayhash", |data: &[u8], _: i32| -> u64 {
benchmark(&mut processor, slice, "highwayhash", |data: &[u8], _: i32| -> u64 {
use highway::{HighwayHasher, HighwayHash};
HighwayHasher::default().hash64(data)
});

// FNV-1a
benchmark(slice, "fnv-1a", |data: &[u8], seed: i32| -> u64 {
fnv::fnv_hash(data, seed as u64)
benchmark(&mut processor, slice, "fnv-1a", |data: &[u8], seed: i32| -> u64 {
fnv_hash(data, seed as u64)
});

// Free benchmark data
unsafe { dealloc(ptr, layout) };
}

fn benchmark<F>(data: &[u8], name: &str, delegate: F)
fn benchmark<F>(processor: &mut ResultProcessor, data: &[u8], name: &str, delegate: F)
where F: Fn(&[u8], i32) -> u64
{
print!("{}, ", name);
processor.on_start(name);
for i in 2.. {
let len = usize::pow(2, i);
if len > data.len() {
Expand All @@ -100,9 +97,9 @@ fn benchmark<F>(data: &[u8], name: &str, delegate: F)
}
let throughput = (len as f64) / (1024f64 * 1024f64 * (total_duration.as_secs_f64() / runs as f64 / ITERATIONS as f64));

print!("{:.2}, ", throughput);
processor.on_result(len, throughput);
}
println!();
processor.on_end();
}

#[inline(never)]
Expand Down
88 changes: 88 additions & 0 deletions benches/throughput/result_processor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#[cfg(feature = "bench-csv")]
#[derive(Default)]
pub struct ResultProcessor {
header_written: bool,
row_data: Vec<String>,
header_data: Vec<String>,
}

#[cfg(feature = "bench-csv")]
impl ResultProcessor {
pub fn on_start(&mut self, name: &str) {
self.row_data.push(name.to_string());
if !self.header_written {
self.header_data.push("Throughput (MiB/s)".to_string());
}
}

pub fn on_result(&mut self, input_size: usize, throughput: f64) {
self.row_data.push(format!("{:.2}", throughput));
if !self.header_written {
self.header_data.push(input_size.to_string());
}
}

pub fn on_end(&mut self) {
if !self.header_written {
println!("{}", self.header_data.join(", "));
self.header_written = true;
}
println!("{}", self.row_data.join(", "));
self.row_data.clear();
}
}

#[cfg(feature = "bench-md")]
#[derive(Default)]
pub struct ResultProcessor {
header_written: bool,
row_data: Vec<String>,
header_data: Vec<String>,
}

#[cfg(feature = "bench-md")]
impl ResultProcessor {
pub fn on_start(&mut self, name: &str) {
self.row_data.push(name.to_string());
if !self.header_written {
self.header_data.push("Throughput (MiB/s)".to_string());
}
}

pub fn on_result(&mut self, input_size: usize, throughput: f64) {
self.row_data.push(format!("{:.2}", throughput));
if !self.header_written {
self.header_data.push(input_size.to_string());
}
}

pub fn on_end(&mut self) {
if !self.header_written {
println!("| {} |", self.header_data.join(" | "));
let separator: Vec<String> = self.header_data.iter().map(|_| "---".to_string()).collect();
println!("|{}|", separator.join("|"));
self.header_written = true;
}
println!("| {} |", self.row_data.join(" | "));
self.row_data.clear();
}
}

#[cfg(all(not(feature = "bench-csv"),not(feature = "bench-md")))]
#[derive(Default)]
pub struct ResultProcessor;

#[cfg(all(not(feature = "bench-csv"),not(feature = "bench-md")))]
impl ResultProcessor {
pub fn on_start(&mut self, name: &str) {
println!("{}", name);
}

pub fn on_result(&mut self, input_size: usize, throughput: f64) {
println!(" | {} > {:.2}", input_size, throughput);
}

pub fn on_end(&mut self) {
println!();
}
}
File renamed without changes.
3 changes: 1 addition & 2 deletions src/gxhash/platform/arm_128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ pub unsafe fn finalize(hash: State, seed: i32) -> State {

// 3 rounds of AES
let mut hash = ReinterpretUnion{ int8: hash }.uint8;
//hash = aes_encrypt(hash, ReinterpretUnion{ int32: vdupq_n_s32(seed) }.uint8);
hash = vaddq_u8(hash, ReinterpretUnion{ int32: vdupq_n_s32(seed) }.uint8);
hash = aes_encrypt(hash, ReinterpretUnion{ int32: vdupq_n_s32(seed) }.uint8);
hash = aes_encrypt(hash, ReinterpretUnion{ uint32: keys_1 }.uint8);
hash = aes_encrypt(hash, ReinterpretUnion{ uint32: keys_2 }.uint8);
hash = aes_encrypt_last(hash, ReinterpretUnion{ uint32: keys_3 }.uint8);
Expand Down
3 changes: 1 addition & 2 deletions src/gxhash/platform/x86_128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ pub unsafe fn finalize(hash: State, seed: i32) -> State {
let keys_3 = _mm_set_epi32(0xC78B122B, 0x5544B1B7, 0x689D2B7D, 0xD0012E32);

// 4 rounds of AES
//let mut hash = _mm_aesenc_si128(hash, _mm_set1_epi32(seed));
let mut hash = _mm_add_epi8(hash, _mm_set1_epi32(seed));
let mut hash = _mm_aesenc_si128(hash, _mm_set1_epi32(seed));
hash = _mm_aesenc_si128(hash, keys_1);
hash = _mm_aesenc_si128(hash, keys_2);
hash = _mm_aesenclast_si128(hash, keys_3);
Expand Down
3 changes: 1 addition & 2 deletions src/gxhash/platform/x86_256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ pub unsafe fn finalize(hash: State, seed: i32) -> State {
let keys_3 = _mm256_set_epi32(0xC78B122B, 0x5544B1B7, 0x689D2B7D, 0xD0012E32, 0xE2784542, 0x4155EE07, 0xC897CCE2, 0x780BF2C2);

// 4 rounds of AES
//let mut hash = _mm256_aesenc_epi128(hash, _mm256_set1_epi32(seed));
let mut hash = _mm256_add_epi8(hash, _mm256_set1_epi32(seed));
let mut hash = _mm256_aesenc_epi128(hash, _mm256_set1_epi32(seed));
hash = _mm256_aesenc_epi128(hash, keys_1);
hash = _mm256_aesenc_epi128(hash, keys_2);
hash = _mm256_aesenclast_epi128(hash, keys_3);
Expand Down

0 comments on commit 103a493

Please sign in to comment.