lgz/examples/layerbench.rs
//! One measurement per process, so peak RSS is this run's alone:
//!
//! `layerbench <flate2|lgz> <file.gz> <threads> <chunk_bytes> <reps>`
//!
//! Prints one JSON line: best-of-`reps` wall seconds, output MB/s, cores busy
//! (CPU time / wall of the best run) and the process's peak RSS. The output is
//! checked against flate2's on the first rep.
use std::io::Read;
use std::time::Instant;
fn cpu_secs() -> f64 {
let mut ru: libc::rusage = unsafe { std::mem::zeroed() };
unsafe { libc::getrusage(libc::RUSAGE_SELF, &mut ru) };
let t = |v: libc::timeval| v.tv_sec as f64 + v.tv_usec as f64 / 1e6;
t(ru.ru_utime) + t(ru.ru_stime)
}
fn peak_rss_mb() -> f64 {
let mut ru: libc::rusage = unsafe { std::mem::zeroed() };
unsafe { libc::getrusage(libc::RUSAGE_SELF, &mut ru) };
ru.ru_maxrss as f64 / 1024.0
}
fn flate2(gz: &[u8]) -> Vec<u8> {
let mut out = Vec::new();
flate2::read::GzDecoder::new(gz)
.read_to_end(&mut out)
.unwrap();
out
}
fn main() {
let a: Vec<String> = std::env::args().collect();
let (how, path) = (&a[1], &a[2]);
let threads: usize = a[3].parse().unwrap();
let chunk: usize = a[4].parse().unwrap();
let reps: usize = a.get(5).map(|s| s.parse().unwrap()).unwrap_or(3);
let gz = std::fs::read(path).unwrap();
let (mut best, mut best_cpu, mut out_len, mut segs) = (f64::MAX, 0.0, 0usize, 0usize);
let mut ok = true;
for rep in 0..reps {
let c0 = cpu_secs();
let t0 = Instant::now();
let (out, s) = match how.as_str() {
"flate2" => (flate2(&gz), 1),
"lgz" => match lgz::bitsplit::decompress(&gz, threads, chunk) {
Ok((o, st)) => {
eprintln!("{st:?}");
(o, st.segments)
}
Err(e) => {
eprintln!("lgz: {e}");
(Vec::new(), 0)
}
},
_ => panic!("flate2|lgz"),
};
let wall = t0.elapsed().as_secs_f64();
let cpu = cpu_secs() - c0;
if rep == 0 && how != "flate2" {
ok = out == flate2(&gz);
}
if wall < best {
best = wall;
best_cpu = cpu;
}
out_len = out.len();
segs = s;
drop(out);
}
println!(
"{{\"how\":\"{how}\",\"file\":\"{}\",\"threads\":{threads},\"chunk_mb\":{},\"in_mb\":{:.1},\"out_mb\":{:.1},\"wall_s\":{best:.3},\"mb_s\":{:.0},\"cores_busy\":{:.2},\"peak_rss_mb\":{:.0},\"segments\":{segs},\"ok\":{ok}}}",
std::path::Path::new(path)
.file_name()
.unwrap()
.to_string_lossy(),
chunk >> 20,
gz.len() as f64 / 1e6,
out_len as f64 / 1e6,
out_len as f64 / 1e6 / best,
best_cpu / best,
peak_rss_mb(),
);
}