1#[allow(dead_code)]
8use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
9use std::ptr::NonNull;
10use std::sync::{Arc, Mutex, RwLock};
11use std::time::{Duration, Instant};
12
13pub struct EvictionEngine {
15 config: EvictionConfig,
17 stats: EvictionStats,
19 policies: HashMap<String, Box<dyn EvictionPolicy>>,
21 active_policy: String,
23 memory_regions: HashMap<usize, MemoryRegion>,
25 performance_monitor: EvictionPerformanceMonitor,
27 policy_history: VecDeque<PolicySelection>,
29}
30
31#[derive(Debug, Clone)]
33pub struct EvictionConfig {
34 pub auto_eviction: bool,
36 pub pressure_threshold: f64,
38 pub enable_adaptive: bool,
40 pub enable_monitoring: bool,
42 pub default_policy: String,
44 pub policy_switch_threshold: f64,
46 pub min_batch_size: usize,
48 pub max_batch_size: usize,
50 pub workload_aware: bool,
52 pub kernel_context_weight: f64,
54}
55
56impl Default for EvictionConfig {
57 fn default() -> Self {
58 Self {
59 auto_eviction: true,
60 pressure_threshold: 0.85,
61 enable_adaptive: true,
62 enable_monitoring: true,
63 default_policy: "LRU".to_string(),
64 policy_switch_threshold: 0.1,
65 min_batch_size: 1,
66 max_batch_size: 64,
67 workload_aware: true,
68 kernel_context_weight: 0.3,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Default)]
75pub struct EvictionStats {
76 pub total_evictions: u64,
78 pub total_bytes_evicted: u64,
80 pub total_objects_evicted: u64,
82 pub average_eviction_time: Duration,
84 pub eviction_accuracy: f64,
86 pub policy_scores: HashMap<String, f64>,
88 pub pressure_events: u64,
90 pub policy_switches: u64,
92}
93
94#[derive(Debug, Clone)]
96pub struct MemoryRegion {
97 pub base_addr: usize,
99 pub size: usize,
101 pub objects: HashMap<usize, CacheObject>,
103 pub region_type: RegionType,
105 pub pressure: f64,
107 pub last_eviction: Option<Instant>,
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub enum RegionType {
114 Cache,
115 Buffer,
116 Texture,
117 Constant,
118 Shared,
119 Global,
120}
121
122#[derive(Debug, Clone)]
124pub struct CacheObject {
125 pub address: usize,
127 pub size: usize,
129 pub created_at: Instant,
131 pub last_access: Instant,
133 pub access_count: u32,
135 pub access_frequency: f64,
137 pub priority: ObjectPriority,
139 pub kernel_context: Option<u32>,
141 pub object_type: ObjectType,
143 pub eviction_cost: f64,
145 pub replacement_cost: f64,
147}
148
149#[derive(Debug, Clone, PartialEq, Ord, PartialOrd, Eq)]
151pub enum ObjectPriority {
152 Low,
153 Normal,
154 High,
155 Critical,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Hash)]
160pub enum ObjectType {
161 Data,
162 Texture,
163 Constant,
164 Instruction,
165 Temporary,
166 Persistent,
167 Critical,
168}
169
170impl CacheObject {
171 pub fn update_access(&mut self) {
173 self.access_count += 1;
174 let now = Instant::now();
175 let time_since_creation = now.duration_since(self.created_at).as_secs_f64();
176
177 if time_since_creation > 0.0 {
178 self.access_frequency = self.access_count as f64 / time_since_creation;
179 }
180
181 self.last_access = now;
182 }
183
184 pub fn calculate_utility(&self) -> f64 {
186 let age_factor = self.last_access.elapsed().as_secs_f64();
187 let frequency_factor = self.access_frequency;
188 let priority_factor = match self.priority {
189 ObjectPriority::Critical => 10.0,
190 ObjectPriority::High => 5.0,
191 ObjectPriority::Normal => 1.0,
192 ObjectPriority::Low => 0.5,
193 };
194
195 let size_factor = 1.0 / (self.size as f64).sqrt();
196
197 (frequency_factor * priority_factor * size_factor) / (age_factor + 1.0)
199 }
200}
201
202pub trait EvictionPolicy: Send + Sync {
204 fn name(&self) -> &str;
205 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize>;
206 fn update_access(&mut self, address: usize, object: &CacheObject);
207 fn add_object(&mut self, address: usize, object: &CacheObject);
208 fn remove_object(&mut self, address: usize);
209 fn get_statistics(&self) -> PolicyStats;
210 fn configure(&mut self, config: &EvictionConfig);
211 fn reset(&mut self);
212}
213
214#[derive(Debug, Clone, Default)]
216pub struct PolicyStats {
217 pub evictions: u64,
218 pub bytes_evicted: u64,
219 pub average_latency: Duration,
220 pub accuracy_score: f64,
221 pub hit_rate: f64,
222}
223
224pub struct LRUPolicy {
226 lru_order: VecDeque<usize>,
228 address_map: HashMap<usize, usize>,
230 stats: PolicyStats,
232}
233
234impl Default for LRUPolicy {
235 fn default() -> Self {
236 Self::new()
237 }
238}
239
240impl LRUPolicy {
241 pub fn new() -> Self {
242 Self {
243 lru_order: VecDeque::new(),
244 address_map: HashMap::new(),
245 stats: PolicyStats::default(),
246 }
247 }
248
249 fn move_to_end(&mut self, address: usize) {
250 if let Some(&pos) = self.address_map.get(&address) {
251 if pos < self.lru_order.len() {
252 self.lru_order.remove(pos);
253 self.lru_order.push_back(address);
254 self.update_positions();
255 }
256 }
257 }
258
259 fn update_positions(&mut self) {
260 self.address_map.clear();
261 for (pos, &addr) in self.lru_order.iter().enumerate() {
262 self.address_map.insert(addr, pos);
263 }
264 }
265}
266
267impl EvictionPolicy for LRUPolicy {
268 fn name(&self) -> &str {
269 "LRU"
270 }
271
272 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize> {
273 let mut victims = Vec::new();
274 let mut bytes_selected = 0;
275
276 for &address in &self.lru_order {
278 if let Some(object) = region.objects.get(&address) {
279 victims.push(address);
280 bytes_selected += object.size;
281
282 if bytes_selected >= target_bytes {
283 break;
284 }
285 }
286 }
287
288 self.stats.evictions += victims.len() as u64;
289 self.stats.bytes_evicted += bytes_selected as u64;
290
291 victims
292 }
293
294 fn update_access(&mut self, address: usize, _object: &CacheObject) {
295 self.move_to_end(address);
296 }
297
298 fn add_object(&mut self, address: usize, _object: &CacheObject) {
299 if !self.address_map.contains_key(&address) {
300 self.lru_order.push_back(address);
301 self.address_map.insert(address, self.lru_order.len() - 1);
302 }
303 }
304
305 fn remove_object(&mut self, address: usize) {
306 if let Some(&pos) = self.address_map.get(&address) {
307 if pos < self.lru_order.len() {
308 self.lru_order.remove(pos);
309 self.address_map.remove(&address);
310 self.update_positions();
311 }
312 }
313 }
314
315 fn get_statistics(&self) -> PolicyStats {
316 self.stats.clone()
317 }
318
319 fn configure(&mut self, _config: &EvictionConfig) {
320 }
322
323 fn reset(&mut self) {
324 self.lru_order.clear();
325 self.address_map.clear();
326 self.stats = PolicyStats::default();
327 }
328}
329
330pub struct LFUPolicy {
332 frequency_map: HashMap<usize, u32>,
334 frequency_buckets: BTreeMap<u32, HashSet<usize>>,
336 stats: PolicyStats,
338}
339
340impl Default for LFUPolicy {
341 fn default() -> Self {
342 Self::new()
343 }
344}
345
346impl LFUPolicy {
347 pub fn new() -> Self {
348 Self {
349 frequency_map: HashMap::new(),
350 frequency_buckets: BTreeMap::new(),
351 stats: PolicyStats::default(),
352 }
353 }
354
355 fn update_frequency(&mut self, address: usize) {
356 let old_freq = self.frequency_map.get(&address).copied().unwrap_or(0);
357 let new_freq = old_freq + 1;
358
359 if old_freq > 0 {
361 if let Some(bucket) = self.frequency_buckets.get_mut(&old_freq) {
362 bucket.remove(&address);
363 if bucket.is_empty() {
364 self.frequency_buckets.remove(&old_freq);
365 }
366 }
367 }
368
369 self.frequency_buckets
371 .entry(new_freq)
372 .or_default()
373 .insert(address);
374 self.frequency_map.insert(address, new_freq);
375 }
376}
377
378impl EvictionPolicy for LFUPolicy {
379 fn name(&self) -> &str {
380 "LFU"
381 }
382
383 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize> {
384 let mut victims = Vec::new();
385 let mut bytes_selected = 0;
386
387 for addresses in self.frequency_buckets.values() {
389 for &address in addresses {
390 if let Some(object) = region.objects.get(&address) {
391 victims.push(address);
392 bytes_selected += object.size;
393
394 if bytes_selected >= target_bytes {
395 break;
396 }
397 }
398 }
399
400 if bytes_selected >= target_bytes {
401 break;
402 }
403 }
404
405 self.stats.evictions += victims.len() as u64;
406 self.stats.bytes_evicted += bytes_selected as u64;
407
408 victims
409 }
410
411 fn update_access(&mut self, address: usize, _object: &CacheObject) {
412 self.update_frequency(address);
413 }
414
415 fn add_object(&mut self, address: usize, _object: &CacheObject) {
416 self.update_frequency(address);
417 }
418
419 fn remove_object(&mut self, address: usize) {
420 if let Some(freq) = self.frequency_map.remove(&address) {
421 if let Some(bucket) = self.frequency_buckets.get_mut(&freq) {
422 bucket.remove(&address);
423 if bucket.is_empty() {
424 self.frequency_buckets.remove(&freq);
425 }
426 }
427 }
428 }
429
430 fn get_statistics(&self) -> PolicyStats {
431 self.stats.clone()
432 }
433
434 fn configure(&mut self, _config: &EvictionConfig) {
435 }
437
438 fn reset(&mut self) {
439 self.frequency_map.clear();
440 self.frequency_buckets.clear();
441 self.stats = PolicyStats::default();
442 }
443}
444
445pub struct FIFOPolicy {
447 insertion_order: VecDeque<usize>,
449 stats: PolicyStats,
451}
452
453impl Default for FIFOPolicy {
454 fn default() -> Self {
455 Self::new()
456 }
457}
458
459impl FIFOPolicy {
460 pub fn new() -> Self {
461 Self {
462 insertion_order: VecDeque::new(),
463 stats: PolicyStats::default(),
464 }
465 }
466}
467
468impl EvictionPolicy for FIFOPolicy {
469 fn name(&self) -> &str {
470 "FIFO"
471 }
472
473 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize> {
474 let mut victims = Vec::new();
475 let mut bytes_selected = 0;
476
477 for &address in &self.insertion_order {
479 if let Some(object) = region.objects.get(&address) {
480 victims.push(address);
481 bytes_selected += object.size;
482
483 if bytes_selected >= target_bytes {
484 break;
485 }
486 }
487 }
488
489 self.stats.evictions += victims.len() as u64;
490 self.stats.bytes_evicted += bytes_selected as u64;
491
492 victims
493 }
494
495 fn update_access(&mut self, _address: usize, _object: &CacheObject) {
496 }
498
499 fn add_object(&mut self, address: usize, _object: &CacheObject) {
500 self.insertion_order.push_back(address);
501 }
502
503 fn remove_object(&mut self, address: usize) {
504 if let Some(pos) = self
505 .insertion_order
506 .iter()
507 .position(|&addr| addr == address)
508 {
509 self.insertion_order.remove(pos);
510 }
511 }
512
513 fn get_statistics(&self) -> PolicyStats {
514 self.stats.clone()
515 }
516
517 fn configure(&mut self, _config: &EvictionConfig) {
518 }
520
521 fn reset(&mut self) {
522 self.insertion_order.clear();
523 self.stats = PolicyStats::default();
524 }
525}
526
527pub struct ClockPolicy {
529 clock_list: Vec<ClockEntry>,
531 address_map: HashMap<usize, usize>,
533 clock_hand: usize,
535 stats: PolicyStats,
537}
538
539#[derive(Debug, Clone)]
541struct ClockEntry {
542 address: usize,
543 reference_bit: bool,
544}
545
546impl Default for ClockPolicy {
547 fn default() -> Self {
548 Self::new()
549 }
550}
551
552impl ClockPolicy {
553 pub fn new() -> Self {
554 Self {
555 clock_list: Vec::new(),
556 address_map: HashMap::new(),
557 clock_hand: 0,
558 stats: PolicyStats::default(),
559 }
560 }
561
562 fn advance_clock(&mut self) -> Option<usize> {
563 if self.clock_list.is_empty() {
564 return None;
565 }
566
567 let start_pos = self.clock_hand;
568
569 loop {
570 let entry = &mut self.clock_list[self.clock_hand];
571
572 if entry.reference_bit {
573 entry.reference_bit = false;
575 } else {
576 let victim = entry.address;
578 self.clock_hand = (self.clock_hand + 1) % self.clock_list.len();
579 return Some(victim);
580 }
581
582 self.clock_hand = (self.clock_hand + 1) % self.clock_list.len();
583
584 if self.clock_hand == start_pos {
585 break;
587 }
588 }
589
590 if !self.clock_list.is_empty() {
592 Some(self.clock_list[0].address)
593 } else {
594 None
595 }
596 }
597}
598
599impl EvictionPolicy for ClockPolicy {
600 fn name(&self) -> &str {
601 "Clock"
602 }
603
604 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize> {
605 let mut victims = Vec::new();
606 let mut bytes_selected = 0;
607
608 while bytes_selected < target_bytes {
609 if let Some(victim_addr) = self.advance_clock() {
610 if let Some(object) = region.objects.get(&victim_addr) {
611 victims.push(victim_addr);
612 bytes_selected += object.size;
613 }
614 } else {
615 break;
616 }
617 }
618
619 self.stats.evictions += victims.len() as u64;
620 self.stats.bytes_evicted += bytes_selected as u64;
621
622 victims
623 }
624
625 fn update_access(&mut self, address: usize, _object: &CacheObject) {
626 if let Some(&index) = self.address_map.get(&address) {
627 if index < self.clock_list.len() {
628 self.clock_list[index].reference_bit = true;
629 }
630 }
631 }
632
633 fn add_object(&mut self, address: usize, _object: &CacheObject) {
634 let entry = ClockEntry {
635 address,
636 reference_bit: true,
637 };
638
639 self.clock_list.push(entry);
640 self.address_map.insert(address, self.clock_list.len() - 1);
641 }
642
643 fn remove_object(&mut self, address: usize) {
644 if let Some(&index) = self.address_map.get(&address) {
645 if index < self.clock_list.len() {
646 self.clock_list.remove(index);
647 self.address_map.remove(&address);
648
649 for i in index..self.clock_list.len() {
651 let addr = self.clock_list[i].address;
652 self.address_map.insert(addr, i);
653 }
654
655 if self.clock_hand > index {
657 self.clock_hand -= 1;
658 } else if self.clock_hand >= self.clock_list.len() && !self.clock_list.is_empty() {
659 self.clock_hand = 0;
660 }
661 }
662 }
663 }
664
665 fn get_statistics(&self) -> PolicyStats {
666 self.stats.clone()
667 }
668
669 fn configure(&mut self, _config: &EvictionConfig) {
670 }
672
673 fn reset(&mut self) {
674 self.clock_list.clear();
675 self.address_map.clear();
676 self.clock_hand = 0;
677 self.stats = PolicyStats::default();
678 }
679}
680
681pub struct ARCPolicy {
683 t1: VecDeque<usize>,
685 t2: VecDeque<usize>,
687 b1: VecDeque<usize>,
689 b2: VecDeque<usize>,
691 p: usize,
693 capacity: usize,
695 stats: PolicyStats,
697}
698
699impl ARCPolicy {
700 pub fn new(capacity: usize) -> Self {
701 Self {
702 t1: VecDeque::new(),
703 t2: VecDeque::new(),
704 b1: VecDeque::new(),
705 b2: VecDeque::new(),
706 p: 0,
707 capacity,
708 stats: PolicyStats::default(),
709 }
710 }
711
712 fn replace(&mut self, address: usize) -> Option<usize> {
713 let t1_len = self.t1.len();
714
715 if t1_len > 0 && (t1_len > self.p || (self.b2.contains(&address) && t1_len == self.p)) {
716 if let Some(victim) = self.t1.pop_front() {
718 self.b1.push_back(victim);
719 if self.b1.len() > self.capacity {
720 self.b1.pop_front();
721 }
722 return Some(victim);
723 }
724 } else {
725 if let Some(victim) = self.t2.pop_front() {
727 self.b2.push_back(victim);
728 if self.b2.len() > self.capacity {
729 self.b2.pop_front();
730 }
731 return Some(victim);
732 }
733 }
734
735 None
736 }
737
738 fn adapt(&mut self, address: usize) {
739 let delta = if self.b1.len() >= self.b2.len() {
740 1
741 } else {
742 self.b2.len() / self.b1.len().max(1)
743 };
744
745 if self.b1.contains(&address) {
746 self.p = (self.p + delta).min(self.capacity);
747 } else if self.b2.contains(&address) {
748 self.p = self.p.saturating_sub(delta);
749 }
750 }
751}
752
753impl EvictionPolicy for ARCPolicy {
754 fn name(&self) -> &str {
755 "ARC"
756 }
757
758 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize> {
759 let mut victims = Vec::new();
760 let mut bytes_selected = 0;
761
762 while bytes_selected < target_bytes {
763 if let Some(victim_addr) = self.replace(0) {
764 if let Some(object) = region.objects.get(&victim_addr) {
766 victims.push(victim_addr);
767 bytes_selected += object.size;
768 }
769 } else {
770 break;
771 }
772 }
773
774 self.stats.evictions += victims.len() as u64;
775 self.stats.bytes_evicted += bytes_selected as u64;
776
777 victims
778 }
779
780 fn update_access(&mut self, address: usize, _object: &CacheObject) {
781 if self.t1.contains(&address) {
783 if let Some(pos) = self.t1.iter().position(|&addr| addr == address) {
785 self.t1.remove(pos);
786 self.t2.push_back(address);
787 }
788 } else if self.t2.contains(&address) {
789 if let Some(pos) = self.t2.iter().position(|&addr| addr == address) {
791 self.t2.remove(pos);
792 self.t2.push_back(address);
793 }
794 }
795 }
796
797 fn add_object(&mut self, address: usize, _object: &CacheObject) {
798 if self.b1.contains(&address) {
799 self.adapt(address);
800 self.b1.retain(|&addr| addr != address);
801 self.t2.push_back(address);
802 } else if self.b2.contains(&address) {
803 self.adapt(address);
804 self.b2.retain(|&addr| addr != address);
805 self.t2.push_back(address);
806 } else {
807 self.t1.push_back(address);
808 }
809 }
810
811 fn remove_object(&mut self, address: usize) {
812 self.t1.retain(|&addr| addr != address);
813 self.t2.retain(|&addr| addr != address);
814 self.b1.retain(|&addr| addr != address);
815 self.b2.retain(|&addr| addr != address);
816 }
817
818 fn get_statistics(&self) -> PolicyStats {
819 self.stats.clone()
820 }
821
822 fn configure(&mut self, _config: &EvictionConfig) {
823 }
825
826 fn reset(&mut self) {
827 self.t1.clear();
828 self.t2.clear();
829 self.b1.clear();
830 self.b2.clear();
831 self.p = 0;
832 self.stats = PolicyStats::default();
833 }
834}
835
836pub struct WorkloadAwarePolicy {
838 base_policy: Box<dyn EvictionPolicy>,
840 kernel_weights: HashMap<u32, f64>,
842 type_priorities: HashMap<ObjectType, f64>,
844 stats: PolicyStats,
846}
847
848impl WorkloadAwarePolicy {
849 pub fn new(base_policy: Box<dyn EvictionPolicy>) -> Self {
850 let mut type_priorities = HashMap::new();
851 type_priorities.insert(ObjectType::Critical, 10.0);
852 type_priorities.insert(ObjectType::Persistent, 5.0);
853 type_priorities.insert(ObjectType::Data, 2.0);
854 type_priorities.insert(ObjectType::Texture, 1.5);
855 type_priorities.insert(ObjectType::Constant, 1.0);
856 type_priorities.insert(ObjectType::Temporary, 0.5);
857
858 Self {
859 base_policy,
860 kernel_weights: HashMap::new(),
861 type_priorities,
862 stats: PolicyStats::default(),
863 }
864 }
865
866 fn calculate_eviction_priority(&self, object: &CacheObject) -> f64 {
867 let mut priority = object.calculate_utility();
868
869 if let Some(&type_priority) = self.type_priorities.get(&object.object_type) {
871 priority *= type_priority;
872 }
873
874 if let Some(kernel_id) = object.kernel_context {
876 if let Some(&weight) = self.kernel_weights.get(&kernel_id) {
877 priority *= weight;
878 }
879 }
880
881 let priority_multiplier = match object.priority {
883 ObjectPriority::Critical => 100.0,
884 ObjectPriority::High => 10.0,
885 ObjectPriority::Normal => 1.0,
886 ObjectPriority::Low => 0.1,
887 };
888
889 priority * priority_multiplier
890 }
891}
892
893impl EvictionPolicy for WorkloadAwarePolicy {
894 fn name(&self) -> &str {
895 "WorkloadAware"
896 }
897
898 fn select_victims(&mut self, region: &MemoryRegion, target_bytes: usize) -> Vec<usize> {
899 let mut object_priorities: Vec<(usize, f64)> = region
901 .objects
902 .iter()
903 .map(|(&addr, obj)| (addr, self.calculate_eviction_priority(obj)))
904 .collect();
905
906 object_priorities
908 .sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
909
910 let mut victims = Vec::new();
911 let mut bytes_selected = 0;
912
913 for (address, _priority) in object_priorities {
914 if let Some(object) = region.objects.get(&address) {
915 victims.push(address);
916 bytes_selected += object.size;
917
918 if bytes_selected >= target_bytes {
919 break;
920 }
921 }
922 }
923
924 self.stats.evictions += victims.len() as u64;
925 self.stats.bytes_evicted += bytes_selected as u64;
926
927 victims
928 }
929
930 fn update_access(&mut self, address: usize, object: &CacheObject) {
931 self.base_policy.update_access(address, object);
932
933 if let Some(kernel_id) = object.kernel_context {
935 let weight = self.kernel_weights.entry(kernel_id).or_insert(1.0);
936 *weight = (*weight * 0.9 + 1.1).min(10.0); }
938 }
939
940 fn add_object(&mut self, address: usize, object: &CacheObject) {
941 self.base_policy.add_object(address, object);
942 }
943
944 fn remove_object(&mut self, address: usize) {
945 self.base_policy.remove_object(address);
946 }
947
948 fn get_statistics(&self) -> PolicyStats {
949 let mut stats = self.stats.clone();
950 let base_stats = self.base_policy.get_statistics();
951
952 stats.evictions += base_stats.evictions;
954 stats.bytes_evicted += base_stats.bytes_evicted;
955
956 stats
957 }
958
959 fn configure(&mut self, config: &EvictionConfig) {
960 self.base_policy.configure(config);
961 }
962
963 fn reset(&mut self) {
964 self.base_policy.reset();
965 self.kernel_weights.clear();
966 self.stats = PolicyStats::default();
967 }
968}
969
970pub struct EvictionPerformanceMonitor {
972 history: VecDeque<EvictionPerformance>,
974 policy_performance: HashMap<String, Vec<f64>>,
976 config: MonitorConfig,
978}
979
980#[derive(Debug, Clone)]
982pub struct EvictionPerformance {
983 pub timestamp: Instant,
984 pub policy_name: String,
985 pub eviction_time: Duration,
986 pub bytes_evicted: usize,
987 pub objects_evicted: usize,
988 pub accuracy_score: f64,
989}
990
991#[derive(Debug, Clone)]
993pub struct MonitorConfig {
994 pub history_size: usize,
995 pub performance_window: usize,
996 pub enable_adaptive: bool,
997}
998
999impl Default for MonitorConfig {
1000 fn default() -> Self {
1001 Self {
1002 history_size: 1000,
1003 performance_window: 100,
1004 enable_adaptive: true,
1005 }
1006 }
1007}
1008
1009impl EvictionPerformanceMonitor {
1010 pub fn new(config: MonitorConfig) -> Self {
1011 Self {
1012 history: VecDeque::with_capacity(config.history_size),
1013 policy_performance: HashMap::new(),
1014 config,
1015 }
1016 }
1017
1018 pub fn record_performance(&mut self, performance: EvictionPerformance) {
1020 self.history.push_back(performance.clone());
1021 if self.history.len() > self.config.history_size {
1022 self.history.pop_front();
1023 }
1024
1025 let scores = self
1027 .policy_performance
1028 .entry(performance.policy_name.clone())
1029 .or_default();
1030
1031 scores.push(performance.accuracy_score);
1032 if scores.len() > self.config.performance_window {
1033 scores.remove(0);
1034 }
1035 }
1036
1037 pub fn get_best_policy(&self) -> Option<String> {
1039 if !self.config.enable_adaptive {
1040 return None;
1041 }
1042
1043 let mut best_policy = None;
1044 let mut best_score = 0.0;
1045
1046 for (policy_name, scores) in &self.policy_performance {
1047 if scores.len() >= 5 {
1048 let avg_score = scores.iter().sum::<f64>() / scores.len() as f64;
1050 if avg_score > best_score {
1051 best_score = avg_score;
1052 best_policy = Some(policy_name.clone());
1053 }
1054 }
1055 }
1056
1057 best_policy
1058 }
1059}
1060
1061#[derive(Debug, Clone)]
1063pub struct PolicySelection {
1064 pub timestamp: Instant,
1065 pub policy_name: String,
1066 pub reason: String,
1067 pub performance_score: f64,
1068}
1069
1070impl EvictionEngine {
1071 pub fn new(config: EvictionConfig) -> Self {
1072 let mut policies: HashMap<String, Box<dyn EvictionPolicy>> = HashMap::new();
1073
1074 policies.insert("LRU".to_string(), Box::new(LRUPolicy::new()));
1076 policies.insert("LFU".to_string(), Box::new(LFUPolicy::new()));
1077 policies.insert("FIFO".to_string(), Box::new(FIFOPolicy::new()));
1078 policies.insert("Clock".to_string(), Box::new(ClockPolicy::new()));
1079 policies.insert("ARC".to_string(), Box::new(ARCPolicy::new(1000)));
1080
1081 if config.workload_aware {
1082 let base_policy = Box::new(LRUPolicy::new());
1083 policies.insert(
1084 "WorkloadAware".to_string(),
1085 Box::new(WorkloadAwarePolicy::new(base_policy)),
1086 );
1087 }
1088
1089 let active_policy = config.default_policy.clone();
1090 let performance_monitor = EvictionPerformanceMonitor::new(MonitorConfig::default());
1091
1092 Self {
1093 config,
1094 stats: EvictionStats::default(),
1095 policies,
1096 active_policy,
1097 memory_regions: HashMap::new(),
1098 performance_monitor,
1099 policy_history: VecDeque::with_capacity(100),
1100 }
1101 }
1102
1103 pub fn register_region(&mut self, base_addr: usize, size: usize, region_type: RegionType) {
1105 let region = MemoryRegion {
1106 base_addr,
1107 size,
1108 objects: HashMap::new(),
1109 region_type,
1110 pressure: 0.0,
1111 last_eviction: None,
1112 };
1113
1114 self.memory_regions.insert(base_addr, region);
1115 }
1116
1117 pub fn add_object(
1119 &mut self,
1120 region_addr: usize,
1121 object: CacheObject,
1122 ) -> Result<(), EvictionError> {
1123 let region = self
1124 .memory_regions
1125 .get_mut(®ion_addr)
1126 .ok_or_else(|| EvictionError::RegionNotFound("Region not registered".to_string()))?;
1127
1128 for policy in self.policies.values_mut() {
1130 policy.add_object(object.address, &object);
1131 }
1132
1133 region.objects.insert(object.address, object);
1134 Ok(())
1135 }
1136
1137 pub fn update_access(
1139 &mut self,
1140 region_addr: usize,
1141 object_addr: usize,
1142 ) -> Result<(), EvictionError> {
1143 let region = self
1144 .memory_regions
1145 .get_mut(®ion_addr)
1146 .ok_or_else(|| EvictionError::RegionNotFound("Region not found".to_string()))?;
1147
1148 if let Some(object) = region.objects.get_mut(&object_addr) {
1149 object.update_access();
1150
1151 for policy in self.policies.values_mut() {
1153 policy.update_access(object_addr, object);
1154 }
1155 }
1156
1157 Ok(())
1158 }
1159
1160 pub fn should_evict(&self, region_addr: usize) -> bool {
1162 if let Some(region) = self.memory_regions.get(®ion_addr) {
1163 region.pressure > self.config.pressure_threshold
1164 } else {
1165 false
1166 }
1167 }
1168
1169 pub fn evict(
1171 &mut self,
1172 region_addr: usize,
1173 target_bytes: usize,
1174 ) -> Result<Vec<usize>, EvictionError> {
1175 let region = self
1176 .memory_regions
1177 .get(®ion_addr)
1178 .ok_or_else(|| EvictionError::RegionNotFound("Region not found".to_string()))?;
1179
1180 let start_time = Instant::now();
1181
1182 let policy_name = if self.config.enable_adaptive {
1184 self.performance_monitor
1185 .get_best_policy()
1186 .unwrap_or_else(|| self.active_policy.clone())
1187 } else {
1188 self.active_policy.clone()
1189 };
1190
1191 let victims = if let Some(policy) = self.policies.get_mut(&policy_name) {
1192 policy.select_victims(region, target_bytes)
1193 } else {
1194 return Err(EvictionError::PolicyNotFound(
1195 "Policy not available".to_string(),
1196 ));
1197 };
1198
1199 let eviction_time = start_time.elapsed();
1200
1201 if let Some(region) = self.memory_regions.get_mut(®ion_addr) {
1203 for &victim_addr in &victims {
1204 region.objects.remove(&victim_addr);
1205
1206 for policy in self.policies.values_mut() {
1208 policy.remove_object(victim_addr);
1209 }
1210 }
1211
1212 region.last_eviction = Some(Instant::now());
1213 }
1214
1215 self.stats.total_evictions += 1;
1217 self.stats.total_objects_evicted += victims.len() as u64;
1218
1219 let total_eviction_time = self.stats.average_eviction_time.as_nanos() as u64
1220 * (self.stats.total_evictions - 1)
1221 + eviction_time.as_nanos() as u64;
1222 self.stats.average_eviction_time =
1223 Duration::from_nanos(total_eviction_time / self.stats.total_evictions);
1224
1225 let performance = EvictionPerformance {
1227 timestamp: start_time,
1228 policy_name: policy_name.clone(),
1229 eviction_time,
1230 bytes_evicted: target_bytes,
1231 objects_evicted: victims.len(),
1232 accuracy_score: 0.8, };
1234
1235 self.performance_monitor.record_performance(performance);
1236
1237 Ok(victims)
1238 }
1239
1240 pub fn switch_policy(&mut self, policy_name: String) -> Result<(), EvictionError> {
1242 if !self.policies.contains_key(&policy_name) {
1243 return Err(EvictionError::PolicyNotFound(
1244 "Policy not available".to_string(),
1245 ));
1246 }
1247
1248 let selection = PolicySelection {
1249 timestamp: Instant::now(),
1250 policy_name: policy_name.clone(),
1251 reason: "Manual switch".to_string(),
1252 performance_score: 0.0,
1253 };
1254
1255 self.policy_history.push_back(selection);
1256 if self.policy_history.len() > 100 {
1257 self.policy_history.pop_front();
1258 }
1259
1260 self.active_policy = policy_name;
1261 self.stats.policy_switches += 1;
1262
1263 Ok(())
1264 }
1265
1266 pub fn get_stats(&self) -> &EvictionStats {
1268 &self.stats
1269 }
1270
1271 pub fn get_policy_stats(&self) -> HashMap<String, PolicyStats> {
1273 self.policies
1274 .iter()
1275 .map(|(name, policy)| (name.clone(), policy.get_statistics()))
1276 .collect()
1277 }
1278}
1279
1280#[derive(Debug, Clone)]
1282pub enum EvictionError {
1283 RegionNotFound(String),
1284 PolicyNotFound(String),
1285 EvictionFailed(String),
1286 InvalidConfiguration(String),
1287}
1288
1289impl std::fmt::Display for EvictionError {
1290 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1291 match self {
1292 EvictionError::RegionNotFound(msg) => write!(f, "Region not found: {}", msg),
1293 EvictionError::PolicyNotFound(msg) => write!(f, "Policy not found: {}", msg),
1294 EvictionError::EvictionFailed(msg) => write!(f, "Eviction failed: {}", msg),
1295 EvictionError::InvalidConfiguration(msg) => write!(f, "Invalid configuration: {}", msg),
1296 }
1297 }
1298}
1299
1300impl std::error::Error for EvictionError {}
1301
1302pub struct ThreadSafeEvictionEngine {
1304 engine: Arc<RwLock<EvictionEngine>>,
1305}
1306
1307impl ThreadSafeEvictionEngine {
1308 pub fn new(config: EvictionConfig) -> Self {
1309 Self {
1310 engine: Arc::new(RwLock::new(EvictionEngine::new(config))),
1311 }
1312 }
1313
1314 pub fn should_evict(&self, region_addr: usize) -> bool {
1315 let engine = self.engine.read().expect("lock poisoned");
1316 engine.should_evict(region_addr)
1317 }
1318
1319 pub fn evict(
1320 &self,
1321 region_addr: usize,
1322 target_bytes: usize,
1323 ) -> Result<Vec<usize>, EvictionError> {
1324 let mut engine = self.engine.write().expect("lock poisoned");
1325 engine.evict(region_addr, target_bytes)
1326 }
1327
1328 pub fn add_object(&self, region_addr: usize, object: CacheObject) -> Result<(), EvictionError> {
1329 let mut engine = self.engine.write().expect("lock poisoned");
1330 engine.add_object(region_addr, object)
1331 }
1332
1333 pub fn get_stats(&self) -> EvictionStats {
1334 let engine = self.engine.read().expect("lock poisoned");
1335 engine.get_stats().clone()
1336 }
1337}
1338
1339#[cfg(test)]
1340mod tests {
1341 use super::*;
1342
1343 #[test]
1344 fn test_eviction_engine_creation() {
1345 let config = EvictionConfig::default();
1346 let engine = EvictionEngine::new(config);
1347 assert!(!engine.policies.is_empty());
1348 }
1349
1350 #[test]
1351 fn test_lru_policy() {
1352 let mut policy = LRUPolicy::new();
1353 assert_eq!(policy.name(), "LRU");
1354
1355 let object = CacheObject {
1356 address: 0x1000,
1357 size: 64,
1358 created_at: Instant::now(),
1359 last_access: Instant::now(),
1360 access_count: 1,
1361 access_frequency: 1.0,
1362 priority: ObjectPriority::Normal,
1363 kernel_context: None,
1364 object_type: ObjectType::Data,
1365 eviction_cost: 1.0,
1366 replacement_cost: 1.0,
1367 };
1368
1369 policy.add_object(0x1000, &object);
1370 assert_eq!(policy.lru_order.len(), 1);
1371 }
1372
1373 #[test]
1374 fn test_cache_object_utility() {
1375 let object = CacheObject {
1376 address: 0x1000,
1377 size: 64,
1378 created_at: Instant::now() - Duration::from_secs(10),
1379 last_access: Instant::now() - Duration::from_secs(1),
1380 access_count: 5,
1381 access_frequency: 0.5,
1382 priority: ObjectPriority::High,
1383 kernel_context: Some(100),
1384 object_type: ObjectType::Data,
1385 eviction_cost: 1.0,
1386 replacement_cost: 2.0,
1387 };
1388
1389 let utility = object.calculate_utility();
1390 assert!(utility > 0.0);
1391 }
1392
1393 #[test]
1394 fn test_thread_safe_engine() {
1395 let config = EvictionConfig::default();
1396 let engine = ThreadSafeEvictionEngine::new(config);
1397
1398 let stats = engine.get_stats();
1399 assert_eq!(stats.total_evictions, 0);
1400 }
1401}