1
1
#![ feature( test) ]
2
2
extern crate test;
3
3
4
- use std:: {
5
- alloc:: { alloc_zeroed, dealloc, Layout } ,
6
- mem:: { self , MaybeUninit } ,
7
- ptr:: NonNull ,
8
- } ;
4
+ use core:: mem:: MaybeUninit ;
9
5
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.
36
8
#[ inline( always) ]
37
9
fn 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
- } ) ;
44
10
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 ( ) ;
53
11
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 ( ) ;
58
14
test:: black_box ( & buf) ;
59
15
} ) ;
60
- b. bytes = N as u64 ;
61
16
}
62
17
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.
66
20
#[ inline( always) ]
67
21
fn 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 ;
72
23
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
+ } ) ;
75
28
}
76
29
77
- // 32 bytes (256-bit) is the seed sized used for rand::thread_rng
78
- const SEED : usize = 32 ;
79
30
// Common size of a page, 4 KiB
80
31
const PAGE : usize = 4096 ;
81
32
// Large buffer to get asymptotic performance, 2 MiB
82
33
const LARGE : usize = 1 << 21 ;
83
34
84
35
#[ 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) ;
87
38
}
88
39
#[ 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) ;
91
47
}
92
48
#[ 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) ;
95
51
}
96
52
97
53
#[ 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) ;
100
56
}
101
57
#[ 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) ;
104
65
}
105
66
#[ bench]
106
67
fn bench_page_uninit ( b : & mut test:: Bencher ) {
@@ -112,17 +73,6 @@ fn bench_large(b: &mut test::Bencher) {
112
73
bench :: < LARGE > ( b) ;
113
74
}
114
75
#[ bench]
115
- fn bench_large_init ( b : & mut test:: Bencher ) {
116
- bench_with_init :: < LARGE > ( b) ;
117
- }
118
- #[ bench]
119
76
fn bench_large_uninit ( b : & mut test:: Bencher ) {
120
77
bench_uninit :: < LARGE > ( b) ;
121
78
}
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