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