Skip to main content

driven/cli/
benchmark.rs

1//! Benchmark Command
2//!
3//! Performance benchmarking for DX Binary Dawn features.
4
5use 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/// Benchmark command for performance testing
13#[derive(Debug)]
14pub struct BenchmarkCommand;
15
16/// Benchmark results
17#[derive(Debug, Default)]
18pub struct BenchmarkResults {
19    /// String table lookup time (ns)
20    pub string_lookup_ns: f64,
21    /// XOR patch compute time (µs)
22    pub xor_compute_us: f64,
23    /// Blake3 hash throughput (bytes/sec)
24    pub hash_throughput: f64,
25}
26
27impl BenchmarkCommand {
28    /// Run all benchmarks
29    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        // String table benchmark
40        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        // XOR patcher benchmark
45        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        // Blake3 benchmark
50        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    /// Benchmark string table lookup
64    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    /// Benchmark XOR patcher
84    fn bench_xor_patcher(iterations: usize) -> f64 {
85        let old = vec![0u8; 4096];
86        let mut new = old.clone();
87        // Simulate small changes
88        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    /// Benchmark Blake3 hashing
104    fn bench_blake3(iterations: usize) -> f64 {
105        let data = vec![0u8; 65536]; // 64KB
106
107        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    /// Run file-based benchmark
118    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        // Hash
129        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}