use criterion::{criterion_group, criterion_main, Criterion, Throughput, BenchmarkId};
use std::fs;
use std::path::PathBuf;
fn zip_cache_dir() -> PathBuf {
if let Ok(d) = std::env::var("LZIP_TEST_ZIPS") {
return PathBuf::from(d);
}
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
PathBuf::from(home).join("work/test-zips")
}
const MAVEN_BASE: &str = "https://repo1.maven.org/maven2";
struct BenchJar {
filename: &'static str,
maven_path: &'static str,
label: &'static str,
}
const BENCH_JARS: &[BenchJar] = &[
BenchJar {
filename: "guava-33.2.1-jre.jar",
maven_path: "com/google/guava/guava/33.2.1-jre/guava-33.2.1-jre.jar",
label: "guava_3.4MB",
},
BenchJar {
filename: "ecj-3.37.0.jar",
maven_path: "org/eclipse/jdt/ecj/3.37.0/ecj-3.37.0.jar",
label: "ecj_4.8MB",
},
BenchJar {
filename: "scala-library-2.13.14.jar",
maven_path: "org/scala-lang/scala-library/2.13.14/scala-library-2.13.14.jar",
label: "scala_5.8MB",
},
BenchJar {
filename: "kotlin-stdlib-2.0.0.jar",
maven_path: "org/jetbrains/kotlin/kotlin-stdlib/2.0.0/kotlin-stdlib-2.0.0.jar",
label: "kotlin_1.8MB",
},
];
fn ensure_jar(jar: &BenchJar) -> Option<PathBuf> {
let dir = zip_cache_dir();
fs::create_dir_all(&dir).ok()?;
let path = dir.join(jar.filename);
if path.exists() {
return Some(path);
}
let url = format!("{}/{}", MAVEN_BASE, jar.maven_path);
eprintln!(" downloading {} ...", jar.filename);
let output = std::process::Command::new("curl")
.args(["-sSfL", "-o"])
.arg(&path)
.arg(&url)
.output()
.ok()?;
if output.status.success() {
Some(path)
} else {
None
}
}
fn bench_zip_decompress(c: &mut Criterion) {
let mut group = c.benchmark_group("zip_decompress");
group.sample_size(20);
for jar in BENCH_JARS {
let path = match ensure_jar(jar) {
Some(p) => p,
None => {
eprintln!(" skipping {} (download failed)", jar.filename);
continue;
}
};
let data = fs::read(&path).unwrap();
let file_size = data.len() as u64;
group.throughput(Throughput::Bytes(file_size));
group.bench_with_input(
BenchmarkId::new("lzip", jar.label),
&data,
|b, data| {
b.iter(|| {
let entries = lzip::decompress_zip(data).unwrap();
criterion::black_box(entries.len())
})
},
);
}
group.finish();
}
fn bench_lzip_vs_zip_crate(c: &mut Criterion) {
let mut group = c.benchmark_group("jar_vs_zip_crate");
group.sample_size(20);
let jar = &BENCH_JARS[0]; let path = match ensure_jar(jar) {
Some(p) => p,
None => {
eprintln!(" skipping comparison (download failed)");
return;
}
};
let data = fs::read(&path).unwrap();
let file_size = data.len() as u64;
group.throughput(Throughput::Bytes(file_size));
group.bench_function("lzip", |b| {
b.iter(|| {
let entries = lzip::decompress_zip(&data).unwrap();
criterion::black_box(entries.len())
})
});
group.bench_function("zip_crate_sequential", |b| {
b.iter(|| {
use std::io::{Cursor, Read};
let cursor = Cursor::new(&data);
let mut archive = zip::ZipArchive::new(cursor).unwrap();
let mut total = 0usize;
for i in 0..archive.len() {
let mut entry = archive.by_index(i).unwrap();
if entry.is_dir() { continue; }
let mut buf = Vec::with_capacity(entry.size() as usize);
entry.read_to_end(&mut buf).unwrap();
total += buf.len();
}
criterion::black_box(total)
})
});
group.finish();
}
fn bench_core_scaling(_c: &mut Criterion) {
}
criterion_group!(benches, bench_zip_decompress, bench_lzip_vs_zip_crate);
criterion_main!(benches);