From 4719b5f6068d80f58cc940fb114739d67bccfaf4 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 17 Oct 2022 16:09:32 -0700 Subject: [PATCH] Rework benchmarks --- benches/mod.rs | 114 ++++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 82 deletions(-) diff --git a/benches/mod.rs b/benches/mod.rs index 322e64ae9..8f8bd6d3e 100644 --- a/benches/mod.rs +++ b/benches/mod.rs @@ -1,106 +1,67 @@ #![feature(test)] extern crate test; -use std::{ - alloc::{alloc_zeroed, dealloc, Layout}, - mem::{self, MaybeUninit}, - ptr::NonNull, -}; +use core::mem::MaybeUninit; -// AlignedBuffer is like a Box<[u8; N]> except that it is always N-byte aligned -struct AlignedBuffer(NonNull<[u8; N]>); - -impl AlignedBuffer { - fn layout() -> Layout { - Layout::from_size_align(N, N).unwrap() - } - - fn new() -> Self { - let p = unsafe { alloc_zeroed(Self::layout()) } as *mut [u8; N]; - Self(NonNull::new(p).unwrap()) - } - - fn buf(&mut self) -> &mut [u8; N] { - unsafe { self.0.as_mut() } - } -} - -impl Drop for AlignedBuffer { - fn drop(&mut self) { - unsafe { dealloc(self.0.as_ptr() as *mut u8, Self::layout()) } - } -} - -// Used to benchmark the throughput of getrandom in an optimal scenario. -// The buffer is hot, and does not require initialization. +// Used to benchmark the throughput of getrandom where we have to initialize the +// buffer every time. #[inline(always)] fn bench(b: &mut test::Bencher) { - let mut ab = AlignedBuffer::::new(); - let buf = ab.buf(); - b.iter(|| { - getrandom::getrandom(&mut buf[..]).unwrap(); - test::black_box(&buf); - }); b.bytes = N as u64; -} - -// Used to benchmark the throughput of getrandom is a slightly less optimal -// scenario. The buffer is still hot, but requires initialization. -#[inline(always)] -fn bench_with_init(b: &mut test::Bencher) { - let mut ab = AlignedBuffer::::new(); - let buf = ab.buf(); b.iter(|| { - for byte in buf.iter_mut() { - *byte = 0; - } - getrandom::getrandom(&mut buf[..]).unwrap(); + let mut buf = [0u8; N]; + getrandom::getrandom(&mut buf).unwrap(); test::black_box(&buf); }); - b.bytes = N as u64; } -// Used to benchmark the benefit of `getrandom_uninit` compared to -// zero-initializing a buffer and then using `getrandom` (`bench_with_init` -// above). +// Used to benchmark getrandom_uninit, where we don't need to initilize the +// buffer each time. #[inline(always)] fn bench_uninit(b: &mut test::Bencher) { - let mut ab = AlignedBuffer::::new(); - let buf = ab.buf(); - // SAFETY: `buf` doesn't escape this scope. - let buf = unsafe { slice_as_uninit_mut(buf) }; + b.bytes = N as u64; b.iter(|| { - let _ = getrandom::getrandom_uninit_slice(buf); - }) + let mut buf = [MaybeUninit::::uninit(); N]; + let buf: &[u8] = getrandom::getrandom_uninit_slice(&mut buf).unwrap(); + test::black_box(buf); + }); } -// 32 bytes (256-bit) is the seed sized used for rand::thread_rng -const SEED: usize = 32; // Common size of a page, 4 KiB const PAGE: usize = 4096; // Large buffer to get asymptotic performance, 2 MiB const LARGE: usize = 1 << 21; #[bench] -fn bench_seed(b: &mut test::Bencher) { - bench::(b); +fn bench_16(b: &mut test::Bencher) { + bench::<16>(b); } #[bench] -fn bench_seed_init(b: &mut test::Bencher) { - bench_with_init::(b); +fn bench_16_uninit(b: &mut test::Bencher) { + bench_uninit::<16>(b); +} + +#[bench] +fn bench_32(b: &mut test::Bencher) { + bench::<32>(b); } #[bench] -fn bench_seed_uninit(b: &mut test::Bencher) { - bench_uninit::(b); +fn bench_32_uninit(b: &mut test::Bencher) { + bench_uninit::<32>(b); } #[bench] -fn bench_page(b: &mut test::Bencher) { - bench::(b); +fn bench_256(b: &mut test::Bencher) { + bench::<256>(b); } #[bench] -fn bench_page_init(b: &mut test::Bencher) { - bench_with_init::(b); +fn bench_256_uninit(b: &mut test::Bencher) { + bench_uninit::<256>(b); +} + +#[bench] +fn bench_page(b: &mut test::Bencher) { + bench::(b); } #[bench] fn bench_page_uninit(b: &mut test::Bencher) { @@ -112,17 +73,6 @@ fn bench_large(b: &mut test::Bencher) { bench::(b); } #[bench] -fn bench_large_init(b: &mut test::Bencher) { - bench_with_init::(b); -} -#[bench] fn bench_large_uninit(b: &mut test::Bencher) { bench_uninit::(b); } - -// TODO: Safety note. -#[inline(always)] -unsafe fn slice_as_uninit_mut(slice: &mut [T]) -> &mut [MaybeUninit] { - // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `T`. - mem::transmute(slice) -}