Skip to content

Commit adbe03b

Browse files
committed
Update tests & benchmarks to the non-generic AVX2Encoder
1 parent c98293b commit adbe03b

File tree

6 files changed

+98
-37
lines changed

6 files changed

+98
-37
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ structopt = "0.3.21"
2727
# test fixtures for engine tests
2828
rstest = "0.11.0"
2929
rstest_reuse = "0.1.3"
30+
lazy_static = "1.4.0"
3031

3132
[features]
3233
default = ["std"]

benches/avx2benchmarks.rs

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,25 @@ extern crate base64;
33
extern crate criterion;
44
extern crate rand;
55

6+
#[macro_use]
7+
extern crate lazy_static;
8+
9+
use std::ops::Deref;
10+
611
use base64::display;
712
use base64::{
813
decode_engine, decode_engine_slice, decode_engine_vec, encode_engine, encode_engine_slice,
914
encode_engine_string, write, engine::DEFAULT_ENGINE,
1015
};
1116

12-
use base64::engine::avx2::{AVX2Encoder, AVX2Config, Standard};
17+
use base64::engine::avx2::{AVX2Encoder, AVX2Config};
1318
use criterion::{black_box, Bencher, BenchmarkId, Criterion, Throughput};
1419
use rand::{FromEntropy, Rng};
1520
use std::io::{self, Read, Write};
1621

17-
const AVX2_ENGINE: AVX2Encoder<Standard> = AVX2Encoder::from(AVX2Config::new());
22+
lazy_static! {
23+
static ref AVX2_ENGINE: AVX2Encoder = AVX2Encoder::from_standard(AVX2Config::new());
24+
}
1825

