mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-25 00:00:22 +02:00
Optimize Bytes::slice for short slices (#136)
Slice operation should return inline when possible It is cheaper than atomic increment/decrement. Before this patch: ``` test slice_avg_le_inline_from_arc ... bench: 28,582 ns/iter (+/- 3,880) test slice_empty ... bench: 8,797 ns/iter (+/- 1,325) test slice_large_le_inline_from_arc ... bench: 27,684 ns/iter (+/- 5,920) test slice_short_from_arc ... bench: 27,439 ns/iter (+/- 5,783) ``` After this patch: ``` test slice_avg_le_inline_from_arc ... bench: 18,872 ns/iter (+/- 2,937) test slice_empty ... bench: 9,136 ns/iter (+/- 1,908) test slice_large_le_inline_from_arc ... bench: 18,052 ns/iter (+/- 2,981) test slice_short_from_arc ... bench: 18,200 ns/iter (+/- 2,534) ```
This commit is contained in:
committed by
Carl Lerche
parent
544997958f
commit
b9ccd2a866
+41
-8
@@ -154,19 +154,52 @@ fn from_long_slice(b: &mut Bencher) {
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn slice_empty(b: &mut Bencher) {
|
fn slice_empty(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
// Use empty vec to avoid measure of allocation/deallocation
|
let b = Bytes::from(vec![17; 1024]).clone();
|
||||||
let bytes = Bytes::from(Vec::new());
|
for i in 0..1000 {
|
||||||
(bytes.slice(0, 0), bytes)
|
test::black_box(b.slice(i % 100, i % 100));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn slice_not_empty(b: &mut Bencher) {
|
fn slice_short_from_arc(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let b = Bytes::from(b"aabbccddeeffgghh".to_vec());
|
// `clone` is to convert to ARC
|
||||||
for _ in 0..1024 {
|
let b = Bytes::from(vec![17; 1024]).clone();
|
||||||
test::black_box(b.slice(3, 5));
|
for i in 0..1000 {
|
||||||
test::black_box(&b);
|
test::black_box(b.slice(1, 2 + i % 10));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep in sync with bytes.rs
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
const INLINE_CAP: usize = 4 * 8 - 1;
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
const INLINE_CAP: usize = 4 * 4 - 1;
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn slice_avg_le_inline_from_arc(b: &mut Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
// `clone` is to convert to ARC
|
||||||
|
let b = Bytes::from(vec![17; 1024]).clone();
|
||||||
|
for i in 0..1000 {
|
||||||
|
// [1, INLINE_CAP]
|
||||||
|
let len = 1 + i % (INLINE_CAP - 1);
|
||||||
|
test::black_box(b.slice(i % 10, i % 10 + len));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn slice_large_le_inline_from_arc(b: &mut Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
// `clone` is to convert to ARC
|
||||||
|
let b = Bytes::from(vec![17; 1024]).clone();
|
||||||
|
for i in 0..1000 {
|
||||||
|
// [INLINE_CAP - 10, INLINE_CAP]
|
||||||
|
let len = INLINE_CAP - 9 + i % 10;
|
||||||
|
test::black_box(b.slice(i % 10, i % 10 + len));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -492,9 +492,11 @@ impl Bytes {
|
|||||||
/// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing
|
/// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing
|
||||||
/// will panic.
|
/// will panic.
|
||||||
pub fn slice(&self, begin: usize, end: usize) -> Bytes {
|
pub fn slice(&self, begin: usize, end: usize) -> Bytes {
|
||||||
if begin == end {
|
assert!(begin <= end);
|
||||||
assert!(begin <= self.len());
|
assert!(end <= self.len());
|
||||||
return Bytes::new();
|
|
||||||
|
if end - begin <= INLINE_CAP {
|
||||||
|
return Bytes::from(&self[begin..end]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = self.clone();
|
let mut ret = self.clone();
|
||||||
@@ -1430,7 +1432,9 @@ impl<'a> From<&'a [u8]> for BytesMut {
|
|||||||
fn from(src: &'a [u8]) -> BytesMut {
|
fn from(src: &'a [u8]) -> BytesMut {
|
||||||
let len = src.len();
|
let len = src.len();
|
||||||
|
|
||||||
if len <= INLINE_CAP {
|
if len == 0 {
|
||||||
|
BytesMut::new()
|
||||||
|
} else if len <= INLINE_CAP {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut inner: Inner = mem::uninitialized();
|
let mut inner: Inner = mem::uninitialized();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user