fashex 0.0.5

Hexadecimal string encoding and decoding with best-effort SIMD acceleration.
Documentation
//! Throughput benchmarks.

#![cfg(any(
    target_arch = "x86",
    target_arch = "x86_64",
    target_arch = "aarch64",
    target_arch = "loongarch64"
))]
#![allow(clippy::pedantic, reason = "XXX")]

use std::hint::black_box;
use std::iter;

use criterion::{
    AxisScale, BenchmarkId, Criterion, PlotConfiguration, Throughput, criterion_group,
    criterion_main,
};
use fastant::Instant;

fn bench_encode(c: &mut Criterion) {
    let mut group = c.benchmark_group("encode/lowercase");

    group.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic));

    for size in [1048576, 131072, 16384, 2048, 256, 32] {
        let input = iter::repeat_n(fastrand::u8(..), size).collect::<Vec<_>>();

        let expected = input
            .iter()
            .copied()
            .flat_map(|b| {
                [
                    fashex::util::DIGITS_LOWER_16[(b >> 4) as usize] as char,
                    fashex::util::DIGITS_LOWER_16[(b & 0b1111) as usize] as char,
                ]
            })
            .collect::<String>();

        group.throughput(Throughput::Bytes(size as u64));

        group.bench_function(BenchmarkId::new("fashex-const", size), |b| {
            b.iter_custom(|iters| {
                (0..iters)
                    .map(|_| {
                        let mut output = String::with_capacity(size * 2);

                        let elapsed = {
                            #[allow(unsafe_code, reason = "XXX")]
                            let output = unsafe {
                                &mut output.as_mut_vec().spare_capacity_mut()[..size * 2]
                            };

                            let now = Instant::now();

                            fashex::encode_generic::<false>(black_box(&input), output).unwrap();

                            now.elapsed()
                        };

                        #[allow(unsafe_code, reason = "XXX")]
                        unsafe {
                            output.as_mut_vec().set_len(size * 2);
                        }

                        assert!(expected == output);

                        elapsed
                    })
                    .sum()
            });
        });

        group.bench_function(BenchmarkId::new("fashex", size), |b| {
            b.iter_custom(|iters| {
                (0..iters)
                    .map(|_| {
                        let mut output = String::with_capacity(size * 2);

                        let elapsed = {
                            #[allow(unsafe_code, reason = "XXX")]
                            let output = unsafe {
                                &mut output.as_mut_vec().spare_capacity_mut()[..size * 2]
                            };

                            let now = Instant::now();

                            fashex::encode::<_, false>(black_box(&input), output).unwrap();

                            now.elapsed()
                        };

                        #[allow(unsafe_code, reason = "XXX")]
                        unsafe {
                            output.as_mut_vec().set_len(size * 2);
                        }

                        assert!(expected == output);

                        elapsed
                    })
                    .sum()
            });
        });

        group.bench_function(BenchmarkId::new("hex-simd", size), |b| {
            b.iter_custom(|iters| {
                (0..iters)
                    .map(|_| {
                        let mut output = String::with_capacity(size * 2);

                        let elapsed = {
                            #[allow(unsafe_code, reason = "XXX")]
                            let output = unsafe { output.as_mut_vec() };

                            let now = Instant::now();

                            hex_simd::encode_append(
                                black_box(&input),
                                output,
                                hex_simd::AsciiCase::Lower,
                            );

                            now.elapsed()
                        };

                        assert!(expected == output);

                        elapsed
                    })
                    .sum()
            });
        });

        group.bench_function(BenchmarkId::new("const-hex", size), |b| {
            b.iter_custom(|iters| {
                (0..iters)
                    .map(|_| {
                        let mut output = String::with_capacity(size * 2);

                        let elapsed = {
                            #[allow(unsafe_code, reason = "XXX")]
                            let output = unsafe { output.as_mut_vec() };

                            output.resize(size * 2, 0);

                            let now = Instant::now();

                            const_hex::encode_to_slice(black_box(&input), output).unwrap();

                            now.elapsed()
                        };

                        assert!(expected == output);

                        elapsed
                    })
                    .sum()
            });
        });

        group.bench_function(BenchmarkId::new("faster-hex", size), |b| {
            b.iter_custom(|iters| {
                (0..iters)
                    .map(|_| {
                        let mut output = String::with_capacity(size * 2);

                        let elapsed = {
                            #[allow(unsafe_code, reason = "XXX")]
                            let output = unsafe { output.as_mut_vec() };

                            output.resize(size * 2, 0);

                            let now = Instant::now();

                            faster_hex::hex_encode(black_box(&input), output).unwrap();

                            now.elapsed()
                        };

                        assert!(expected == output);

                        elapsed
                    })
                    .sum()
            });
        });
    }

    group.finish();
}

criterion_group!(benches, bench_encode);
criterion_main!(benches);