1#![feature(test)]
2#![warn(rust_2018_idioms)]
3
4extern crate test;
5
6use bytes::Buf;
7use test::Bencher;
8
9/// Dummy Buf implementation
10struct TestBuf {
11 buf: &'static [u8],
12 readlens: &'static [usize],
13 init_pos: usize,
14 pos: usize,
15 readlen_pos: usize,
16 readlen: usize,
17}
18impl TestBuf {
19 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 }
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
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}
47impl Buf for TestBuf {
48 fn remaining(&self) -> usize {
49 self.buf.len() - self.pos
50 }
51 fn advance(&mut self, cnt: usize) {
52 self.pos += cnt;
53 assert!(self.pos <= self.buf.len());
54 self.next_readlen();
55 }
56 fn chunk(&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)
67struct TestBufC {
68 inner: TestBuf,
69}
70impl TestBufC {
71 fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBufC {
72 TestBufC {
73 inner: TestBuf::new(buf, readlens, init_pos),
74 }
75 }
76 fn reset(&mut self) {
77 self.inner.reset()
78 }
79}
80impl Buf for TestBufC {
81 #[inline(never)]
82 fn remaining(&self) -> usize {
83 self.inner.remaining()
84 }
85 #[inline(never)]
86 fn advance(&mut self, cnt: usize) {
87 self.inner.advance(cnt)
88 }
89 #[inline(never)]
90 fn chunk(&self) -> &[u8] {
91 self.inner.chunk()
92 }
93}
94
95macro_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
147macro_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
159mod get_u8 {
160 use super::*;
161 bench_group!(get_u8);
162}
163mod get_u16 {
164 use super::*;
165 bench_group!(get_u16);
166}
167mod get_u32 {
168 use super::*;
169 bench_group!(get_u32);
170}
171mod get_u64 {
172 use super::*;
173 bench_group!(get_u64);
174}
175mod get_f32 {
176 use super::*;
177 bench_group!(get_f32);
178}
179mod get_f64 {
180 use super::*;
181 bench_group!(get_f64);
182}
183mod get_uint24 {
184 use super::*;
185 bench_group!(get_uint, 3);
186}
187