Merge branch 'hashx-bench' into 'main'

hashx_cachegrind: factor out some common stuff in benchmarks

See merge request tpo/core/arti!1529
This commit is contained in:
Ian Jackson 2023-08-23 10:05:51 +00:00
commit 7d6f5531ce
1 changed files with 63 additions and 38 deletions

View File

@ -11,68 +11,93 @@
use iai::black_box;
fn generate_interp_1000x() {
let mut builder = hashx::HashXBuilder::new();
builder.runtime(hashx::RuntimeOption::InterpretOnly);
for s in 0_u32..1000_u32 {
let _ = black_box(builder.build(black_box(&s.to_be_bytes())));
/// Bind Rust `HashBuilder` whose `RuntimeOption` is `$runtime_option` to `$builder`
//
// This and mk_c_equix are macros rather than a function because it avoids us
// having to import RuntimeOption::*, etc. or clutter the calls with a local alias.
macro_rules! mk_rust { { $builder:ident = $runtime_option:ident } => {
let mut $builder = hashx::HashXBuilder::new();
$builder.runtime(hashx::RuntimeOption::$runtime_option);
} }
/// Bind a C `HashX` whose `HashXType` is `$hashx_type` to `$ctx`
macro_rules! mk_c_equix { { $ctx:ident = $hashx_type:ident } => {
let mut $ctx = tor_c_equix::HashX::new(tor_c_equix::HashXType::$hashx_type);
} }
/// Evaluate `$eval` binding `$loopvar` to `0..$max`
///
/// Applies `black_box` to inputs and outputs.
///
/// If `$loopvar_map` is supplied, it is a function applied to $loopvar
/// to convert from the integer loop variable, to whatever more useful type is needed.
//
// We expect $loopvar_map:ident even though a closure would be suitable, mostly because
// we expect the actual benchmark cases to want to use a short alias like `u32be`
macro_rules! bench_loop { {
$loopvar:ident, $max:expr $(, $loopvar_map:ident )? => $eval:expr
} => {
for $loopvar in 0..$max {
$(
let $loopvar = $loopvar_map($loopvar);
)?
let $loopvar = black_box($loopvar);
let _ = black_box($eval);
}
} }
/// Convenience alias to reduce clutter in actual benchmarks
const C_HASHX_OK: tor_c_equix::ffi::hashx_result = tor_c_equix::HashXResult::HASHX_OK;
/// Helper, alias for `u32::to_be_bytes`
//
// Unfortunately, we can't just `use u32::to_be_bytes`.
fn u32be(s: u32) -> [u8; 4] {
s.to_be_bytes()
}
fn generate_interp_1000x() {
mk_rust!(builder = InterpretOnly);
bench_loop! { s, 1000_u32, u32be => builder.build(&s) }
}
fn generate_interp_1000x_c() {
let mut ctx = tor_c_equix::HashX::new(tor_c_equix::HashXType::HASHX_TYPE_INTERPRETED);
for s in 0_u32..1000_u32 {
let _ = black_box(ctx.make(black_box(&s.to_be_bytes())));
}
mk_c_equix!(ctx = HASHX_TYPE_INTERPRETED);
bench_loop! { s, 1000_u32, u32be => ctx.make(&s) }
}
fn generate_compiled_1000x() {
let mut builder = hashx::HashXBuilder::new();
builder.runtime(hashx::RuntimeOption::CompileOnly);
for s in 0_u32..1000_u32 {
let _ = black_box(builder.build(black_box(&s.to_be_bytes())));
}
mk_rust!(builder = CompileOnly);
bench_loop! { s, 1000_u32, u32be => builder.build(&s) }
}
fn generate_compiled_1000x_c() {
let mut ctx = tor_c_equix::HashX::new(tor_c_equix::HashXType::HASHX_TYPE_COMPILED);
for s in 0_u32..1000_u32 {
let _ = black_box(ctx.make(black_box(&s.to_be_bytes())));
}
mk_c_equix!(ctx = HASHX_TYPE_COMPILED);
bench_loop! { s, 1000_u32, u32be => ctx.make(&s) }
}
fn interp_u64_hash_1000x() {
let mut builder = hashx::HashXBuilder::new();
builder.runtime(hashx::RuntimeOption::InterpretOnly);
mk_rust!(builder = InterpretOnly);
let hashx = builder.build(b"abc").unwrap();
for i in 0_u64..1000_u64 {
let _ = black_box(hashx.hash_to_u64(black_box(i)));
}
bench_loop! { i, 1000_u64 => hashx.hash_to_u64(i) }
}
fn interp_8b_hash_1000x_c() {
let mut ctx = tor_c_equix::HashX::new(tor_c_equix::HashXType::HASHX_TYPE_INTERPRETED);
assert_eq!(ctx.make(b"abc"), tor_c_equix::HashXResult::HASHX_OK);
for i in 0_u64..1000_u64 {
let _ = black_box(ctx.exec(black_box(i)));
}
mk_c_equix!(ctx = HASHX_TYPE_INTERPRETED);
assert_eq!(ctx.make(b"abc"), C_HASHX_OK);
bench_loop! { i, 1000_u64 => ctx.exec(i) }
}
fn compiled_u64_hash_100000x() {
let mut builder = hashx::HashXBuilder::new();
builder.runtime(hashx::RuntimeOption::CompileOnly);
mk_rust!(builder = CompileOnly);
let hashx = builder.build(b"abc").unwrap();
for i in 0_u64..100000_u64 {
let _ = black_box(hashx.hash_to_u64(black_box(i)));
}
bench_loop! { i, 100000_u64 => hashx.hash_to_u64(i) }
}
fn compiled_8b_hash_100000x_c() {
let mut ctx = tor_c_equix::HashX::new(tor_c_equix::HashXType::HASHX_TYPE_COMPILED);
assert_eq!(ctx.make(b"abc"), tor_c_equix::HashXResult::HASHX_OK);
for i in 0_u64..100000_u64 {
let _ = black_box(ctx.exec(black_box(i)));
}
mk_c_equix!(ctx = HASHX_TYPE_COMPILED);
assert_eq!(ctx.make(b"abc"), C_HASHX_OK);
bench_loop! { i, 100000_u64 => ctx.exec(i) }
}
iai::main!(