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