Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various changes (hopefully improvements) #12

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6f392c3
Fix decode output buffer length calculation.
ggriffiniii Feb 11, 2020
a811901
Upgrade criterion and test a variety of byte lengths.
ggriffiniii Feb 11, 2020
50f9d46
Fix compiler warnings.
ggriffiniii Feb 11, 2020
a5898da
Don't return an error when decoding an empty slice.
ggriffiniii Feb 11, 2020
59e5b28
Add a basic roundtrip property test.
ggriffiniii Feb 11, 2020
2605d11
Reorganize decode into submodules.
ggriffiniii Feb 14, 2020
ca46185
migrate hex_check from sse to avx2
ggriffiniii Feb 14, 2020
21cacdd
Modify the avx2::hex_check
ggriffiniii Feb 14, 2020
0de392a
Modify decode to check the input as decoding rather than as a separat…
ggriffiniii Feb 14, 2020
fcb43b2
Faster avx2 is_valid implementation
ggriffiniii Feb 14, 2020
ad34b9e
New avx2 decode algorithm.
ggriffiniii Feb 14, 2020
4d1af86
Update the name of the check bench to reflect it's now avx2 rather th…
ggriffiniii Feb 14, 2020
2773009
New encode algorithm
ggriffiniii Feb 16, 2020
e5c516f
hex_string doesn't need to return an Result
ggriffiniii Feb 16, 2020
1558c78
Add sse decoding
ggriffiniii Feb 17, 2020
b7e178b
Add features for avx2 and sse41
ggriffiniii Feb 18, 2020
ae677f1
Add a decode function that returns a Vec<u8> and a couple proptests to
ggriffiniii Feb 18, 2020
9bd7c34
Rename functions removing the hex prefix as it stutters with the name…
ggriffiniii Feb 18, 2020
124a106
Accept input as AsRef<[u8]> to be more convenient.
ggriffiniii Feb 18, 2020
8d8ace9
Remove the check bench and implementations.
ggriffiniii Feb 18, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ exclude = [
"fuzz/*"
]

[features]
default = ["avx2", "sse41"]
bench = []
avx2 = []
sse41 = []

[dev-dependencies]
criterion = "0.2"
criterion = "0.3"
rustc-hex = "1.0"
hex = "0.3.2"
hex = "0.4"
proptest = "0.8"
rand = "0.7.3"

[[bench]]
name = "hex"
harness = false


[[bench]]
name = "check"
harness = false
required-features = ["bench", "avx2", "sse41"]
38 changes: 0 additions & 38 deletions benches/check.rs

This file was deleted.

212 changes: 133 additions & 79 deletions benches/hex.rs
Original file line number Diff line number Diff line change
@@ -1,91 +1,145 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use faster_hex::{
hex_decode, hex_decode_fallback, hex_decode_unchecked, hex_encode_fallback, hex_string,
decode_fallback, decode_to_slice, decode_to_slice_unchecked, decode_unchecked_fallback, encode,
encode_fallback,
};
use rustc_hex::{FromHex, ToHex};
use std::time::Duration;

