Skip to content

Instantly share code, notes, and snippets.

@vmx

vmx/Cargo.toml Secret

Forked from twittner/Cargo.toml
Last active February 17, 2020 16:05
Show Gist options
  • Save vmx/0dc0d981b522e2834084559faa0dcb56 to your computer and use it in GitHub Desktop.
Save vmx/0dc0d981b522e2834084559faa0dcb56 to your computer and use it in GitHub Desktop.
Vec<u8>/Bytes/custom storage cloning benchmark. Download ZIP and run `cargo bench`
[package]
name = "bench"
version = "0.1.0"
edition = "2018"
[dev-dependencies]
bytes = "0.5"
criterion = "0.3"
[[bench]]
name = "clone"
harness = false
path = "clone.rs"
#[path = "storage.rs"]
mod storage;
use bytes::{Bytes, BytesMut};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use storage::Storage;
criterion_group!(benches, clone);
criterion_main!(benches);
fn clone(c: &mut Criterion) {
let mut group = c.benchmark_group("10 clones of Vec<u8>");
for v in &[vec(10), vec(100)] {
group.bench_with_input(BenchmarkId::from_parameter(v.len()), v, |b, v| {
b.iter(|| {
for _ in 0 .. 10 {
let _ = v.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("10 clones of Bytes");
for v in &[bytes(10), bytes(100)] {
group.bench_with_input(BenchmarkId::from_parameter(v.len()), v, |b, v| {
b.iter(|| {
for _ in 0 .. 10 {
let _ = v.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("10 clones of custom storage");
for v in &[storage(10), storage(100)] {
group.bench_with_input(BenchmarkId::from_parameter(v.bytes().len()), v, |b, v| {
b.iter(|| {
for _ in 0 .. 10 {
let _ = v.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("64 bytes long Vec<u8> cloning");
for v in &[10, 100] {
group.bench_with_input(BenchmarkId::from_parameter(v), v, |b, &v| {
let data = vec(64);
b.iter(|| {
for _ in 0 .. v {
let _ = data.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("64 bytes long Bytes cloning");
for v in &[10, 100] {
group.bench_with_input(BenchmarkId::from_parameter(v), v, |b, &v| {
let data = bytes(64);
b.iter(|| {
for _ in 0 .. v {
let _ = data.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("64 bytes long custom storage cloning");
for v in &[10, 100] {
group.bench_with_input(BenchmarkId::from_parameter(v), v, |b, &v| {
let data = storage(36);
b.iter(|| {
for _ in 0 .. v {
let _ = data.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("36 bytes long Vec<u8> cloning");
for v in &[10, 100] {
group.bench_with_input(BenchmarkId::from_parameter(v), v, |b, &v| {
let data = vec(36);
b.iter(|| {
for _ in 0 .. v {
let _ = data.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("36 bytes long Bytes cloning");
for v in &[10, 100] {
group.bench_with_input(BenchmarkId::from_parameter(v), v, |b, &v| {
let data = bytes(36);
b.iter(|| {
for _ in 0 .. v {
let _ = data.clone();
}
})
});
}
group.finish();
let mut group = c.benchmark_group("36 bytes long custom storage cloning");
for v in &[10, 100] {
group.bench_with_input(BenchmarkId::from_parameter(v), v, |b, &v| {
let data = storage(36);
b.iter(|| {
for _ in 0 .. v {
let _ = data.clone();
}
})
});
}
group.finish();
}
fn vec(n: usize) -> Vec<u8> {
let mut data = Vec::with_capacity(n);
data.resize(n, 0);
data
}
fn bytes(n: usize) -> Bytes {
let mut data = BytesMut::with_capacity(n);
data.resize(n, 0);
data.freeze()
}
fn storage(n: usize) -> Storage {
let mut data: Vec<u8> = Vec::with_capacity(n);
data.resize(n, 0);
Storage::from_slice(&data)
}
use std::sync::Arc;
const MAX_INLINE: usize = 38;
#[derive(Clone)]
pub enum Storage {
/// hash is stored inline if it is smaller than MAX_INLINE
Inline(u8, [u8; MAX_INLINE]),
/// hash is stored on the heap. this must be only used if the hash is actually larger than
/// MAX_INLINE bytes to ensure an unique representation.
Heap(Arc<[u8]>),
}
impl Storage {
/// The raw bytes.
pub fn bytes(&self) -> &[u8] {
match self {
Storage::Inline(len, bytes) => &bytes[..(*len as usize)],
Storage::Heap(data) => &data,
}
}
/// creates storage from a vec. For a size up to MAX_INLINE, this will not allocate.
pub fn from_slice(slice: &[u8]) -> Self {
let len = slice.len();
if len <= MAX_INLINE {
let mut data: [u8; MAX_INLINE] = [0; MAX_INLINE];
data[..len].copy_from_slice(slice);
Storage::Inline(len as u8, data)
} else {
Storage::Heap(slice.into())
}
}
}
#[cfg(test)]
mod tests {
use super::{Storage, MAX_INLINE};
#[test]
fn struct_size() {
// this should be true for both 32 and 64 bit archs
assert_eq!(std::mem::size_of::<Storage>(), 40);
}
#[test]
fn roundtrip() {
// check that .bytes() returns whatever the storage was created with
for i in 0..((MAX_INLINE + 10) as u8) {
let data = (0..i).collect::<Vec<u8>>();
let storage = Storage::from_slice(&data);
assert_eq!(data, storage.bytes());
}
}
}
@vmx
Copy link
Author

vmx commented Feb 17, 2020

Results from my machine:

10 clones of Vec<u8>/10 time:   [197.96 ns 204.44 ns 211.01 ns]                                    
Found 6 outliers among 100 measurements (6.00%)
  6 (6.00%) high mild
10 clones of Vec<u8>/100                                                                            
                        time:   [195.64 ns 201.86 ns 207.80 ns]
Found 10 outliers among 100 measurements (10.00%)
  9 (9.00%) high mild
  1 (1.00%) high severe

10 clones of Bytes/10   time:   [144.14 ns 144.82 ns 145.53 ns]                                  
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe
10 clones of Bytes/100  time:   [147.04 ns 149.24 ns 151.50 ns]                                   
Found 10 outliers among 100 measurements (10.00%)
  9 (9.00%) high mild
  1 (1.00%) high severe

10 clones of custom storage/10                                                                             
                        time:   [17.482 ns 17.635 ns 17.813 ns]
Found 11 outliers among 100 measurements (11.00%)
  1 (1.00%) high mild
  10 (10.00%) high severe
10 clones of custom storage/100                                                                            
                        time:   [139.83 ns 141.44 ns 143.28 ns]
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe

64 bytes long Vec<u8> cloning/10                                                                            
                        time:   [178.23 ns 182.58 ns 188.14 ns]
Found 5 outliers among 100 measurements (5.00%)
  2 (2.00%) high mild
  3 (3.00%) high severe
64 bytes long Vec<u8> cloning/100                                                                             
                        time:   [1.7477 us 1.7783 us 1.8164 us]
Found 9 outliers among 100 measurements (9.00%)
  4 (4.00%) high mild
  5 (5.00%) high severe

64 bytes long Bytes cloning/10                                                                            
                        time:   [145.41 ns 146.57 ns 147.98 ns]
64 bytes long Bytes cloning/100                                                                             
                        time:   [1.4556 us 1.4672 us 1.4802 us]
Found 9 outliers among 100 measurements (9.00%)
  3 (3.00%) high mild
  6 (6.00%) high severe

64 bytes long custom storage cloning/10                                                                             
                        time:   [14.341 ns 14.453 ns 14.587 ns]
Found 11 outliers among 100 measurements (11.00%)
  2 (2.00%) low mild
  6 (6.00%) high mild
  3 (3.00%) high severe
64 bytes long custom storage cloning/100                                                                            
                        time:   [145.05 ns 145.88 ns 146.74 ns]
Found 5 outliers among 100 measurements (5.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  1 (1.00%) high severe

36 bytes long Vec<u8> cloning/10                                                                            
                        time:   [182.63 ns 186.71 ns 191.50 ns]
Found 15 outliers among 100 measurements (15.00%)
  12 (12.00%) high mild
  3 (3.00%) high severe
36 bytes long Vec<u8> cloning/100                                                                             
                        time:   [1.7918 us 1.8308 us 1.8763 us]

36 bytes long Bytes cloning/10                                                                            
                        time:   [144.13 ns 145.34 ns 146.87 ns]
Found 6 outliers among 100 measurements (6.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  4 (4.00%) high severe
36 bytes long Bytes cloning/100                                                                             
                        time:   [1.4910 us 1.5108 us 1.5329 us]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

36 bytes long custom storage cloning/10                                                                             
                        time:   [15.431 ns 15.909 ns 16.382 ns]
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe
36 bytes long custom storage cloning/100                                                                            
                        time:   [144.08 ns 145.07 ns 146.14 ns]
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment