| #![feature(test)] |
| #![warn(rust_2018_idioms)] |
| |
| extern crate test; |
| |
| use bytes::Buf; |
| use test::Bencher; |
| |
| /// Dummy Buf implementation |
| struct TestBuf { |
| buf: &'static [u8], |
| readlens: &'static [usize], |
| init_pos: usize, |
| pos: usize, |
| readlen_pos: usize, |
| readlen: usize, |
| } |
| impl TestBuf { |
| fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBuf { |
| let mut buf = TestBuf { |
| buf, |
| readlens, |
| init_pos, |
| pos: 0, |
| readlen_pos: 0, |
| readlen: 0, |
| }; |
| buf.reset(); |
| buf |
| } |
| fn reset(&mut self) { |
| self.pos = self.init_pos; |
| self.readlen_pos = 0; |
| self.next_readlen(); |
| } |
| /// Compute the length of the next read : |
| /// - use the next value specified in readlens (capped by remaining) if any |
| /// - else the remaining |
| fn next_readlen(&mut self) { |
| self.readlen = self.buf.len() - self.pos; |
| if let Some(readlen) = self.readlens.get(self.readlen_pos) { |
| self.readlen = std::cmp::min(self.readlen, *readlen); |
| self.readlen_pos += 1; |
| } |
| } |
| } |
| impl Buf for TestBuf { |
| fn remaining(&self) -> usize { |
| self.buf.len() - self.pos |
| } |
| fn advance(&mut self, cnt: usize) { |
| self.pos += cnt; |
| assert!(self.pos <= self.buf.len()); |
| self.next_readlen(); |
| } |
| fn chunk(&self) -> &[u8] { |
| if self.readlen == 0 { |
| Default::default() |
| } else { |
| &self.buf[self.pos..self.pos + self.readlen] |
| } |
| } |
| } |
| |
| /// Dummy Buf implementation |
| /// version with methods forced to not be inlined (to simulate costly calls) |
| struct TestBufC { |
| inner: TestBuf, |
| } |
| impl TestBufC { |
| fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBufC { |
| TestBufC { |
| inner: TestBuf::new(buf, readlens, init_pos), |
| } |
| } |
| fn reset(&mut self) { |
| self.inner.reset() |
| } |
| } |
| impl Buf for TestBufC { |
| #[inline(never)] |
| fn remaining(&self) -> usize { |
| self.inner.remaining() |
| } |
| #[inline(never)] |
| fn advance(&mut self, cnt: usize) { |
| self.inner.advance(cnt) |
| } |
| #[inline(never)] |
| fn chunk(&self) -> &[u8] { |
| self.inner.chunk() |
| } |
| } |
| |
| macro_rules! bench { |
| ($fname:ident, testbuf $testbuf:ident $readlens:expr, $method:ident $(,$arg:expr)*) => ( |
| #[bench] |
| fn $fname(b: &mut Bencher) { |
| let mut bufs = [ |
| $testbuf::new(&[1u8; 8+0], $readlens, 0), |
| $testbuf::new(&[1u8; 8+1], $readlens, 1), |
| $testbuf::new(&[1u8; 8+2], $readlens, 2), |
| $testbuf::new(&[1u8; 8+3], $readlens, 3), |
| $testbuf::new(&[1u8; 8+4], $readlens, 4), |
| $testbuf::new(&[1u8; 8+5], $readlens, 5), |
| $testbuf::new(&[1u8; 8+6], $readlens, 6), |
| $testbuf::new(&[1u8; 8+7], $readlens, 7), |
| ]; |
| b.iter(|| { |
| for i in 0..8 { |
| bufs[i].reset(); |
| let buf: &mut dyn Buf = &mut bufs[i]; // type erasure |
| test::black_box(buf.$method($($arg,)*)); |
| } |
| }) |
| } |
| ); |
| ($fname:ident, slice, $method:ident $(,$arg:expr)*) => ( |
| #[bench] |
| fn $fname(b: &mut Bencher) { |
| // buf must be long enough for one read of 8 bytes starting at pos 7 |
| let arr = [1u8; 8+7]; |
| b.iter(|| { |
| for i in 0..8 { |
| let mut buf = &arr[i..]; |
| let buf = &mut buf as &mut dyn Buf; // type erasure |
| test::black_box(buf.$method($($arg,)*)); |
| } |
| }) |
| } |
| ); |
| ($fname:ident, option) => ( |
| #[bench] |
| fn $fname(b: &mut Bencher) { |
| let data = [1u8; 1]; |
| b.iter(|| { |
| for _ in 0..8 { |
| let mut buf = Some(data); |
| let buf = &mut buf as &mut dyn Buf; // type erasure |
| test::black_box(buf.get_u8()); |
| } |
| }) |
| } |
| ); |
| } |
| |
| macro_rules! bench_group { |
| ($method:ident $(,$arg:expr)*) => ( |
| bench!(slice, slice, $method $(,$arg)*); |
| bench!(tbuf_1, testbuf TestBuf &[], $method $(,$arg)*); |
| bench!(tbuf_1_costly, testbuf TestBufC &[], $method $(,$arg)*); |
| bench!(tbuf_2, testbuf TestBuf &[1], $method $(,$arg)*); |
| bench!(tbuf_2_costly, testbuf TestBufC &[1], $method $(,$arg)*); |
| // bench!(tbuf_onebyone, testbuf TestBuf &[1,1,1,1,1,1,1,1], $method $(,$arg)*); |
| // bench!(tbuf_onebyone_costly, testbuf TestBufC &[1,1,1,1,1,1,1,1], $method $(,$arg)*); |
| ); |
| } |
| |
| mod get_u8 { |
| use super::*; |
| bench_group!(get_u8); |
| } |
| mod get_u16 { |
| use super::*; |
| bench_group!(get_u16); |
| } |
| mod get_u32 { |
| use super::*; |
| bench_group!(get_u32); |
| } |
| mod get_u64 { |
| use super::*; |
| bench_group!(get_u64); |
| } |
| mod get_f32 { |
| use super::*; |
| bench_group!(get_f32); |
| } |
| mod get_f64 { |
| use super::*; |
| bench_group!(get_f64); |
| } |
| mod get_uint24 { |
| use super::*; |
| bench_group!(get_uint, 3); |
| } |