@@ -3,18 +3,25 @@ extern crate base64;
33extern crate criterion;
44extern crate rand;
55
6+ #[ macro_use]
7+ extern crate lazy_static;
8+
9+ use std:: ops:: Deref ;
10+
611use base64:: display;
712use 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 } ;
1318use criterion:: { black_box, Bencher , BenchmarkId , Criterion , Throughput } ;
1419use rand:: { FromEntropy , Rng } ;
1520use 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
1926fn 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) {
2936fn 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) {
5360fn 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) {
7986fn 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) {
110117fn 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+
550607fn 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
557616criterion_group ! ( benches, bench) ;
0 commit comments