Skip to content

Commit 9ac388e

Browse files
committed
Rework benchmarks to make it easier to get assembly.
This change: - Move the benchmarks from mod.rs to buffer.rs - Move the inner loop we benchmark into an `#[inline(never)]` function - Includes instructions for getting the ASM for a specific benchmark This should hopefully reduce the variance of these benchmarks and make it easier to figure out if we are emitting the assembly or IR we expect for a particular implementation. Signed-off-by: Joe Richey <joerichey@google.com>
1 parent 359b978 commit 9ac388e

File tree

1 file changed

+32
-25
lines changed

1 file changed

+32
-25
lines changed

benches/buffer.rs

+32-25
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,53 @@
1-
#![feature(test)]
2-
#![feature(maybe_uninit_as_bytes)]
3-
1+
#![feature(test, maybe_uninit_uninit_array_transpose)]
42
extern crate test;
53

64
use std::mem::MaybeUninit;
75

8-
// Used to benchmark the throughput of getrandom in an optimal scenario.
9-
// The buffer is hot, and does not require initialization.
6+
// Call getrandom on a zero-initialized stack buffer
107
#[inline(always)]
11-
fn bench_getrandom<const N: usize>(b: &mut test::Bencher) {
12-
b.bytes = N as u64;
13-
b.iter(|| {
14-
let mut buf = [0u8; N];
15-
getrandom::getrandom(&mut buf[..]).unwrap();
16-
test::black_box(buf);
17-
});
8+
fn bench_getrandom<const N: usize>() {
9+
let mut buf = [0u8; N];
10+
getrandom::getrandom(&mut buf).unwrap();
11+
test::black_box(&buf as &[u8]);
1812
}
1913

20-
// Used to benchmark the throughput of getrandom is a slightly less optimal
21-
// scenario. The buffer is still hot, but requires initialization.
14+
// Call getrandom_uninit on an uninitialized stack buffer
2215
#[inline(always)]
23-
fn bench_getrandom_uninit<const N: usize>(b: &mut test::Bencher) {
24-
b.bytes = N as u64;
25-
b.iter(|| {
26-
let mut buf: MaybeUninit<[u8; N]> = MaybeUninit::uninit();
27-
let _ = getrandom::getrandom_uninit(buf.as_bytes_mut()).unwrap();
28-
let buf: [u8; N] = unsafe { buf.assume_init() };
29-
test::black_box(buf)
30-
});
16+
fn bench_getrandom_uninit<const N: usize>() {
17+
let mut uninit = [MaybeUninit::uninit(); N];
18+
let buf: &[u8] = getrandom::getrandom_uninit(&mut uninit).unwrap();
19+
test::black_box(buf);
3120
}
3221

22+
// We benchmark using #[inline(never)] "inner" functions for two reasons:
23+
// - Avoiding inlining reduces a source of variance when running benchmarks.
24+
// - It is _much_ easier to get the assembly or IR for the inner loop.
25+
//
26+
// For example, using cargo-show-asm (https://github.com/pacak/cargo-show-asm),
27+
// we can get the assembly for a particular benchmark's inner loop by running:
28+
// cargo asm --bench buffer --release buffer::p384::bench_getrandom::inner
3329
macro_rules! bench {
3430
( $name:ident, $size:expr ) => {
3531
pub mod $name {
3632
#[bench]
3733
pub fn bench_getrandom(b: &mut test::Bencher) {
38-
super::bench_getrandom::<{ $size }>(b);
39-
}
34+
#[inline(never)]
35+
fn inner() {
36+
super::bench_getrandom::<{ $size }>()
37+
}
4038

39+
b.bytes = $size as u64;
40+
b.iter(inner);
41+
}
4142
#[bench]
4243
pub fn bench_getrandom_uninit(b: &mut test::Bencher) {
43-
super::bench_getrandom_uninit::<{ $size }>(b);
44+
#[inline(never)]
45+
fn inner() {
46+
super::bench_getrandom_uninit::<{ $size }>()
47+
}
48+
49+
b.bytes = $size as u64;
50+
b.iter(inner);
4451
}
4552
}
4653
};

0 commit comments

Comments
 (0)