bench_stream/
bench_stream.rs1use std::time::Instant;
6
7use znippy_compress::{compress_stream, ArchiveEntry};
8
9const MB: usize = 1024 * 1024;
10
11fn gen_text(size: usize) -> Vec<u8> {
12 let word = b"the quick brown fox jumps over the lazy dog ";
14 let mut v = Vec::with_capacity(size);
15 while v.len() < size {
16 v.extend_from_slice(word);
17 }
18 v.truncate(size);
19 v
20}
21
22fn gen_random(size: usize) -> Vec<u8> {
23 let mut s = 0x9E37_79B9_7F4A_7C15u64;
25 (0..size)
26 .map(|_| {
27 s ^= s >> 12;
28 s ^= s << 25;
29 s ^= s >> 27;
30 (s.wrapping_mul(0x2545_F491_4F6C_DD1D) >> 33) as u8
31 })
32 .collect()
33}
34
35fn build_entries(kind: &str) -> Vec<ArchiveEntry> {
36 match kind {
37 "text" => vec![ArchiveEntry::new("text.txt", gen_text(512 * MB))],
38 "random" => vec![ArchiveEntry::new("random.bin", gen_random(512 * MB))],
39 "mixed" => vec![
40 ArchiveEntry::new("pom.xml", gen_text(64 * 1024)),
41 ArchiveEntry::new("app.jar", gen_random(180 * MB)),
42 ArchiveEntry::new("sources.jar", gen_text(120 * MB)),
43 ArchiveEntry::new("javadoc.jar", gen_text(90 * MB)),
44 ArchiveEntry::new("deps.tar.gz", gen_random(140 * MB)),
45 ],
46 "small" => (0..2000)
47 .map(|i| ArchiveEntry::new(format!("f_{i:04}.txt"), gen_text(4096 + (i % 97))))
48 .collect(),
49 _ => panic!("unknown kind"),
50 }
51}
52
53fn run_once(kind: &str, entries: Vec<ArchiveEntry>, archive: &std::path::PathBuf) -> (f64, u64, u64) {
54 let input_bytes: u64 = entries.iter().map(|e| e.data.len() as u64).sum();
55 let t0 = Instant::now();
56 let compressor = compress_stream(archive, false).expect("compress_stream");
57 for e in entries {
58 compressor.sender().send(e).expect("send");
59 }
60 let report = compressor.finish().expect("finish");
61 let secs = t0.elapsed().as_secs_f64();
62 let _ = kind;
63 (secs, input_bytes, report.chunks)
64}
65
66fn main() {
67 let dir = std::env::var("BENCH_DIR").unwrap_or_else(|_| "/run/media/rickard/T9/tmp/bench_stream".into());
68 std::fs::create_dir_all(&dir).unwrap();
69
70 for kind in ["text", "random", "mixed", "small"] {
71 let archive = std::path::PathBuf::from(&dir).join(format!("{kind}.znippy"));
72 let mut best = f64::INFINITY;
73 let mut in_bytes = 0u64;
74 let mut chunks = 0u64;
75 for _ in 0..3 {
76 let entries = build_entries(kind);
77 let (secs, ib, ch) = run_once(kind, entries, &archive);
78 in_bytes = ib;
79 chunks = ch;
80 if secs < best {
81 best = secs;
82 }
83 }
84 let in_mb = in_bytes as f64 / MB as f64;
85 let mbps = in_mb / best;
86
87 let arc = archive.with_extension("znippy");
89 let dec = std::path::PathBuf::from(&dir).join(format!("{kind}_dec"));
90 let _ = std::fs::remove_dir_all(&dec);
91 std::fs::create_dir_all(&dec).unwrap();
92 let v = znippy_common::decompress_archive(&arc, true, &dec).expect("decompress");
93 let orig = build_entries(kind);
94 let mut roundtrip_ok = v.corrupt_files == 0;
95 for e in &orig {
96 let p = dec.join(&e.relative_path);
97 match std::fs::read(&p) {
98 Ok(b) => {
99 if b != e.data {
100 roundtrip_ok = false;
101 eprintln!("MISMATCH {kind} {}", e.relative_path);
102 }
103 }
104 Err(err) => {
105 roundtrip_ok = false;
106 eprintln!("MISSING {kind} {}: {err}", e.relative_path);
107 }
108 }
109 }
110
111 println!(
112 "BENCH kind={kind} best_s={best:.4} in_mb={in_mb:.1} mbps={mbps:.1} chunks={chunks} corrupt={} roundtrip_ok={roundtrip_ok}",
113 v.corrupt_files
114 );
115 }
116}