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 { |
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 | } |
47 | impl 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) |
67 | struct TestBufC { |
68 | inner: TestBuf, |
69 | } |
70 | impl 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 | } |
80 | impl 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 | |
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 | } |
163 | mod get_u16 { |
164 | use super::*; |
165 | bench_group!(get_u16); |
166 | } |
167 | mod get_u32 { |
168 | use super::*; |
169 | bench_group!(get_u32); |
170 | } |
171 | mod get_u64 { |
172 | use super::*; |
173 | bench_group!(get_u64); |
174 | } |
175 | mod get_f32 { |
176 | use super::*; |
177 | bench_group!(get_f32); |
178 | } |
179 | mod get_f64 { |
180 | use super::*; |
181 | bench_group!(get_f64); |
182 | } |
183 | mod get_uint24 { |
184 | use super::*; |
185 | bench_group!(get_uint, 3); |
186 | } |
187 | |