#![allow(
clippy::expect_used,
clippy::unwrap_used,
clippy::cast_possible_truncation
)]
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use crush_parallel::{compress, decompress, EngineConfiguration};
fn generate_corpus(size: usize, seed: u64) -> Vec<u8> {
const TOKENS: &[&[u8]] = &[
b"fn ",
b"let ",
b"mut ",
b"pub ",
b"use ",
b"mod ",
b"struct ",
b"impl ",
b"return ",
b"match ",
b"if ",
b"else ",
b"for ",
b"while ",
b"Vec<u8>",
b"Result<",
b" ",
b"\n",
b"// comment\n",
b"Ok(",
b"Err(",
b"Some(",
b"None",
b"true",
b"false",
b"self",
b"type ",
b"trait ",
b"where ",
b"0x",
b"ERROR: ",
b"WARN: ",
b"INFO: ",
b"2026-02-",
b"::new()",
];
let mut data = Vec::with_capacity(size);
let mut state = seed;
while data.len() < size {
state ^= state << 13;
state ^= state >> 7;
state ^= state << 17;
if state.is_multiple_of(3) {
data.push(((state >> 8) & 0x5F) as u8 + 32);
} else {
let token = TOKENS[(state as usize >> 4) % TOKENS.len()];
let remaining = size - data.len();
data.extend_from_slice(&token[..token.len().min(remaining)]);
}
}
data.truncate(size);
data
}
fn bench_compression(c: &mut Criterion) {
let data = generate_corpus(128 * 1024 * 1024, 0xDEAD_BEEF_CAFE_1234);
let mut group = c.benchmark_group("compress_throughput");
group.throughput(Throughput::Bytes(data.len() as u64));
group.sample_size(10);
for (label, workers) in [("default", 0usize), ("1", 1), ("2", 2), ("4", 4), ("8", 8)] {
for block_kb in [64usize, 512, 1024] {
let block_size = u32::try_from(block_kb * 1024).expect("block_size fits u32");
let config = EngineConfiguration::builder()
.workers(workers)
.block_size(block_size)
.build()
.expect("config");
group.bench_with_input(
BenchmarkId::new(format!("threads={label}"), format!("block={block_kb}KB")),
&data,
|b, data| {
b.iter(|| compress(data, &config).expect("compress"));
},
);
}
}
group.finish();
}
fn bench_decompression(c: &mut Criterion) {
let data = generate_corpus(128 * 1024 * 1024, 0xCAFE_BABE_0000_0001);
let config_compress = EngineConfiguration::builder()
.block_size(1_048_576)
.build()
.expect("config");
let compressed = compress(&data, &config_compress).expect("compress");
let mut group = c.benchmark_group("decompress_throughput");
group.throughput(Throughput::Bytes(data.len() as u64));
group.sample_size(10);
for (label, workers) in [("default", 0usize), ("1", 1), ("2", 2), ("4", 4), ("8", 8)] {
let config = EngineConfiguration::builder()
.workers(workers)
.block_size(1_048_576)
.build()
.expect("config");
group.bench_with_input(
BenchmarkId::new("threads", label),
&compressed,
|b, compressed| {
b.iter(|| decompress(compressed, &config).expect("decompress"));
},
);
}
group.finish();
}
criterion_group!(benches, bench_compression, bench_decompression);
criterion_main!(benches);