cache_rs/metrics/lfu.rs
1//! LFU Cache Metrics
2//!
3//! Metrics specific to the LFU (Least Frequently Used) cache algorithm.
4
5extern crate alloc;
6
7use super::{CacheMetrics, CoreCacheMetrics};
8use alloc::collections::BTreeMap;
9use alloc::string::{String, ToString};
10
11/// LFU-specific metrics (extends CoreCacheMetrics)
12///
13/// This struct contains metrics specific to the LFU (Least Frequently Used) cache algorithm.
14/// LFU tracks frequency of access for each item, so these metrics focus on frequency
15/// distribution and access patterns.
16#[derive(Debug, Clone)]
17pub struct LfuCacheMetrics {
18 /// Core metrics common to all cache algorithms
19 pub core: CoreCacheMetrics,
20
21 /// Current minimum frequency in the cache
22 pub min_frequency: u64,
23
24 /// Current maximum frequency in the cache
25 pub max_frequency: u64,
26
27 /// Total number of frequency increments (every cache hit increases frequency)
28 pub total_frequency_increments: u64,
29
30 /// Number of unique frequency levels currently in use
31 pub active_frequency_levels: u64,
32}
33
34impl LfuCacheMetrics {
35 /// Creates a new LfuCacheMetrics instance with the specified maximum cache size
36 ///
37 /// # Arguments
38 /// * `max_cache_size_bytes` - The maximum allowed cache size in bytes
39 pub fn new(max_cache_size_bytes: u64) -> Self {
40 Self {
41 core: CoreCacheMetrics::new(max_cache_size_bytes),
42 min_frequency: 0,
43 max_frequency: 0,
44 total_frequency_increments: 0,
45 active_frequency_levels: 0,
46 }
47 }
48
49 /// Records a frequency increment (when an item is accessed and its frequency increases)
50 ///
51 /// # Arguments
52 /// * `old_frequency` - The previous frequency value
53 /// * `new_frequency` - The new frequency value for the accessed item
54 pub fn record_frequency_increment(&mut self, _old_frequency: usize, new_frequency: usize) {
55 self.total_frequency_increments += 1;
56
57 // Update min/max frequency tracking
58 let new_freq_u64 = new_frequency as u64;
59 if self.min_frequency == 0 || new_freq_u64 < self.min_frequency {
60 self.min_frequency = new_freq_u64;
61 }
62 if new_freq_u64 > self.max_frequency {
63 self.max_frequency = new_freq_u64;
64 }
65 }
66
67 /// Records a cache hit with frequency information
68 ///
69 /// # Arguments
70 /// * `object_size` - Size of the object that was served from cache (in bytes)
71 /// * `frequency` - Current frequency of the accessed item
72 pub fn record_frequency_hit(&mut self, object_size: u64, frequency: usize) {
73 self.core.record_hit(object_size);
74
75 // Update frequency bounds
76 let freq_u64 = frequency as u64;
77 if self.min_frequency == 0 || freq_u64 < self.min_frequency {
78 self.min_frequency = freq_u64;
79 }
80 if freq_u64 > self.max_frequency {
81 self.max_frequency = freq_u64;
82 }
83 }
84
85 /// Updates the frequency levels based on current frequency lists
86 ///
87 /// # Arguments
88 /// * `frequency_lists` - Map of frequency to list of items at that frequency
89 pub fn update_frequency_levels<T>(&mut self, frequency_lists: &BTreeMap<usize, T>) {
90 self.active_frequency_levels = frequency_lists.len() as u64;
91
92 // Update min/max from the actual frequency keys
93 if let (Some(&min_freq), Some(&max_freq)) =
94 (frequency_lists.keys().min(), frequency_lists.keys().max())
95 {
96 self.min_frequency = min_freq as u64;
97 self.max_frequency = max_freq as u64;
98 }
99 }
100
101 /// Records a cache miss for LFU metrics
102 ///
103 /// # Arguments
104 /// * `object_size` - Size of the object that was requested (in bytes)
105 pub fn record_miss(&mut self, object_size: u64) {
106 self.core.record_miss(object_size);
107 }
108
109 /// Updates the count of active frequency levels
110 ///
111 /// # Arguments
112 /// * `levels` - The number of different frequency levels currently in use
113 pub fn update_active_frequency_levels(&mut self, levels: u64) {
114 self.active_frequency_levels = levels;
115 }
116
117 /// Calculates the average frequency of accesses
118 ///
119 /// # Returns
120 /// Average frequency per item access, or 0.0 if no hits have occurred
121 pub fn average_frequency(&self) -> f64 {
122 if self.core.cache_hits > 0 {
123 self.total_frequency_increments as f64 / self.core.cache_hits as f64
124 } else {
125 0.0
126 }
127 }
128
129 /// Calculates the frequency range (max - min)
130 ///
131 /// # Returns
132 /// The range of frequencies currently in the cache
133 pub fn frequency_range(&self) -> u64 {
134 self.max_frequency.saturating_sub(self.min_frequency)
135 }
136
137 /// Converts LFU metrics to a BTreeMap for reporting
138 ///
139 /// This method returns all metrics relevant to the LFU cache algorithm,
140 /// including both core metrics and LFU-specific frequency metrics.
141 ///
142 /// Uses BTreeMap to ensure consistent, deterministic ordering of metrics.
143 ///
144 /// # Returns
145 /// A BTreeMap containing all LFU cache metrics as key-value pairs
146 pub fn to_btreemap(&self) -> BTreeMap<String, f64> {
147 let mut metrics = self.core.to_btreemap();
148
149 // LFU-specific metrics
150 metrics.insert("min_frequency".to_string(), self.min_frequency as f64);
151 metrics.insert("max_frequency".to_string(), self.max_frequency as f64);
152 metrics.insert("frequency_range".to_string(), self.frequency_range() as f64);
153 metrics.insert(
154 "total_frequency_increments".to_string(),
155 self.total_frequency_increments as f64,
156 );
157 metrics.insert(
158 "active_frequency_levels".to_string(),
159 self.active_frequency_levels as f64,
160 );
161 metrics.insert("average_frequency".to_string(), self.average_frequency());
162
163 // Frequency efficiency metrics
164 if self.core.requests > 0 {
165 metrics.insert(
166 "frequency_increment_rate".to_string(),
167 self.total_frequency_increments as f64 / self.core.requests as f64,
168 );
169 }
170
171 if self.active_frequency_levels > 0 && self.core.cache_hits > 0 {
172 metrics.insert(
173 "frequency_distribution_efficiency".to_string(),
174 self.active_frequency_levels as f64 / self.core.cache_hits as f64,
175 );
176 }
177
178 metrics
179 }
180}
181
182impl CacheMetrics for LfuCacheMetrics {
183 /// Returns all LFU cache metrics as key-value pairs in deterministic order
184 ///
185 /// # Returns
186 /// A BTreeMap containing all metrics tracked by this LFU cache instance
187 fn metrics(&self) -> BTreeMap<String, f64> {
188 self.to_btreemap()
189 }
190
191 /// Returns the algorithm name for this cache implementation
192 ///
193 /// # Returns
194 /// "LFU" - identifying this as a Least Frequently Used cache
195 fn algorithm_name(&self) -> &'static str {
196 "LFU"
197 }
198}