1926
fn do_decode_bench(b: &mut Bencher, &size: &usize) {
2027
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
@@ -29,10 +36,10 @@ fn do_decode_bench(b: &mut Bencher, &size: &usize) {
2936
fn do_decode_bench_avx(b: &mut Bencher, &size: &usize) {
3037
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
3138
fill(&mut v);
32-
let encoded = encode_engine(&v, &AVX2_ENGINE);
39+
let encoded = encode_engine(&v, AVX2_ENGINE.deref());
3340

3441
b.iter(|| {
35-
let orig = decode_engine(&encoded, &AVX2_ENGINE);
42+
let orig = decode_engine(&encoded, AVX2_ENGINE.deref());
3643
black_box(&orig);
3744
});
3845
}
@@ -53,11 +60,11 @@ fn do_decode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
5360
fn do_decode_bench_reuse_buf_avx(b: &mut Bencher, &size: &usize) {
5461
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
5562
fill(&mut v);
56-
let encoded = encode_engine(&v, &AVX2_ENGINE);
63+
let encoded = encode_engine(&v, AVX2_ENGINE.deref());
5764

5865
let mut buf = Vec::new();
5966
b.iter(|| {
60-
decode_engine_vec(&encoded, &mut buf, &AVX2_ENGINE).unwrap();
67+
decode_engine_vec(&encoded, &mut buf, AVX2_ENGINE.deref()).unwrap();
6168
black_box(&buf);
6269
buf.clear();
6370
});
@@ -79,12 +86,12 @@ fn do_decode_bench_slice(b: &mut Bencher, &size: &usize) {
7986
fn do_decode_bench_slice_avx(b: &mut Bencher, &size: &usize) {
8087
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
8188
fill(&mut v);
82-
let encoded = encode_engine(&v, &AVX2_ENGINE);
89+
let encoded = encode_engine(&v, AVX2_ENGINE.deref());
8390

8491
let mut buf = Vec::new();
8592
buf.resize(size, 0);
8693
b.iter(|| {
87-
decode_engine_slice(&encoded, &mut buf, &AVX2_ENGINE).unwrap();
94+
decode_engine_slice(&encoded, &mut buf, AVX2_ENGINE.deref()).unwrap();
8895
black_box(&buf);
8996
});
9097
}
@@ -110,15 +117,15 @@ fn do_decode_bench_stream(b: &mut Bencher, &size: &usize) {
110117
fn do_decode_bench_stream_avx(b: &mut Bencher, &size: &usize) {
111118
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
112119
fill(&mut v);
113-
let encoded = encode_engine(&v, &AVX2_ENGINE);
120+
let encoded = encode_engine(&v, AVX2_ENGINE.deref());
114121

115122
let mut buf = Vec::new();
116123
buf.resize(size, 0);
117124
buf.truncate(0);
118125

119126
b.iter(|| {
120127
let mut cursor = io::Cursor::new(&encoded[..]);
121-
let mut decoder = base64::read::DecoderReader::from(&mut cursor, &AVX2_ENGINE);
128+
let mut decoder = base64::read::DecoderReader::from(&mut cursor, AVX2_ENGINE.deref());
122129
decoder.read_to_end(&mut buf).unwrap();
123130
buf.clear();
124131
black_box(&buf);
@@ -138,7 +145,7 @@ fn do_encode_bench_avx(b: &mut Bencher, &size: &usize) {
138145
let mut v: Vec<u8> = Vec::with_capacity(size);
139146
fill(&mut v);
140147
b.iter(|| {
141-
let e = encode_engine(&v, &AVX2_ENGINE);
148+
let e = encode_engine(&v, AVX2_ENGINE.deref());
142149
black_box(&e);
143150
});
144151
}
@@ -156,7 +163,7 @@ fn do_encode_bench_display_avx(b: &mut Bencher, &size: &usize) {
156163
let mut v: Vec<u8> = Vec::with_capacity(size);
157164
fill(&mut v);
158165
b.iter(|| {
159-
let e = format!("{}", display::Base64Display::from(&v, &AVX2_ENGINE));
166+
let e = format!("{}", display::Base64Display::from(&v, AVX2_ENGINE.deref()));
160167
black_box(&e);
161168
});
162169
}
@@ -176,7 +183,7 @@ fn do_encode_bench_reuse_buf_avx(b: &mut Bencher, &size: &usize) {
176183
fill(&mut v);
177184
let mut buf = String::new();
178185
b.iter(|| {
179-
encode_engine_string(&v, &mut buf, &AVX2_ENGINE);
186+
encode_engine_string(&v, &mut buf, AVX2_ENGINE.deref());
180187
buf.clear();
181188
});
182189
}
@@ -199,7 +206,7 @@ fn do_encode_bench_slice_avx(b: &mut Bencher, &size: &usize) {
199206
// conservative estimate of encoded size
200207
buf.resize(v.len() * 2, 0);
201208
b.iter(|| {
202-
encode_engine_slice(&v, &mut buf, &AVX2_ENGINE);
209+
encode_engine_slice(&v, &mut buf, AVX2_ENGINE.deref());
203210
});
204211
}
205212

@@ -225,7 +232,7 @@ fn do_encode_bench_stream_avx(b: &mut Bencher, &size: &usize) {
225232
buf.reserve(size * 2);
226233
b.iter(|| {
227234
buf.clear();
228-
let mut stream_enc = write::EncoderWriter::from(&mut buf, &AVX2_ENGINE);
235+
let mut stream_enc = write::EncoderWriter::from(&mut buf, AVX2_ENGINE.deref());
229236
stream_enc.write_all(&v).unwrap();
230237
stream_enc.flush().unwrap();
231238
});
@@ -248,7 +255,7 @@ fn do_encode_bench_string_stream_avx(b: &mut Bencher, &size: &usize) {
248255
fill(&mut v);
249256

250257
b.iter(|| {
251-
let mut stream_enc = write::EncoderStringWriter::from(&AVX2_ENGINE);
258+
let mut stream_enc = write::EncoderStringWriter::from(AVX2_ENGINE.deref());
252259
stream_enc.write_all(&v).unwrap();
253260
stream_enc.flush().unwrap();
254261
let _ = stream_enc.into_inner();
@@ -276,7 +283,7 @@ fn do_encode_bench_string_reuse_buf_stream_avx(b: &mut Bencher, &size: &usize) {
276283
let mut buf = String::new();
277284
b.iter(|| {
278285
buf.clear();
279-
let mut stream_enc = write::EncoderStringWriter::from_consumer(&mut buf, &AVX2_ENGINE);
286+
let mut stream_enc = write::EncoderStringWriter::from_consumer(&mut buf, AVX2_ENGINE.deref());
280287
stream_enc.write_all(&v).unwrap();
281288
stream_enc.flush().unwrap();
282289
let _ = stream_enc.into_inner();
@@ -547,11 +554,63 @@ fn decode_benchmarks(c: &mut Criterion, label: &str, byte_sizes: &[usize]) {
547554

548555
}
549556

557+
fn do_align_bench(b: &mut Bencher, &size: &usize) {
558+
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4 + 32);
559+
fill(&mut v);
560+
561+
let (pre, aligned_u32, post) = unsafe {
562+
v.align_to_mut::<u32>()
563+
};
564+
let aligned: &[u8] = unsafe {
565+
core::mem::transmute(aligned_u32)
566+
};
567+
assert!(pre.len() == 0);
568+
assert!(post.len() == 0);
569+
570+
571+
let encoded = encode_engine(&v, AVX2_ENGINE.deref());
572+
573+
let mut buf = Vec::new();
574+
buf.resize(size, 0);
575+
b.iter(|| {
576+
decode_engine_slice(&encoded, &mut buf, AVX2_ENGINE.deref()).unwrap();
577+
black_box(&buf);
578+
});
579+
}
580+
fn do_unalign_bench(b: &mut Bencher, &size: &usize) {
581+
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4 + 32);
582+
fill(&mut v);
583+
584+
let encoded = encode_engine(&v[5..], AVX2_ENGINE.deref());
585+
586+
let mut buf = Vec::new();
587+
buf.resize(size, 0);
588+
b.iter(|| {
589+
decode_engine_slice(&encoded, &mut buf, AVX2_ENGINE.deref()).unwrap();
590+
black_box(&buf);
591+
});
592+
}
593+
594+
fn align_benchmarks(c: &mut Criterion, label: &str, byte_sizes: &[usize]) {
595+
let mut group = c.benchmark_group(label);
596+
for size in byte_sizes {
597+
group
598+
.warm_up_time(std::time::Duration::from_millis(500))
599+
.measurement_time(std::time::Duration::from_secs(3))
600+
.throughput(Throughput::Bytes(*size as u64))
601+
.bench_with_input(BenchmarkId::new("aligned", size), size, do_align_bench)
602+
.bench_with_input(BenchmarkId::new("unaligned", size), size, do_unalign_bench);
603+
}
604+
group.finish();
605+
}
606+
550607
fn bench(c: &mut Criterion) {
551608
encode_benchmarks(c, "encode_small_input", &BYTE_SIZES[..]);
552609
encode_benchmarks(c, "encode_large_input", &LARGE_BYTE_SIZES[..]);
553610
decode_benchmarks(c, "decode_small_input", &BYTE_SIZES[..]);
554611
decode_benchmarks(c, "decode_large_input", &LARGE_BYTE_SIZES[..]);
612+
613+
align_benchmarks(c, "align_benchmark", &LARGE_BYTE_SIZES[..]);
555614
}
556615

557616
criterion_group!(benches, bench);

src/engine/tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -962,20 +962,20 @@ mod avx2_tests {
962962
pub(super) struct AVX2Wrapper {}
963963

964964
impl EngineWrapper for AVX2Wrapper {
965-
type Engine = avx2::AVX2Encoder<avx2::Standard>;
965+
type Engine = avx2::AVX2Encoder;
966966

967967
fn standard() -> Self::Engine {
968-
avx2::AVX2Encoder::from(avx2::AVX2Config::default())
968+
avx2::AVX2Encoder::from_standard(avx2::AVX2Config::default())
969969
}
970970

971971
fn standard_forgiving() -> Self::Engine {
972-
avx2::AVX2Encoder::from(avx2::AVX2Config::default()
972+
avx2::AVX2Encoder::from_standard(avx2::AVX2Config::default()
973973
.with_decode_allow_trailing_bits(true))
974974
}
975975

976976
fn random<R: Rng>(_rng: &mut R) -> Self::Engine {
977977
// The avx alg can't handle custom alphabets yet
978-
avx2::AVX2Encoder::from(avx2::AVX2Config::default())
978+
avx2::AVX2Encoder::from_standard(avx2::AVX2Config::default())
979979
}
980980

981981
fn random_alphabet<R: Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine {

tests/decode.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,17 @@ fn decode_imap() {
8989
mod avx2test {
9090
use super::*;
9191

92-
use base64::engine::avx2::{AVX2Encoder, AVX2Config, Standard};
93-
const AVX_ENGINE: AVX2Encoder<Standard> = AVX2Encoder::from(AVX2Config::new());
92+
use base64::engine::avx2::{AVX2Encoder, AVX2Config};
9493

9594
#[test]
9695
fn decode_long() {
96+
let engine = AVX2Encoder::from_standard(AVX2Config::new());
9797
let out = decode_engine(
9898
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0\
9999
BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+Ag\
100100
YKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHC\
101101
w8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==",
102-
&AVX_ENGINE
102+
&engine
103103
).unwrap();
104104
println!("{:?}", out);
105105
for (a,b) in out.iter().enumerate() {
@@ -109,22 +109,24 @@ mod avx2test {
109109

110110
#[test]
111111
fn decode_long_err() {
112+
let engine = AVX2Encoder::from_standard(AVX2Config::new());
112113
let out = decode_engine(
113114
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0.P0\
114115
BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+Ag\
115116
YKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHC\
116117
w8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==",
117-
&AVX_ENGINE
118+
&engine
118119
).unwrap_err();
119120

120121
assert_eq!(DecodeError::InvalidByte(83, '.' as u8), out);
121122
}
122123

123124
#[test]
124125
fn decode_reject_null() {
126+
let engine = AVX2Encoder::from_standard(AVX2Config::new());
125127
assert_eq!(
126128
DecodeError::InvalidByte(3, 0x0),
127-
decode_engine("YWx\0pY2U==", &AVX_ENGINE).unwrap_err()
129+
decode_engine("YWx\0pY2U==", &engine).unwrap_err()
128130
);
129131
}
130132

tests/encode.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ fn compare_encode(expected: &str, target: &[u8]) {
1313
fn compare_encode(expected: &str, target: &[u8]) {
1414
assert_eq!(expected, encode(target));
1515

16-
use base64::engine::avx2::{AVX2Encoder, AVX2Config, Standard};
17-
const AVX_ENGINE: AVX2Encoder<Standard> = AVX2Encoder::from(AVX2Config::new());
16+
use base64::engine::avx2::{AVX2Encoder, AVX2Config};
17+
let engine: AVX2Encoder = AVX2Encoder::from_standard(AVX2Config::new());
1818

19-
assert_eq!(expected, encode_engine(target, &AVX_ENGINE));
19+
assert_eq!(expected, encode_engine(target, &engine));
2020
}
2121

2222
#[test]
@@ -127,11 +127,11 @@ fn encode_url_safe_without_padding() {
127127
mod avx2tests {
128128
use super::*;
129129

130-
use base64::engine::avx2::{AVX2Encoder, AVX2Config, Urlsafe};
131-
const AVX_URL_ENGINE: AVX2Encoder<Urlsafe> = AVX2Encoder::from(AVX2Config::new());
130+
use base64::engine::avx2::{AVX2Encoder, AVX2Config};
132131

133132
#[test]
134133
fn encode_all_bytes_url() {
134+
let engine: AVX2Encoder = AVX2Encoder::from_url_safe(AVX2Config::new());
135135
let mut bytes = Vec::<u8>::with_capacity(256);
136136

137137
for i in 0..255 {
@@ -147,7 +147,7 @@ mod avx2tests {
147147
8_T19vf4-fr7_P3-_w==",
148148
encode_engine(
149149
&bytes,
150-
&AVX_URL_ENGINE
150+
&engine
151151
)
152152
);
153153
}

tests/helpers.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,15 @@ pub fn compare_decode(expected: &str, target: &str) {
2626
String::from_utf8(decode_engine(target.as_bytes(), engine).unwrap()).unwrap()
2727
);
2828

29-
use base64::engine::avx2::{AVX2Encoder, AVX2Config, Standard};
30-
const AVX_ENGINE: AVX2Encoder<Standard> = AVX2Encoder::from(AVX2Config::new());
31-
let engine = &AVX_ENGINE;
29+
use base64::engine::avx2::{AVX2Encoder, AVX2Config};
30+
let engine = AVX2Encoder::from_standard(AVX2Config::new());
3231

3332
assert_eq!(
3433
expected,
35-
String::from_utf8(decode_engine(target, engine).unwrap()).unwrap()
34+
String::from_utf8(decode_engine(target, &engine).unwrap()).unwrap()
3635
);
3736
assert_eq!(
3837
expected,
39-
String::from_utf8(decode_engine(target.as_bytes(), engine).unwrap()).unwrap()
38+
String::from_utf8(decode_engine(target.as_bytes(), &engine).unwrap()).unwrap()
4039
);
4140
}

0 commit comments

Comments
 (0)