fn bench(c: &mut Criterion) {
let s = "Day before yesterday I saw a rabbit, and yesterday a deer, and today, you.";

c.bench_function("bench_rustc_hex_encode", move |b| {
b.iter(|| {
let ret = s.as_bytes().to_hex();
black_box(ret);
})
});

c.bench_function("bench_hex_encode", move |b| {
b.iter(|| {
let ret = hex::encode(s);
black_box(ret);
})
});

c.bench_function("bench_faster_hex_encode", move |b| {
b.iter(|| {
let ret = hex_string(s.as_bytes()).unwrap();
black_box(ret);
})
});

c.bench_function("bench_faster_hex_encode_fallback", move |b| {
b.iter(|| {
let bytes = s.as_bytes();
let mut buffer = vec![0; bytes.len() * 2];
let ret = hex_encode_fallback(bytes, &mut buffer);
black_box(ret);
})
});
const BYTE_SIZES: [usize; 5] = [2, 16, 32, 128, 4096];

c.bench_function("bench_rustc_hex_decode", move |b| {
let hex = s.as_bytes().to_hex();
b.iter(|| {
let ret: Vec<u8> = hex.from_hex().unwrap();
black_box(ret);
})
});
fn rand_slice(size: usize) -> Vec<u8> {
use rand::Rng;
let mut input: Vec<u8> = vec![0; size];
rand::thread_rng().fill(input.as_mut_slice());
input
}

c.bench_function("bench_hex_decode", move |b| {
let hex = s.as_bytes().to_hex();
b.iter(|| {
let ret: Vec<u8> = hex::decode(&hex).unwrap();
black_box(ret);
})
});
fn rand_hex_encoded(size: usize) -> String {
use rand::seq::SliceRandom;
String::from_utf8(
std::iter::repeat(())
.map(|_| *b"0123456789abcdef".choose(&mut rand::thread_rng()).unwrap())
.take(size)
.collect(),
)
.unwrap()
}

c.bench_function("bench_faster_hex_decode", move |b| {
let hex = hex_string(s.as_bytes()).unwrap();
let len = s.as_bytes().len();
b.iter(|| {
let mut dst = Vec::with_capacity(len);
dst.resize(len, 0);
let ret = hex_decode(hex.as_bytes(), &mut dst);
black_box(ret);
})
});
fn bench(c: &mut Criterion) {
let mut encode_group = c.benchmark_group("encode");
for size in &BYTE_SIZES[..] {
encode_group.throughput(Throughput::Bytes(*size as u64));
encode_group.bench_with_input(BenchmarkId::new("rustc", size), size, |b, &size| {
let input = rand_slice(size);
b.iter(|| {
let ret = input.to_hex();
black_box(ret);
})
});
encode_group.bench_with_input(BenchmarkId::new("hex", size), size, |b, &size| {
let input = rand_slice(size);
b.iter(|| {
let ret = hex::encode(&input);
black_box(ret);
})
});
encode_group.bench_with_input(BenchmarkId::new("faster_hex", size), size, |b, &size| {
let input = rand_slice(size);
b.iter(|| {
let ret = encode(&input);
black_box(ret);
})
});
encode_group.bench_with_input(
BenchmarkId::new("faster_hex_fallback", size),
size,
|b, &size| {
let input = rand_slice(size);
let mut buffer = vec![0; input.len() * 2];
b.iter(|| {
let ret = encode_fallback(&input, buffer.as_mut_slice());
black_box(ret);
})
},
);
}
encode_group.finish();

c.bench_function("bench_faster_hex_decode_unchecked", move |b| {
let hex = hex_string(s.as_bytes()).unwrap();
let len = s.as_bytes().len();
b.iter(|| {
let mut dst = Vec::with_capacity(len);
dst.resize(len, 0);
let ret = hex_decode_unchecked(hex.as_bytes(), &mut dst);
black_box(ret);
})
});
let mut decode_group = c.benchmark_group("decode");
for size in &BYTE_SIZES[..] {
decode_group.throughput(Throughput::Bytes(*size as u64));
decode_group.bench_with_input(BenchmarkId::new("rustc", size), size, |b, &size| {
let hex_input = rand_hex_encoded(size);
b.iter(|| {
let ret: Vec<u8> = hex_input.from_hex().unwrap();
black_box(ret);
})
});
decode_group.bench_with_input(BenchmarkId::new("hex", size), size, |b, &size| {
let hex_input = rand_hex_encoded(size);
b.iter(|| {
let ret: Vec<u8> = hex::decode(&hex_input).unwrap();
black_box(ret);
})
});
decode_group.bench_with_input(BenchmarkId::new("faster_hex", size), size, |b, &size| {
let hex_input = rand_hex_encoded(size);
let mut dst = vec![0; size / 2];
b.iter(|| {
let ret = decode_to_slice(hex_input.as_bytes(), &mut dst).unwrap();
black_box(ret);
})
});
decode_group.bench_with_input(
BenchmarkId::new("faster_hex_unchecked", size),
size,
|b, &size| {
let hex_input = rand_hex_encoded(size);
let mut dst = vec![0; size / 2];
b.iter(|| {
let ret = decode_to_slice_unchecked(hex_input.as_bytes(), &mut dst);
black_box(ret);
})
},
);
decode_group.bench_with_input(
BenchmarkId::new("faster_hex_fallback", size),
size,
|b, &size| {
let hex_input = rand_hex_encoded(size);
let mut dst = vec![0; size / 2];
b.iter(|| {
let ret = decode_fallback(hex_input.as_bytes(), &mut dst).unwrap();
black_box(ret);
})
},
);
decode_group.bench_with_input(
BenchmarkId::new("faster_hex_unchecked_fallback", size),
size,
|b, &size| {
let hex_input = rand_hex_encoded(size);
let mut dst = vec![0; size / 2];
b.iter(|| {
let ret = decode_unchecked_fallback(hex_input.as_bytes(), &mut dst);
black_box(ret);
})
},
);
}
decode_group.finish();
}

c.bench_function("bench_faster_hex_decode_fallback", move |b| {
let hex = hex_string(s.as_bytes()).unwrap();
let len = s.as_bytes().len();
b.iter(|| {
let mut dst = Vec::with_capacity(len);
dst.resize(len, 0);
let ret = hex_decode_fallback(hex.as_bytes(), &mut dst);
black_box(ret);
})
});
fn quicker() -> Criterion {
Criterion::default()
.warm_up_time(Duration::from_millis(500))
.measurement_time(Duration::from_secs(1))
}

criterion_group!(benches, bench);
criterion_group! {
name = benches;
config = quicker();
targets = bench
}
criterion_main!(benches);
Loading