// Copyright (c) 2022, Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 #[macro_use] extern crate criterion; mod encoding_benches { use super::*; use base64::engine::general_purpose; use base64::Engine; use base64ct::{Base64 as b64ct, Encoding}; use criterion::*; use faster_hex::{ hex_decode, hex_decode_fallback, hex_decode_unchecked, hex_encode_fallback, hex_string, }; use rustc_hex::{FromHex, ToHex}; struct TestMessage<'a> { name: &'a str, value: &'a [u8], } const TEST_MESSAGES: &[TestMessage] = &[ TestMessage { name: "MSG_20B_ZERO", value: &[0u8; 20], }, TestMessage { name: "MSG_32B_ZERO", value: &[0u8; 32], }, TestMessage { name: "MSG_64B_ZERO", value: &[0u8; 64], }, TestMessage { name: "MSG_20B_RANDOM", value: b"this is a random msg", }, TestMessage { name: "MSG_32B_RANDOM", value: b"this is a random msg: (32B long)", }, TestMessage { name: "MSG_64B_RANDOM", value: b"this is a random msg: (64B long)this is a random msg: (64B long)", }, ]; // Hex encoding bench. fn hex_encoding(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("Hex encoding"); for test_message in TEST_MESSAGES { group.bench_function( &("rustc_hex_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret: String = test_message.value.to_hex(); black_box(ret); }) }, ); group.bench_function(&("hex_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret = hex::encode(test_message.value); black_box(ret); }) }); group.bench_function( &("faster_hex_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret = hex_string(test_message.value); black_box(ret); }) }, ); group.bench_function( &("faster_hex_encode_fallback_".to_owned() + test_message.name), move |b| { b.iter(|| { let bytes = test_message.value; let mut buffer = vec![0; bytes.len() * 2]; hex_encode_fallback(bytes, &mut buffer); }) }, ); } } // Hex decoding bench. fn hex_decoding(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("Hex decoding"); for test_message in TEST_MESSAGES { group.bench_function( &("rustc_hex_decode_".to_owned() + test_message.name), move |b| { let hex: String = test_message.value.to_hex(); b.iter(|| { let ret: Vec = hex.from_hex().unwrap(); black_box(ret); }) }, ); group.bench_function(&("hex_decode_".to_owned() + test_message.name), move |b| { let hex: String = test_message.value.to_hex(); b.iter(|| { let ret: Vec = hex::decode(&hex).unwrap(); black_box(ret); }) }); group.bench_function( &("faster_hex_decode_".to_owned() + test_message.name), move |b| { let hex: String = test_message.value.to_hex(); let len = test_message.value.len(); b.iter(|| { let mut dst = vec![0; len]; dst.resize(len, 0); hex_decode(hex.as_bytes(), &mut dst).unwrap(); }) }, ); group.bench_function( &("faster_hex_decode_unchecked_".to_owned() + test_message.name), move |b| { let hex: String = test_message.value.to_hex(); let len = test_message.value.len(); b.iter(|| { let mut dst = vec![0; len]; dst.resize(len, 0); hex_decode_unchecked(hex.as_bytes(), &mut dst); }) }, ); group.bench_function( &("faster_hex_decode_fallback_".to_owned() + test_message.name), move |b| { let hex: String = test_message.value.to_hex(); let len = test_message.value.len(); b.iter(|| { let mut dst = vec![0; len]; dst.resize(len, 0); hex_decode_fallback(hex.as_bytes(), &mut dst); }) }, ); } } // Base64 encoding bench. fn base64_encoding(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("Base64 encoding"); for test_message in TEST_MESSAGES { group.bench_function( &("base64_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret = general_purpose::STANDARD.encode(test_message.value); black_box(ret); }) }, ); group.bench_function( &("base64ct_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret = b64ct::encode_string(test_message.value); black_box(ret); }) }, ); group.bench_function( &("radix64_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret = radix64::STD.encode(test_message.value); black_box(ret); }) }, ); } } // Base64 decoding bench. fn base64_decoding(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("Base64 encoding"); for test_message in TEST_MESSAGES { group.bench_function( &("base64_decode_".to_owned() + test_message.name), move |b| { let base64_string: String = general_purpose::STANDARD.encode(test_message.value); b.iter(|| { let ret = general_purpose::STANDARD.encode(&base64_string); black_box(ret); }) }, ); group.bench_function( &("base64ct_decode_".to_owned() + test_message.name), move |b| { let base64_string: String = b64ct::encode_string(test_message.value); b.iter(|| { let ret = b64ct::decode_vec(&base64_string).unwrap(); black_box(ret); }) }, ); group.bench_function( &("radix64_decode_".to_owned() + test_message.name), move |b| { let base64_string: String = radix64::STD.encode(test_message.value); b.iter(|| { let ret = radix64::STD.decode(&base64_string).unwrap(); black_box(ret); }) }, ); } } // Base58 encoding bench. fn base58_encoding(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("Base58 encoding"); for test_message in TEST_MESSAGES { group.bench_function(&("bs58_encode_".to_owned() + test_message.name), move |b| { b.iter(|| { let ret = bs58::encode(test_message.value).into_string(); black_box(ret); }) }); group.bench_function( &("base58_encode_".to_owned() + test_message.name), move |b| { use base58::ToBase58; b.iter(|| { let ret = test_message.value.to_base58(); black_box(ret); }) }, ); group.bench_function( &("rust_base58_encode_".to_owned() + test_message.name), move |b| { use rust_base58::ToBase58; b.iter(|| { let ret = test_message.value.to_base58(); black_box(ret); }) }, ); } } // Base58 decoding bench. fn base58_decoding(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("Base58 decoding"); for test_message in TEST_MESSAGES { group.bench_function(&("bs58_decode_".to_owned() + test_message.name), move |b| { let base58_string: String = bs58::encode(test_message.value).into_string(); b.iter(|| { let ret = bs58::decode(&base58_string).into_vec().unwrap(); black_box(ret); }) }); group.bench_function( &("base58_decode_".to_owned() + test_message.name), move |b| { use base58::{FromBase58, ToBase58}; let base58_string: String = test_message.value.to_base58(); b.iter(|| { let ret = base58_string.from_base58().unwrap(); black_box(ret); }) }, ); group.bench_function( &("rust_base58_decode_".to_owned() + test_message.name), move |b| { use rust_base58::{FromBase58, ToBase58}; let base58_string: String = test_message.value.to_base58(); b.iter(|| { let ret = base58_string.from_base58().unwrap(); black_box(ret); }) }, ); } } criterion_group! { name = encoding_benches; config = Criterion::default(); targets = hex_encoding, hex_decoding, base64_encoding, base64_decoding, base58_encoding, base58_decoding, } } criterion_main!(encoding_benches::encoding_benches,);