#[cfg(test)]
mod tests {
use std::time::Instant;
fn read_threshold(key: &str, default: f64) -> f64 {
for prefix in &["", "../", "../../"] {
let path = format!("{}benchmarks/baselines.json", prefix);
if let Ok(json) = std::fs::read_to_string(&path) {
if let Some(v) = extract_f64(&json, key) {
return v;
}
}
}
default
}
fn extract_f64(json: &str, key: &str) -> Option<f64> {
let pattern = format!("\"{}\":", key);
let start = json.find(&pattern)? + pattern.len();
let rest = json[start..].trim_start();
let end = rest.find(|c: char| !c.is_ascii_digit() && c != '.' && c != '-')?;
rest[..end].parse().ok()
}
fn measure_alternating<A, B>(n: usize, mut f_a: A, mut f_b: B) -> (u64, u64)
where
A: FnMut(),
B: FnMut(),
{
let mut times_a = Vec::with_capacity(n);
let mut times_b = Vec::with_capacity(n);
for _ in 0..3 {
f_a();
f_b();
}
for _ in 0..n {
let t = Instant::now();
f_a();
times_a.push(t.elapsed().as_nanos() as u64);
let t = Instant::now();
f_b();
times_b.push(t.elapsed().as_nanos() as u64);
}
(median(&mut times_a), median(&mut times_b))
}
fn median(v: &mut [u64]) -> u64 {
v.sort_unstable();
v[v.len() / 2]
}
#[test]
fn diff_ratio_single_member_1mb() {
let fixture = crate::tests::fixtures::text_1mb();
let data = &fixture.single_member_gz;
let out_size = fixture.plain.len() + 1024;
let mut ld_buf = vec![0u8; out_size];
let (gzippy_ns, libdeflate_ns) = measure_alternating(
20,
|| {
let _ = crate::decompress::decompress_gzip_to_vec(data, 1).unwrap();
},
|| {
let mut d = libdeflater::Decompressor::new();
let _ = d.gzip_decompress(data, &mut ld_buf);
},
);
let ratio = gzippy_ns as f64 / libdeflate_ns as f64;
let threshold = read_threshold("max_ratio", 1.15);
eprintln!(
"diff_ratio_single_member_1mb: gzippy={:.2}ms libdeflate={:.2}ms ratio={:.3} threshold={:.3}",
gzippy_ns as f64 / 1e6,
libdeflate_ns as f64 / 1e6,
ratio,
threshold
);
if std::env::var("RECORD_BASELINES").is_ok() {
println!("baseline: diff_ratio.max_ratio = {:.3}", ratio * 1.10);
return;
}
assert!(
ratio <= threshold,
"gzippy {:.2}ms vs libdeflate {:.2}ms — ratio {:.3} > threshold {:.3}\n\
Run 'make update-baselines' if this is an intentional improvement.",
gzippy_ns as f64 / 1e6,
libdeflate_ns as f64 / 1e6,
ratio,
threshold
);
}
#[cfg(all(feature = "isal-compression", target_arch = "x86_64"))]
#[test]
fn diff_ratio_parallel_single_member_speedup() {
let fixture = crate::tests::fixtures::text_10mb();
let data = &fixture.single_member_gz;
let (parallel_ns, sequential_ns) = measure_alternating(
10,
|| {
let mut out = Vec::new();
let _ = crate::decompress::parallel::single_member::decompress_parallel(
data, &mut out, 4,
);
},
|| {
let _ = crate::decompress::decompress_gzip_to_vec(data, 1).unwrap();
},
);
let ratio = parallel_ns as f64 / sequential_ns as f64;
let threshold = read_threshold("max_ratio_parallel_sm_speedup", 1.0);
eprintln!(
"diff_ratio_parallel_single_member_speedup: parallel_T4={:.2}ms sequential_T1={:.2}ms ratio={:.3} threshold={:.3}",
parallel_ns as f64 / 1e6,
sequential_ns as f64 / 1e6,
ratio,
threshold
);
if std::env::var("RECORD_BASELINES").is_ok() {
println!(
"baseline: diff_ratio.max_ratio_parallel_sm_speedup = {:.3}",
ratio * 1.10
);
return;
}
assert!(
ratio <= threshold,
"parallel_sm_T4 {:.2}ms vs sequential_T1 {:.2}ms — ratio {:.3} > threshold {:.3} (should be faster)\n\
parallel_single_member has regressed on x86_64.",
parallel_ns as f64 / 1e6,
sequential_ns as f64 / 1e6,
ratio,
threshold
);
}
#[test]
fn diff_ratio_parallel_no_regression_vs_sequential() {
let fixture = crate::tests::fixtures::text_10mb();
let data = &fixture.single_member_gz;
let out_size = fixture.plain.len() + 1024;
let mut ld_buf = vec![0u8; out_size];
let (parallel_ns, libdeflate_ns) = measure_alternating(
10,
|| {
let mut out = Vec::new();
let _ = crate::decompress::parallel::single_member::decompress_parallel(
data, &mut out, 4,
);
},
|| {
let mut d = libdeflater::Decompressor::new();
let _ = d.gzip_decompress(data, &mut ld_buf);
},
);
let ratio = parallel_ns as f64 / libdeflate_ns as f64;
let threshold = read_threshold("max_ratio_parallel_sm_no_regression", 15.0);
eprintln!(
"diff_ratio_parallel_no_regression_vs_sequential: parallel_T4={:.2}ms libdeflate_T1={:.2}ms ratio={:.3} threshold={:.3}",
parallel_ns as f64 / 1e6,
libdeflate_ns as f64 / 1e6,
ratio,
threshold
);
if std::env::var("RECORD_BASELINES").is_ok() {
println!(
"baseline: diff_ratio.max_ratio_parallel_sm_no_regression = {:.3}",
ratio * 1.15
);
return;
}
assert!(
ratio <= threshold,
"parallel_sm_T4 {:.2}ms vs libdeflate_T1 {:.2}ms — ratio {:.3} > threshold {:.3}\n\
parallel_single_member has catastrophically regressed.",
parallel_ns as f64 / 1e6,
libdeflate_ns as f64 / 1e6,
ratio,
threshold
);
}
#[test]
fn diff_ratio_bgzf_10mb_no_regression() {
let fixture = crate::tests::fixtures::text_10mb();
let bgzf_data = &fixture.bgzf_gz;
let single_data = &fixture.single_member_gz;
let out_size = fixture.plain.len() + 1024;
let mut ld_buf = vec![0u8; out_size];
let (gzippy_ns, libdeflate_ns) = measure_alternating(
10,
|| {
let _ =
crate::decompress::bgzf::decompress_bgzf_parallel_to_vec(bgzf_data, 4).unwrap();
},
|| {
let mut d = libdeflater::Decompressor::new();
let _ = d.gzip_decompress(single_data, &mut ld_buf);
},
);
let ratio = gzippy_ns as f64 / libdeflate_ns as f64;
let threshold = read_threshold("max_ratio_bgzf_10mb", 3.5);
eprintln!(
"diff_ratio_bgzf_10mb: gzippy_T4={:.2}ms libdeflate_T1={:.2}ms ratio={:.3} threshold={:.3}",
gzippy_ns as f64 / 1e6,
libdeflate_ns as f64 / 1e6,
ratio,
threshold
);
if std::env::var("RECORD_BASELINES").is_ok() {
println!(
"baseline: diff_ratio.max_ratio_bgzf_10mb = {:.3}",
ratio * 1.15
);
return;
}
assert!(
ratio <= threshold,
"gzippy_T4 {:.2}ms vs libdeflate_T1 {:.2}ms — ratio {:.3} > threshold {:.3}\n\
bgzf parallel path has regressed. Run with GZIPPY_DEBUG=1 to check routing.",
gzippy_ns as f64 / 1e6,
libdeflate_ns as f64 / 1e6,
ratio,
threshold
);
}
}