1 #![feature(test)]
2 #![warn(rust_2018_idioms)]
3 
4 extern crate test;
5 
6 use bytes::Buf;
7 use test::Bencher;
8 
9 /// Dummy Buf implementation
10 struct TestBuf {
11     buf: &'static [u8],
12     readlens: &'static [usize],
13     init_pos: usize,
14     pos: usize,
15     readlen_pos: usize,
16     readlen: usize,
17 }
18 impl TestBuf {
new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBuf19     fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBuf {
20         let mut buf = TestBuf {
21             buf,
22             readlens,
23             init_pos,
24             pos: 0,
25             readlen_pos: 0,
26             readlen: 0,
27         };
28         buf.reset();
29         buf
30     }
reset(&mut self)31     fn reset(&mut self) {
32         self.pos = self.init_pos;
33         self.readlen_pos = 0;
34         self.next_readlen();
35     }
36     /// Compute the length of the next read :
37     /// - use the next value specified in readlens (capped by remaining) if any
38     /// - else the remaining
next_readlen(&mut self)39     fn next_readlen(&mut self) {
40         self.readlen = self.buf.len() - self.pos;
41         if let Some(readlen) = self.readlens.get(self.readlen_pos) {
42             self.readlen = std::cmp::min(self.readlen, *readlen);
43             self.readlen_pos += 1;
44         }
45     }
46 }
47 impl Buf for TestBuf {
remaining(&self) -> usize48     fn remaining(&self) -> usize {
49         return self.buf.len() - self.pos;
50     }
advance(&mut self, cnt: usize)51     fn advance(&mut self, cnt: usize) {
52         self.pos += cnt;
53         assert!(self.pos <= self.buf.len());
54         self.next_readlen();
55     }
bytes(&self) -> &[u8]56     fn bytes(&self) -> &[u8] {
57         if self.readlen == 0 {
58             Default::default()
59         } else {
60             &self.buf[self.pos..self.pos + self.readlen]
61         }
62     }
63 }
64 
65 /// Dummy Buf implementation
66 ///  version with methods forced to not be inlined (to simulate costly calls)
67 struct TestBufC {
68     inner: TestBuf,
69 }
70 impl TestBufC {
new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBufC71     fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBufC {
72         TestBufC {
73             inner: TestBuf::new(buf, readlens, init_pos),
74         }
75     }
reset(&mut self)76     fn reset(&mut self) {
77         self.inner.reset()
78     }
79 }
80 impl Buf for TestBufC {
81     #[inline(never)]
remaining(&self) -> usize82     fn remaining(&self) -> usize {
83         self.inner.remaining()
84     }
85     #[inline(never)]
advance(&mut self, cnt: usize)86     fn advance(&mut self, cnt: usize) {
87         self.inner.advance(cnt)
88     }
89     #[inline(never)]
bytes(&self) -> &[u8]90     fn bytes(&self) -> &[u8] {
91         self.inner.bytes()
92     }
93 }
94 
95 macro_rules! bench {
96     ($fname:ident, testbuf $testbuf:ident $readlens:expr, $method:ident $(,$arg:expr)*) => (
97         #[bench]
98         fn $fname(b: &mut Bencher) {
99             let mut bufs = [
100                 $testbuf::new(&[1u8; 8+0], $readlens, 0),
101                 $testbuf::new(&[1u8; 8+1], $readlens, 1),
102                 $testbuf::new(&[1u8; 8+2], $readlens, 2),
103                 $testbuf::new(&[1u8; 8+3], $readlens, 3),
104                 $testbuf::new(&[1u8; 8+4], $readlens, 4),
105                 $testbuf::new(&[1u8; 8+5], $readlens, 5),
106                 $testbuf::new(&[1u8; 8+6], $readlens, 6),
107                 $testbuf::new(&[1u8; 8+7], $readlens, 7),
108             ];
109             b.iter(|| {
110                 for i in 0..8 {
111                     bufs[i].reset();
112                     let buf: &mut dyn Buf =  &mut bufs[i]; // type erasure
113                     test::black_box(buf.$method($($arg,)*));
114                 }
115             })
116         }
117     );
118     ($fname:ident, slice, $method:ident $(,$arg:expr)*) => (
119         #[bench]
120         fn $fname(b: &mut Bencher) {
121             // buf must be long enough for one read of 8 bytes starting at pos 7
122             let arr = [1u8; 8+7];
123             b.iter(|| {
124                 for i in 0..8 {
125                     let mut buf = &arr[i..];
126                     let buf = &mut buf as &mut dyn Buf; // type erasure
127                     test::black_box(buf.$method($($arg,)*));
128                 }
129             })
130         }
131     );
132     ($fname:ident, option) => (
133         #[bench]
134         fn $fname(b: &mut Bencher) {
135             let data = [1u8; 1];
136             b.iter(|| {
137                 for _ in 0..8 {
138                     let mut buf = Some(data);
139                     let buf = &mut buf as &mut dyn Buf; // type erasure
140                     test::black_box(buf.get_u8());
141                 }
142             })
143         }
144     );
145 }
146 
147 macro_rules! bench_group {
148     ($method:ident $(,$arg:expr)*) => (
149         bench!(slice, slice, $method $(,$arg)*);
150         bench!(tbuf_1,        testbuf TestBuf  &[],  $method $(,$arg)*);
151         bench!(tbuf_1_costly, testbuf TestBufC &[],  $method $(,$arg)*);
152         bench!(tbuf_2,        testbuf TestBuf  &[1], $method $(,$arg)*);
153         bench!(tbuf_2_costly, testbuf TestBufC &[1], $method $(,$arg)*);
154         // bench!(tbuf_onebyone,        testbuf TestBuf  &[1,1,1,1,1,1,1,1], $method $(,$arg)*);
155         // bench!(tbuf_onebyone_costly, testbuf TestBufC &[1,1,1,1,1,1,1,1], $method $(,$arg)*);
156     );
157 }
158 
159 mod get_u8 {
160     use super::*;
161     bench_group!(get_u8);
162     bench!(option, option);
163 }
164 mod get_u16 {
165     use super::*;
166     bench_group!(get_u16);
167 }
168 mod get_u32 {
169     use super::*;
170     bench_group!(get_u32);
171 }
172 mod get_u64 {
173     use super::*;
174     bench_group!(get_u64);
175 }
176 mod get_f32 {
177     use super::*;
178     bench_group!(get_f32);
179 }
180 mod get_f64 {
181     use super::*;
182     bench_group!(get_f64);
183 }
184 mod get_uint24 {
185     use super::*;
186     bench_group!(get_uint, 3);
187 }
188