1use serde::{Deserialize, Serialize};
9use std::time::{SystemTime, UNIX_EPOCH};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct UnifiedCacheStats {
16 pub l1_stats: CacheLevelStats,
18 pub l2_stats: CacheLevelStats,
20 pub overall_stats: OverallCacheStats,
22 pub preheating_stats: CachePreheatingStats,
24 pub tuning_stats: TuningStats,
26 pub performance_metrics: PerformanceMetrics,
28 pub timestamp: u64,
30}
31
32impl Default for UnifiedCacheStats {
33 fn default() -> Self {
34 Self {
35 l1_stats: CacheLevelStats::default(),
36 l2_stats: CacheLevelStats::default(),
37 overall_stats: OverallCacheStats::default(),
38 preheating_stats: CachePreheatingStats::default(),
39 tuning_stats: TuningStats::default(),
40 performance_metrics: PerformanceMetrics::default(),
41 timestamp: SystemTime::now()
42 .duration_since(UNIX_EPOCH)
43 .map(|d| d.as_secs())
44 .unwrap_or(0),
45 }
46 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct CacheLevelStats {
52 pub hits: u64,
54 pub misses: u64,
56 pub entries: usize,
58 pub capacity: usize,
60 pub usage_bytes: u64,
62 pub max_usage_bytes: u64,
64 pub evictions: u64,
66 pub hit_rate: f64,
68 pub load_factor: f64,
70 pub avg_entry_size: f64,
72}
73
74impl Default for CacheLevelStats {
75 fn default() -> Self {
76 Self {
77 hits: 0,
78 misses: 0,
79 entries: 0,
80 capacity: 0,
81 usage_bytes: 0,
82 max_usage_bytes: 0,
83 evictions: 0,
84 hit_rate: 0.0,
85 load_factor: 0.0,
86 avg_entry_size: 0.0,
87 }
88 }
89}
90
91impl CacheLevelStats {
92 pub fn update_hit_rate(&mut self) {
94 let total_requests = self.hits + self.misses;
95 if total_requests > 0 {
96 self.hit_rate = self.hits as f64 / total_requests as f64;
97 }
98 }
99
100 pub fn update_load_factor(&mut self) {
102 if self.capacity > 0 {
103 self.load_factor = self.entries as f64 / self.capacity as f64;
104 }
105 }
106
107 pub fn update_avg_entry_size(&mut self) {
109 if self.entries > 0 {
110 self.avg_entry_size = self.usage_bytes as f64 / self.entries as f64;
111 }
112 }
113
114 pub fn update_calculated_fields(&mut self) {
116 self.update_hit_rate();
117 self.update_load_factor();
118 self.update_avg_entry_size();
119 }
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct OverallCacheStats {
125 pub total_hits: u64,
127 pub total_misses: u64,
129 pub overall_hit_rate: f64,
131 pub total_entries: usize,
133 pub total_memory_bytes: u64,
135 pub total_disk_bytes: u64,
137 pub efficiency_score: f64,
139 pub promotions: u64,
141 pub demotions: u64,
143}
144
145impl Default for OverallCacheStats {
146 fn default() -> Self {
147 Self {
148 total_hits: 0,
149 total_misses: 0,
150 overall_hit_rate: 0.0,
151 total_entries: 0,
152 total_memory_bytes: 0,
153 total_disk_bytes: 0,
154 efficiency_score: 0.0,
155 promotions: 0,
156 demotions: 0,
157 }
158 }
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct CachePreheatingStats {
164 pub preheat_attempts: u64,
166 pub preheat_successes: u64,
168 pub preheat_hit_rate: f64,
170 pub entries_preheated: u64,
172 pub preheated_entries_accessed: u64,
174 pub avg_prediction_confidence: f64,
176 pub time_saved_ms: u64,
178 pub cpu_time_used_ms: u64,
180}
181
182impl Default for CachePreheatingStats {
183 fn default() -> Self {
184 Self {
185 preheat_attempts: 0,
186 preheat_successes: 0,
187 preheat_hit_rate: 0.0,
188 entries_preheated: 0,
189 preheated_entries_accessed: 0,
190 avg_prediction_confidence: 0.0,
191 time_saved_ms: 0,
192 cpu_time_used_ms: 0,
193 }
194 }
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct TuningStats {
200 pub tuning_cycles: u64,
202 pub successful_adjustments: u64,
204 pub ttl_adjustments: u64,
206 pub capacity_adjustments: u64,
208 pub eviction_strategy_changes: u64,
210 pub performance_improvement: f64,
212 pub last_tuning_timestamp: u64,
214 pub stability_score: f64,
216}
217
218impl Default for TuningStats {
219 fn default() -> Self {
220 Self {
221 tuning_cycles: 0,
222 successful_adjustments: 0,
223 ttl_adjustments: 0,
224 capacity_adjustments: 0,
225 eviction_strategy_changes: 0,
226 performance_improvement: 0.0,
227 last_tuning_timestamp: 0,
228 stability_score: 1.0,
229 }
230 }
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct PerformanceMetrics {
236 pub avg_get_latency_us: f64,
238 pub avg_put_latency_us: f64,
240 pub avg_eviction_latency_us: f64,
242 pub ops_per_second: f64,
244 pub memory_allocation_rate: f64,
246 pub disk_io_rate: f64,
248 pub cpu_usage_percent: f64,
250 pub peak_memory_usage: u64,
252}
253
254impl Default for PerformanceMetrics {
255 fn default() -> Self {
256 Self {
257 avg_get_latency_us: 0.0,
258 avg_put_latency_us: 0.0,
259 avg_eviction_latency_us: 0.0,
260 ops_per_second: 0.0,
261 memory_allocation_rate: 0.0,
262 disk_io_rate: 0.0,
263 cpu_usage_percent: 0.0,
264 peak_memory_usage: 0,
265 }
266 }
267}
268
269impl UnifiedCacheStats {
270 pub fn new() -> Self {
272 Self::default()
273 }
274
275 pub fn update_overall_stats(&mut self) {
277 self.overall_stats.total_hits = self.l1_stats.hits + self.l2_stats.hits;
278 self.overall_stats.total_misses = self.l1_stats.misses + self.l2_stats.misses;
279
280 let total_requests = self.overall_stats.total_hits + self.overall_stats.total_misses;
281 if total_requests > 0 {
282 self.overall_stats.overall_hit_rate =
283 self.overall_stats.total_hits as f64 / total_requests as f64;
284 }
285
286 self.overall_stats.total_entries = self.l1_stats.entries + self.l2_stats.entries;
287 self.overall_stats.total_memory_bytes = self.l1_stats.usage_bytes;
288 self.overall_stats.total_disk_bytes = self.l2_stats.usage_bytes;
289
290 let hit_rate_score = self.overall_stats.overall_hit_rate;
292 let memory_efficiency = if self.l1_stats.max_usage_bytes > 0 {
293 1.0 - (self.l1_stats.usage_bytes as f64 / self.l1_stats.max_usage_bytes as f64)
294 } else {
295 1.0
296 };
297 self.overall_stats.efficiency_score = (hit_rate_score + memory_efficiency) / 2.0;
298
299 self.timestamp = SystemTime::now()
301 .duration_since(UNIX_EPOCH)
302 .map(|d| d.as_secs())
303 .unwrap_or(0);
304 }
305
306 pub fn summary_report(&self) -> String {
308 format!(
309 "Cache Statistics Summary:\n\
310 Overall Hit Rate: {:.2}%\n\
311 Total Entries: {}\n\
312 Memory Usage: {:.2} MB\n\
313 Disk Usage: {:.2} MB\n\
314 Efficiency Score: {:.2}\n\
315 Preheating Hit Rate: {:.2}%\n\
316 Tuning Cycles: {}",
317 self.overall_stats.overall_hit_rate * 100.0,
318 self.overall_stats.total_entries,
319 self.overall_stats.total_memory_bytes as f64 / (1024.0 * 1024.0),
320 self.overall_stats.total_disk_bytes as f64 / (1024.0 * 1024.0),
321 self.overall_stats.efficiency_score,
322 self.preheating_stats.preheat_hit_rate * 100.0,
323 self.tuning_stats.tuning_cycles
324 )
325 }
326
327 pub fn is_performing_well(&self, target_hit_rate: f64) -> bool {
329 self.overall_stats.overall_hit_rate >= target_hit_rate
330 && self.overall_stats.efficiency_score >= 0.7
331 && self.tuning_stats.stability_score >= 0.8
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338
339 #[test]
340 fn test_cache_level_stats() {
341 let mut stats = CacheLevelStats::default();
342 stats.hits = 80;
343 stats.misses = 20;
344 stats.entries = 100;
345 stats.capacity = 200;
346 stats.usage_bytes = 1024;
347
348 stats.update_calculated_fields();
349
350 assert_eq!(stats.hit_rate, 0.8);
351 assert_eq!(stats.load_factor, 0.5);
352 assert_eq!(stats.avg_entry_size, 10.24);
353 }
354
355 #[test]
356 fn test_unified_cache_stats() {
357 let mut stats = UnifiedCacheStats::new();
358 stats.l1_stats.hits = 70;
359 stats.l1_stats.misses = 10;
360 stats.l2_stats.hits = 20;
361 stats.l2_stats.misses = 5;
362
363 stats.update_overall_stats();
364
365 assert_eq!(stats.overall_stats.total_hits, 90);
366 assert_eq!(stats.overall_stats.total_misses, 15);
367 assert!((stats.overall_stats.overall_hit_rate - 0.857).abs() < 0.01);
368 }
369
370 #[test]
371 fn test_performance_check() {
372 let mut stats = UnifiedCacheStats::new();
373 stats.overall_stats.overall_hit_rate = 0.95;
374 stats.overall_stats.efficiency_score = 0.8;
375 stats.tuning_stats.stability_score = 0.9;
376
377 assert!(stats.is_performing_well(0.9));
378 assert!(!stats.is_performing_well(0.96));
379 }
380}