1use crate::Result;
6use crate::binary::{StringTable, StringTableBuilder, compute_blake3};
7use crate::streaming::XorPatcher;
8use console::style;
9use std::path::Path;
10use std::time::Instant;
11
12#[derive(Debug)]
14pub struct BenchmarkCommand;
15
16#[derive(Debug, Default)]
18pub struct BenchmarkResults {
19 pub string_lookup_ns: f64,
21 pub xor_compute_us: f64,
23 pub hash_throughput: f64,
25}
26
27impl BenchmarkCommand {
28 pub fn execute(iterations: usize) -> Result<BenchmarkResults> {
30 println!(
31 "{} Running DX Binary Dawn Benchmarks ({} iterations)",
32 style("⚡").bold(),
33 iterations
34 );
35 println!();
36
37 let mut results = BenchmarkResults::default();
38
39 println!(" {} String Table Lookup...", style("▸").cyan());
41 results.string_lookup_ns = Self::bench_string_table(iterations);
42 println!(" Lookup: {:.2} ns/op", results.string_lookup_ns);
43
44 println!(" {} XOR Patcher...", style("▸").cyan());
46 results.xor_compute_us = Self::bench_xor_patcher(iterations);
47 println!(" Compute: {:.2} µs/op", results.xor_compute_us);
48
49 println!(" {} Blake3 Checksum...", style("▸").cyan());
51 results.hash_throughput = Self::bench_blake3(iterations);
52 println!(
53 " Throughput: {:.2} MB/s",
54 results.hash_throughput / 1_000_000.0
55 );
56
57 println!();
58 println!("{} Benchmarks complete!", style("✓").green().bold());
59
60 Ok(results)
61 }
62
63 fn bench_string_table(iterations: usize) -> f64 {
65 let mut builder = StringTableBuilder::new();
66 let strings: Vec<_> = (0..1000).map(|i| format!("string_{}", i)).collect();
67 let ids: Vec<_> = strings.iter().map(|s| builder.intern(s)).collect();
68 let table_bytes = builder.build();
69 let table = StringTable::from_bytes(&table_bytes).unwrap();
70
71 let start = Instant::now();
72 for _ in 0..iterations {
73 for &id in &ids {
74 let _ = table.get(id);
75 }
76 }
77 let elapsed = start.elapsed();
78
79 let total_ops = ids.len() * iterations;
80 elapsed.as_nanos() as f64 / total_ops as f64
81 }
82
83 fn bench_xor_patcher(iterations: usize) -> f64 {
85 let old = vec![0u8; 4096];
86 let mut new = old.clone();
87 for i in (0..new.len()).step_by(100) {
89 new[i] = 1;
90 }
91
92 let patcher = XorPatcher::new(64);
93
94 let start = Instant::now();
95 for _ in 0..iterations {
96 let _ = patcher.compute(&old, &new);
97 }
98 let elapsed = start.elapsed();
99
100 elapsed.as_micros() as f64 / iterations as f64
101 }
102
103 fn bench_blake3(iterations: usize) -> f64 {
105 let data = vec![0u8; 65536]; let start = Instant::now();
108 for _ in 0..iterations {
109 let _ = compute_blake3(&data);
110 }
111 let elapsed = start.elapsed();
112
113 let total_bytes = data.len() * iterations;
114 total_bytes as f64 / elapsed.as_secs_f64()
115 }
116
117 pub fn bench_file(path: &Path) -> Result<()> {
119 println!(
120 "{} Benchmarking file: {}",
121 style("⚡").bold(),
122 path.display()
123 );
124
125 let data = std::fs::read(path)?;
126 let size = data.len();
127
128 let start = Instant::now();
130 let hash = compute_blake3(&data);
131 let hash_time = start.elapsed();
132
133 println!();
134 println!(" File size: {} bytes", size);
135 println!(" Hash: {:?}", hash_time);
136 println!(" Blake3: {:02x?}", hash);
137
138 Ok(())
139 }
140}