1use crate::types::{Algorithm, CompressionRatio};
4
5#[derive(Debug, Clone, Default)]
7pub struct CompressionStats {
8 pub algorithm: Option<Algorithm>,
10
11 pub original_size: usize,
13
14 pub compressed_size: usize,
16
17 pub time_us: u64,
19
20 pub blocks_processed: usize,
22
23 pub peak_memory: Option<usize>,
25
26 pub dictionary_used: bool,
28
29 pub simd_used: bool,
31
32 pub checksum: Option<u64>,
34}
35
36impl CompressionStats {
37 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn from_operation(
44 algorithm: Algorithm,
45 original_size: usize,
46 compressed_size: usize,
47 time_us: u64,
48 ) -> Self {
49 CompressionStats {
50 algorithm: Some(algorithm),
51 original_size,
52 compressed_size,
53 time_us,
54 blocks_processed: 1,
55 ..Default::default()
56 }
57 }
58
59 pub fn ratio(&self) -> CompressionRatio {
61 CompressionRatio::new(self.original_size, self.compressed_size)
62 }
63
64 pub fn throughput_bps(&self) -> f64 {
66 if self.time_us == 0 {
67 return 0.0;
68 }
69 self.original_size as f64 * 1_000_000.0 / self.time_us as f64
70 }
71
72 pub fn throughput_mbs(&self) -> f64 {
74 self.throughput_bps() / 1_000_000.0
75 }
76
77 pub fn savings_percent(&self) -> f64 {
79 self.ratio().savings_percent()
80 }
81
82 pub fn merge(&mut self, other: &CompressionStats) {
84 self.original_size += other.original_size;
85 self.compressed_size += other.compressed_size;
86 self.time_us += other.time_us;
87 self.blocks_processed += other.blocks_processed;
88
89 match (&self.peak_memory, &other.peak_memory) {
91 (Some(a), Some(b)) => self.peak_memory = Some((*a).max(*b)),
92 (None, Some(b)) => self.peak_memory = Some(*b),
93 _ => {}
94 }
95 }
96}
97
98#[derive(Debug, Clone, Default)]
100pub struct Metrics {
101 pub total_operations: u64,
103
104 pub total_bytes_in: u64,
106
107 pub total_bytes_out: u64,
109
110 pub total_time_us: u64,
112
113 pub error_count: u64,
115}
116
117impl Metrics {
118 pub fn new() -> Self {
120 Self::default()
121 }
122
123 pub fn record(&mut self, stats: &CompressionStats) {
125 self.total_operations += 1;
126 self.total_bytes_in += stats.original_size as u64;
127 self.total_bytes_out += stats.compressed_size as u64;
128 self.total_time_us += stats.time_us;
129 }
130
131 pub fn record_error(&mut self) {
133 self.error_count += 1;
134 }
135
136 pub fn average_ratio(&self) -> f64 {
138 if self.total_bytes_out == 0 {
139 return 1.0;
140 }
141 self.total_bytes_in as f64 / self.total_bytes_out as f64
142 }
143
144 pub fn average_throughput_mbs(&self) -> f64 {
146 if self.total_time_us == 0 {
147 return 0.0;
148 }
149 self.total_bytes_in as f64 / self.total_time_us as f64
150 }
151
152 pub fn error_rate(&self) -> f64 {
154 if self.total_operations == 0 {
155 return 0.0;
156 }
157 self.error_count as f64 / self.total_operations as f64
158 }
159
160 pub fn reset(&mut self) {
162 *self = Self::default();
163 }
164
165 pub fn summary(&self) -> String {
167 format!(
168 "Operations: {}, Bytes: {} -> {} (ratio: {:.2}x), Throughput: {:.1} MB/s, Errors: {}",
169 self.total_operations,
170 self.total_bytes_in,
171 self.total_bytes_out,
172 self.average_ratio(),
173 self.average_throughput_mbs(),
174 self.error_count,
175 )
176 }
177}