use criterion::{ black_box, criterion_group, criterion_main, Bencher, Criterion, ParameterizedBenchmark, Throughput, }; use radix64::Config; use std::fmt::Debug; use base64::STANDARD as B64_CONFIG; use radix64::STD as RADIX_CONFIG; mod radix { use super::*; use rand::Rng; pub(crate) fn encode(config: C, b: &mut Bencher, &size: &usize) { let mut input = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); b.iter(|| { let encoded = config.encode(&input); black_box(&encoded); }) } pub(crate) fn decode(config: C, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = config.encode(&input); b.iter(|| { let decoded = config.decode(&encoded).expect("decode failed"); black_box(&decoded); }) } pub(crate) fn encode_with_buffer(config: C, b: &mut Bencher, &size: &usize) { let mut input = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); // This could be initialized to an empty buffer, but we want to remove // allocations from the timed portion. let mut buffer = vec![0; size * 4 / 3 + 3]; b.iter(|| { let encoded = config.encode_with_buffer(&input, &mut buffer); black_box(&encoded); }) } pub(crate) fn decode_with_buffer(config: C, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = config.encode(&input); // This could be initialized to an empty buffer, but we want to remove // allocations from the timed portion. let mut buffer = vec![0; size]; b.iter(|| { let decoded = config .decode_with_buffer(&encoded, &mut buffer) .expect("decode failed"); black_box(&decoded); }) } pub(crate) fn encode_slice(config: C, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let mut output = vec![0; size * 4 / 3 + 3]; b.iter(|| { config.encode_slice(&input, output.as_mut_slice()); black_box(&output); }) } pub(crate) fn decode_slice(config: C, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = config.encode(&input); let mut decoded = vec![0; size]; b.iter(|| { config .decode_slice(&encoded, decoded.as_mut_slice()) .unwrap(); black_box(&decoded); }) } pub(crate) fn encode_writer(config: C, b: &mut Bencher, &size: &usize) { use std::io::Write; let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let mut output = Vec::with_capacity(size * 4 / 3 + 3); b.iter(|| { output.clear(); let mut writer = radix64::io::EncodeWriter::new(config, &mut output); writer.write_all(&input).expect("failed to write all input"); writer.finish().expect("failed to finish write"); black_box(&output); }) } pub(crate) fn decode_reader(config: C, b: &mut Bencher, &size: &usize) { use std::io::Read; let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = config.encode(&input); let mut decoded = Vec::with_capacity(input.len()); b.iter(|| { decoded.clear(); let mut rdr = radix64::io::DecodeReader::new(config, std::io::Cursor::new(&encoded)); rdr.read_to_end(&mut decoded) .expect("failed to read to the end"); black_box(&decoded); }) } pub(crate) fn display(config: C, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let display = radix64::Display::new(config, &input); b.iter(|| { let encoded = display.to_string(); black_box(&encoded); }) } } mod b64 { use super::*; use rand::Rng; pub(crate) fn encode(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); b.iter(|| { let encoded = base64::encode_config(&input, config); black_box(&encoded); }) } pub(crate) fn decode(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = base64::encode_config(&input, config); b.iter(|| { let decoded = base64::decode_config(&encoded, config).expect("decode failed"); black_box(&decoded); }) } pub(crate) fn encode_with_buffer(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let mut buffer = String::with_capacity(size * 4 / 3 + 3); b.iter(|| { buffer.clear(); let encoded = base64::encode_config_buf(&input, config, &mut buffer); black_box(&encoded); }) } pub(crate) fn decode_with_buffer(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = base64::encode(&input); let mut buffer = Vec::with_capacity(size); b.iter(|| { buffer.clear(); base64::decode_config_buf(&encoded, config, &mut buffer).expect("decode failed"); black_box(&buffer); }) } pub(crate) fn encode_slice(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let mut output = vec![0; size * 4 / 3 + 4]; b.iter(|| { base64::encode_config_slice(&input, config, output.as_mut_slice()); black_box(&output); }) } pub(crate) fn decode_slice(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let encoded = base64::encode(&input); let mut decoded = vec![0; size]; b.iter(|| { base64::decode_config_slice(&encoded, config, decoded.as_mut_slice()).unwrap(); black_box(&decoded); }) } pub(crate) fn encode_writer(config: base64::Config, b: &mut Bencher, &size: &usize) { use std::io::Write; let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let mut output = Vec::with_capacity(size * 4 / 3 + 4); b.iter(|| { output.clear(); { let mut writer = base64::write::EncoderWriter::new(&mut output, config); writer.write_all(&input).expect("failed to write all input"); writer.finish().expect("failed to finish write"); } black_box(&output); }) } pub(crate) fn display(config: base64::Config, b: &mut Bencher, &size: &usize) { let mut input: Vec = vec![0; size]; rand::thread_rng().fill(input.as_mut_slice()); let display = base64::display::Base64Display::with_config(&input, config); b.iter(|| { let encoded = display.to_string(); black_box(&encoded); }) } } const BYTE_SIZES: [usize; 7] = [3, 32, 64, 128, 512, 4096, 8192]; pub fn encode_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::encode(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::encode(B64_CONFIG, b, s)) } pub fn encode_with_buffer_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::encode_with_buffer(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::encode_with_buffer(B64_CONFIG, b, s)) } pub fn encode_slice_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::encode_slice(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::encode_slice(B64_CONFIG, b, s)) } pub fn encode_writer_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::encode_writer(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::encode_writer(B64_CONFIG, b, s)) } pub fn decode_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::decode(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::decode(B64_CONFIG, b, s)) } pub fn decode_with_buffer_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::decode_with_buffer(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::decode_with_buffer(B64_CONFIG, b, s)) } pub fn decode_slice_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::decode_slice(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::decode_slice(B64_CONFIG, b, s)) } pub fn decode_reader_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::decode_reader(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) } pub fn display_benches(byte_sizes: &[usize]) -> ParameterizedBenchmark { ParameterizedBenchmark::new( "radix64", |b, s| radix::display(RADIX_CONFIG, b, s), byte_sizes.iter().cloned(), ) .with_function("base64", |b, s| b64::display(B64_CONFIG, b, s)) } fn customize_benchmark(benchmark: ParameterizedBenchmark) -> ParameterizedBenchmark { benchmark.throughput(|s| Throughput::Bytes(*s as u32)) } fn bench(c: &mut Criterion) { c.bench( "encode_bench", customize_benchmark(encode_benches(&BYTE_SIZES[..])), ); c.bench( "encode_slice_bench", customize_benchmark(encode_slice_benches(&BYTE_SIZES[..])), ); c.bench( "encode_with_buffer_bench", customize_benchmark(encode_with_buffer_benches(&BYTE_SIZES[..])), ); c.bench( "encode_writer_bench", customize_benchmark(encode_writer_benches(&BYTE_SIZES[..])), ); c.bench( "decode_bench", customize_benchmark(decode_benches(&BYTE_SIZES[..])), ); c.bench( "decode_slice_bench", customize_benchmark(decode_slice_benches(&BYTE_SIZES[..])), ); c.bench( "decode_with_buffer_bench", customize_benchmark(decode_with_buffer_benches(&BYTE_SIZES[..])), ); c.bench( "decode_reader_bench", customize_benchmark(decode_reader_benches(&BYTE_SIZES[..])), ); c.bench( "display_bench", customize_benchmark(display_benches(&BYTE_SIZES[..])), ); } criterion_group!(benches, bench); criterion_main!(benches);