Some checks failed
Continuous integration / Tests (push) Blocked by required conditions
Continuous integration / Tests (windows-latest) (push) Waiting to run
Continuous integration / Check clippy, formatting, and documentation (push) Failing after 20s
Continuous integration / Tests (ubuntu-latest) (push) Failing after 22s
Continuous integration / Check fuzzers (push) Failing after 18s
Continuous integration / Check mininum Rust version (push) Failing after 20s
209 lines
7.1 KiB
Rust
209 lines
7.1 KiB
Rust
// This file is part of ICU4X. For terms of use, please see the file
|
|
// called LICENSE at the top level of the ICU4X source tree
|
|
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
|
|
|
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
use rand::SeedableRng;
|
|
use rand_distr::{Alphanumeric, Distribution, Uniform};
|
|
use rand_pcg::Lcg64Xsh32;
|
|
use std::ops::RangeInclusive;
|
|
|
|
use zerovec::VarZeroVec;
|
|
|
|
/// Generates an array of random alphanumeric strings.
|
|
///
|
|
/// - length = range of lengths for the strings (chosen uniformly at random)
|
|
/// - count = number of strings to generate
|
|
/// - seed = seed for the PRNG
|
|
///
|
|
/// Returns a tuple including the vector and a u64 that can be used to seed the next PRNG.
|
|
fn random_alphanums(lengths: RangeInclusive<usize>, count: usize, seed: u64) -> (Vec<String>, u64) {
|
|
// Lcg64Xsh32 is a small, fast PRNG for reproducible benchmarks.
|
|
let mut rng1 = Lcg64Xsh32::seed_from_u64(seed);
|
|
let mut rng2 = Lcg64Xsh32::seed_from_u64(rand::Rng::gen(&mut rng1));
|
|
let alpha_dist = Alphanumeric;
|
|
let len_dist = Uniform::from(lengths);
|
|
let string_vec = len_dist
|
|
.sample_iter(&mut rng1)
|
|
.take(count)
|
|
.map(|len| {
|
|
(&alpha_dist)
|
|
.sample_iter(&mut rng2)
|
|
.take(len)
|
|
.map(char::from)
|
|
.collect::<String>()
|
|
})
|
|
.collect();
|
|
(string_vec, rand::Rng::gen(&mut rng1))
|
|
}
|
|
|
|
fn overview_bench(c: &mut Criterion) {
|
|
// Same as vzv/char_count/vzv but with different inputs
|
|
let seed = 42;
|
|
let (string_vec, _) = random_alphanums(2..=10, 100, seed);
|
|
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
|
|
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();
|
|
|
|
c.bench_function("vzv/overview", |b| {
|
|
b.iter(|| {
|
|
black_box(&vzv)
|
|
.iter()
|
|
.fold(0, |sum, string| sum + string.chars().count())
|
|
});
|
|
});
|
|
|
|
#[cfg(feature = "bench")]
|
|
{
|
|
char_count_benches(c);
|
|
binary_search_benches(c);
|
|
vzv_precompute_bench(c);
|
|
}
|
|
|
|
#[cfg(all(feature = "bench", feature = "serde"))]
|
|
{
|
|
serde_benches(c);
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "bench")]
|
|
fn char_count_benches(c: &mut Criterion) {
|
|
let seed = 2021;
|
|
let (string_vec, _) = random_alphanums(2..=20, 100, seed);
|
|
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
|
|
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();
|
|
|
|
// *** Count chars in vec of 100 strings ***
|
|
c.bench_function("vzv/char_count/slice", |b| {
|
|
b.iter(|| {
|
|
black_box(&string_vec)
|
|
.iter()
|
|
.fold(0, |sum, string| sum + string.chars().count())
|
|
});
|
|
});
|
|
|
|
// *** Count chars in vec of 100 strings ***
|
|
c.bench_function("vzv/char_count/vzv", |b| {
|
|
b.iter(|| {
|
|
black_box(&vzv)
|
|
.iter()
|
|
.fold(0, |sum, string| sum + string.chars().count())
|
|
});
|
|
});
|
|
}
|
|
|
|
#[cfg(feature = "bench")]
|
|
fn binary_search_benches(c: &mut Criterion) {
|
|
let seed = 2021;
|
|
let (string_vec, seed) = random_alphanums(2..=20, 500, seed);
|
|
let (needles, _) = random_alphanums(2..=20, 10, seed);
|
|
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
|
|
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();
|
|
let single_needle = "lmnop".to_owned();
|
|
|
|
// *** Binary search vec of 500 strings 10 times ***
|
|
c.bench_function("vzv/binary_search/slice", |b| {
|
|
b.iter(|| {
|
|
black_box(&needles)
|
|
.iter()
|
|
.map(|needle| black_box(&string_vec).binary_search(needle))
|
|
.filter(|r| r.is_ok())
|
|
.count()
|
|
});
|
|
});
|
|
|
|
// *** Binary search vec of 500 strings 10 times ***
|
|
c.bench_function("vzv/binary_search/vzv", |b| {
|
|
b.iter(|| {
|
|
black_box(&needles)
|
|
.iter()
|
|
.map(|needle| black_box(&vzv).binary_search(needle))
|
|
.filter(|r| r.is_ok())
|
|
.count()
|
|
});
|
|
});
|
|
|
|
c.bench_function("vzv/binary_search/single/slice", |b| {
|
|
b.iter(|| black_box(&string_vec).binary_search(black_box(&single_needle)));
|
|
});
|
|
|
|
c.bench_function("vzv/binary_search/single/vzv", |b| {
|
|
b.iter(|| black_box(&vzv).binary_search(black_box(&single_needle)));
|
|
});
|
|
}
|
|
|
|
#[cfg(all(feature = "bench", feature = "serde"))]
|
|
fn serde_benches(c: &mut Criterion) {
|
|
let seed = 2021;
|
|
let (string_vec, _) = random_alphanums(2..=20, 100, seed);
|
|
let bincode_vec = bincode::serialize(&string_vec).unwrap();
|
|
let vzv: VarZeroVec<str> = VarZeroVec::from(&*string_vec);
|
|
let bincode_vzv = bincode::serialize(&vzv).unwrap();
|
|
|
|
// *** Deserialize vec of 100 strings ***
|
|
c.bench_function("vzv/deserialize/string/vec_owned", |b| {
|
|
b.iter(|| bincode::deserialize::<Vec<String>>(black_box(&bincode_vec)));
|
|
});
|
|
|
|
// *** Deserialize vec of 100 strings ***
|
|
c.bench_function("vzv/deserialize/string/vec_borrowed", |b| {
|
|
b.iter(|| bincode::deserialize::<Vec<&str>>(black_box(&bincode_vec)));
|
|
});
|
|
|
|
// *** Deserialize vec of 100 strings ***
|
|
c.bench_function("vzv/deserialize/string/vzv", |b| {
|
|
b.iter(|| bincode::deserialize::<VarZeroVec<str>>(black_box(&bincode_vzv)));
|
|
});
|
|
}
|
|
|
|
#[cfg(feature = "bench")]
|
|
// Testing differences between operating on slices with precomputed/non-precomputed indexing info
|
|
fn vzv_precompute_bench(c: &mut Criterion) {
|
|
let seed = 2021;
|
|
let (string_vec, seed) = random_alphanums(2..=20, 500, seed);
|
|
let (needles, _) = random_alphanums(2..=20, 10, seed);
|
|
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
|
|
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();
|
|
let borrowed = vzv.as_components();
|
|
let slice = vzv.as_slice();
|
|
let single_needle = "lmnop";
|
|
|
|
c.bench_function("vzv_precompute/get/precomputed", |b| {
|
|
b.iter(|| black_box(&borrowed).get(100));
|
|
});
|
|
|
|
c.bench_function("vzv_precompute/get/slice", |b| {
|
|
b.iter(|| black_box(&slice).get(100));
|
|
});
|
|
|
|
c.bench_function("vzv_precompute/search/precomputed", |b| {
|
|
b.iter(|| black_box(&borrowed).binary_search(single_needle));
|
|
});
|
|
|
|
c.bench_function("vzv_precompute/search/slice", |b| {
|
|
b.iter(|| black_box(&slice).binary_search(single_needle));
|
|
});
|
|
|
|
c.bench_function("vzv_precompute/search_multi/precomputed", |b| {
|
|
b.iter(|| {
|
|
black_box(&needles)
|
|
.iter()
|
|
.map(|needle| black_box(&borrowed).binary_search(needle))
|
|
.filter(|r| r.is_ok())
|
|
.count()
|
|
});
|
|
});
|
|
|
|
c.bench_function("vzv_precompute/search_multi/slice", |b| {
|
|
b.iter(|| {
|
|
black_box(&needles)
|
|
.iter()
|
|
.map(|needle| black_box(&slice).binary_search(needle))
|
|
.filter(|r| r.is_ok())
|
|
.count()
|
|
});
|
|
});
|
|
}
|
|
|
|
criterion_group!(benches, overview_bench,);
|
|
criterion_main!(benches);
|