11#![ feature( test) ]
22extern crate test;
33
4- use std:: {
5- alloc:: { alloc_zeroed, dealloc, Layout } ,
6- mem:: { self , MaybeUninit } ,
7- ptr:: NonNull ,
8- } ;
4+ use core:: mem:: MaybeUninit ;
95
10- // AlignedBuffer is like a Box<[u8; N]> except that it is always N-byte aligned
11- struct AlignedBuffer < const N : usize > ( NonNull < [ u8 ; N ] > ) ;
12-
13- impl < const N : usize > AlignedBuffer < N > {
14- fn layout ( ) -> Layout {
15- Layout :: from_size_align ( N , N ) . unwrap ( )
16- }
17-
18- fn new ( ) -> Self {
19- let p = unsafe { alloc_zeroed ( Self :: layout ( ) ) } as * mut [ u8 ; N ] ;
20- Self ( NonNull :: new ( p) . unwrap ( ) )
21- }
22-
23- fn buf ( & mut self ) -> & mut [ u8 ; N ] {
24- unsafe { self . 0 . as_mut ( ) }
25- }
26- }
27-
28- impl < const N : usize > Drop for AlignedBuffer < N > {
29- fn drop ( & mut self ) {
30- unsafe { dealloc ( self . 0 . as_ptr ( ) as * mut u8 , Self :: layout ( ) ) }
31- }
32- }
33-
34- // Used to benchmark the throughput of getrandom in an optimal scenario.
35- // The buffer is hot, and does not require initialization.
6+ // Used to benchmark the throughput of getrandom where we have to initialize the
7+ // buffer every time.
368#[ inline( always) ]
379fn bench < const N : usize > ( b : & mut test:: Bencher ) {
38- let mut ab = AlignedBuffer :: < N > :: new ( ) ;
39- let buf = ab. buf ( ) ;
40- b. iter ( || {
41- getrandom:: getrandom ( & mut buf[ ..] ) . unwrap ( ) ;
42- test:: black_box ( & buf) ;
43- } ) ;
4410 b. bytes = N as u64 ;
45- }
46-
47- // Used to benchmark the throughput of getrandom is a slightly less optimal
48- // scenario. The buffer is still hot, but requires initialization.
49- #[ inline( always) ]
50- fn bench_with_init < const N : usize > ( b : & mut test:: Bencher ) {
51- let mut ab = AlignedBuffer :: < N > :: new ( ) ;
52- let buf = ab. buf ( ) ;
5311 b. iter ( || {
54- for byte in buf. iter_mut ( ) {
55- * byte = 0 ;
56- }
57- getrandom:: getrandom ( & mut buf[ ..] ) . unwrap ( ) ;
12+ let mut buf = [ 0u8 ; N ] ;
13+ getrandom:: getrandom ( & mut buf) . unwrap ( ) ;
5814 test:: black_box ( & buf) ;
5915 } ) ;
60- b. bytes = N as u64 ;
6116}
6217
63- // Used to benchmark the benefit of `getrandom_uninit` compared to
64- // zero-initializing a buffer and then using `getrandom` (`bench_with_init`
65- // above).
18+ // Used to benchmark getrandom_uninit, where we don't need to initilize the
19+ // buffer each time.
6620#[ inline( always) ]
6721fn bench_uninit < const N : usize > ( b : & mut test:: Bencher ) {
68- let mut ab = AlignedBuffer :: < N > :: new ( ) ;
69- let buf = ab. buf ( ) ;
70- // SAFETY: `buf` doesn't escape this scope.
71- let buf = unsafe { slice_as_uninit_mut ( buf) } ;
22+ b. bytes = N as u64 ;
7223 b. iter ( || {
73- let _ = getrandom:: getrandom_uninit_slice ( buf) ;
74- } )
24+ let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; N ] ;
25+ let buf: & [ u8 ] = getrandom:: getrandom_uninit_slice ( & mut buf) . unwrap ( ) ;
26+ test:: black_box ( buf) ;
27+ } ) ;
7528}
7629
77- // 32 bytes (256-bit) is the seed sized used for rand::thread_rng
78- const SEED : usize = 32 ;
7930// Common size of a page, 4 KiB
8031const PAGE : usize = 4096 ;
8132// Large buffer to get asymptotic performance, 2 MiB
8233const LARGE : usize = 1 << 21 ;
8334
8435#[ bench]
85- fn bench_seed ( b : & mut test:: Bencher ) {
86- bench :: < SEED > ( b) ;
36+ fn bench_16 ( b : & mut test:: Bencher ) {
37+ bench :: < 16 > ( b) ;
8738}
8839#[ bench]
89- fn bench_seed_init ( b : & mut test:: Bencher ) {
90- bench_with_init :: < SEED > ( b) ;
40+ fn bench_16_uninit ( b : & mut test:: Bencher ) {
41+ bench_uninit :: < 16 > ( b) ;
42+ }
43+
44+ #[ bench]
45+ fn bench_32 ( b : & mut test:: Bencher ) {
46+ bench :: < 32 > ( b) ;
9147}
9248#[ bench]
93- fn bench_seed_uninit ( b : & mut test:: Bencher ) {
94- bench_uninit :: < SEED > ( b) ;
49+ fn bench_32_uninit ( b : & mut test:: Bencher ) {
50+ bench_uninit :: < 32 > ( b) ;
9551}
9652
9753#[ bench]
98- fn bench_page ( b : & mut test:: Bencher ) {
99- bench :: < PAGE > ( b) ;
54+ fn bench_256 ( b : & mut test:: Bencher ) {
55+ bench :: < 256 > ( b) ;
10056}
10157#[ bench]
102- fn bench_page_init ( b : & mut test:: Bencher ) {
103- bench_with_init :: < PAGE > ( b) ;
58+ fn bench_256_uninit ( b : & mut test:: Bencher ) {
59+ bench_uninit :: < 256 > ( b) ;
60+ }
61+
62+ #[ bench]
63+ fn bench_page ( b : & mut test:: Bencher ) {
64+ bench :: < PAGE > ( b) ;
10465}
10566#[ bench]
10667fn bench_page_uninit ( b : & mut test:: Bencher ) {
@@ -112,17 +73,6 @@ fn bench_large(b: &mut test::Bencher) {
11273 bench :: < LARGE > ( b) ;
11374}
11475#[ bench]
115- fn bench_large_init ( b : & mut test:: Bencher ) {
116- bench_with_init :: < LARGE > ( b) ;
117- }
118- #[ bench]
11976fn bench_large_uninit ( b : & mut test:: Bencher ) {
12077 bench_uninit :: < LARGE > ( b) ;
12178}
122-
123- // TODO: Safety note.
124- #[ inline( always) ]
125- unsafe fn slice_as_uninit_mut < T > ( slice : & mut [ T ] ) -> & mut [ MaybeUninit < T > ] {
126- // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
127- mem:: transmute ( slice)
128- }
0 commit comments