1use std::collections::{HashMap, VecDeque};
7use std::time::Instant;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
11pub enum AllocationStrategy {
12 FirstFit,
14 BestFit,
16 WorstFit,
18 BuddySystem,
20 SegregatedList,
22 #[default]
24 Adaptive,
25 MLBased,
27 Hybrid,
29}
30
31#[derive(Debug, Clone)]
33pub struct MemoryBlock {
34 pub ptr: *mut u8,
35 pub size: usize,
36 pub is_free: bool,
37 pub allocated_at: Option<Instant>,
38 pub last_accessed: Option<Instant>,
39 pub access_count: u64,
40 pub fragmentation_score: f32,
41}
42
43impl MemoryBlock {
44 pub fn new(ptr: *mut u8, size: usize) -> Self {
45 Self {
46 ptr,
47 size,
48 is_free: true,
49 allocated_at: None,
50 last_accessed: None,
51 access_count: 0,
52 fragmentation_score: 0.0,
53 }
54 }
55
56 pub fn mark_used(&mut self) {
57 self.is_free = false;
58 self.allocated_at = Some(Instant::now());
59 self.access_count += 1;
60 }
61
62 pub fn mark_free(&mut self) {
63 self.is_free = true;
64 self.allocated_at = None;
65 }
66
67 pub fn update_access(&mut self) {
68 self.last_accessed = Some(Instant::now());
69 self.access_count += 1;
70 }
71}
72
73#[derive(Debug, Clone)]
75pub struct AllocationEvent {
76 pub size: usize,
78 pub timestamp: Instant,
80 pub cache_hit: bool,
82 pub latency_us: u64,
84 pub thread_id: Option<u64>,
86 pub kernel_context: Option<String>,
88}
89
90impl AllocationEvent {
91 pub fn new(size: usize, cache_hit: bool, latency_us: u64) -> Self {
92 Self {
93 size,
94 timestamp: Instant::now(),
95 cache_hit,
96 latency_us,
97 thread_id: None,
98 kernel_context: None,
99 }
100 }
101}
102
103#[derive(Debug, Clone, Default)]
105pub struct AllocationStats {
106 pub total_allocations: u64,
107 pub total_deallocations: u64,
108 pub cache_hits: u64,
109 pub cache_misses: u64,
110 pub fragmentation_events: u64,
111 pub total_allocated_bytes: u64,
112 pub peak_allocated_bytes: u64,
113 pub average_allocation_size: f64,
114 pub allocation_latency_ms: f64,
115}
116
117impl AllocationStats {
118 pub fn record_allocation(&mut self, size: usize, cache_hit: bool, latency_us: u64) {
119 self.total_allocations += 1;
120 self.total_allocated_bytes += size as u64;
121
122 if self.total_allocated_bytes > self.peak_allocated_bytes {
123 self.peak_allocated_bytes = self.total_allocated_bytes;
124 }
125
126 if cache_hit {
127 self.cache_hits += 1;
128 } else {
129 self.cache_misses += 1;
130 }
131
132 self.average_allocation_size =
134 self.total_allocated_bytes as f64 / self.total_allocations as f64;
135
136 self.allocation_latency_ms = (self.allocation_latency_ms
138 * (self.total_allocations - 1) as f64
139 + latency_us as f64 / 1000.0)
140 / self.total_allocations as f64;
141 }
142
143 pub fn record_deallocation(&mut self, size: usize) {
144 self.total_deallocations += 1;
145 self.total_allocated_bytes = self.total_allocated_bytes.saturating_sub(size as u64);
146 }
147
148 pub fn get_cache_hit_rate(&self) -> f64 {
149 if self.total_allocations == 0 {
150 0.0
151 } else {
152 self.cache_hits as f64 / self.total_allocations as f64
153 }
154 }
155
156 pub fn get_fragmentation_rate(&self) -> f64 {
157 if self.total_allocations == 0 {
158 0.0
159 } else {
160 self.fragmentation_events as f64 / self.total_allocations as f64
161 }
162 }
163}
164
165pub struct AllocationStrategyManager {
167 strategy: AllocationStrategy,
168 free_blocks: HashMap<usize, VecDeque<MemoryBlock>>,
169 allocation_history: VecDeque<AllocationEvent>,
170 stats: AllocationStats,
171 adaptive_config: AdaptiveConfig,
172 hybrid_config: HybridConfig,
173 ml_config: Option<MLConfig>,
174}
175
176#[derive(Debug, Clone)]
178pub struct AdaptiveConfig {
179 pub history_window: usize,
180 pub small_allocation_threshold: usize,
181 pub large_allocation_threshold: usize,
182 pub fragmentation_threshold: f32,
183 pub enable_pattern_detection: bool,
184 pub adaptation_interval: u64,
185}
186
187impl Default for AdaptiveConfig {
188 fn default() -> Self {
189 Self {
190 history_window: 1000,
191 small_allocation_threshold: 4096,
192 large_allocation_threshold: 1024 * 1024,
193 fragmentation_threshold: 0.3,
194 enable_pattern_detection: true,
195 adaptation_interval: 100,
196 }
197 }
198}
199
200#[derive(Debug, Clone)]
202pub struct HybridConfig {
203 pub primary_strategy: AllocationStrategy,
204 pub secondary_strategy: AllocationStrategy,
205 pub switch_threshold_fragmentation: f32,
206 pub switch_threshold_utilization: f32,
207 pub evaluation_window: usize,
208}
209
210impl Default for HybridConfig {
211 fn default() -> Self {
212 Self {
213 primary_strategy: AllocationStrategy::BestFit,
214 secondary_strategy: AllocationStrategy::FirstFit,
215 switch_threshold_fragmentation: 0.4,
216 switch_threshold_utilization: 0.8,
217 evaluation_window: 100,
218 }
219 }
220}
221
222#[derive(Debug, Clone)]
224pub struct MLConfig {
225 pub model_type: MLModelType,
226 pub feature_window: usize,
227 pub training_interval: u64,
228 pub prediction_confidence_threshold: f32,
229 pub fallback_strategy: AllocationStrategy,
230}
231
232#[derive(Debug, Clone)]
233pub enum MLModelType {
234 LinearRegression,
235 DecisionTree,
236 NeuralNetwork,
237 ReinforcementLearning,
238}
239
240impl AllocationStrategyManager {
241 pub fn new(strategy: AllocationStrategy) -> Self {
242 Self {
243 strategy,
244 free_blocks: HashMap::new(),
245 allocation_history: VecDeque::new(),
246 stats: AllocationStats::default(),
247 adaptive_config: AdaptiveConfig::default(),
248 hybrid_config: HybridConfig::default(),
249 ml_config: None,
250 }
251 }
252
253 pub fn with_adaptive_config(mut self, config: AdaptiveConfig) -> Self {
254 self.adaptive_config = config;
255 self
256 }
257
258 pub fn with_hybrid_config(mut self, config: HybridConfig) -> Self {
259 self.hybrid_config = config;
260 self
261 }
262
263 pub fn with_ml_config(mut self, config: MLConfig) -> Self {
264 self.ml_config = Some(config);
265 self
266 }
267
268 pub fn find_free_block(&mut self, size: usize) -> Option<*mut u8> {
270 let start_time = Instant::now();
271
272 let result = match self.strategy {
273 AllocationStrategy::FirstFit => self.find_first_fit(size),
274 AllocationStrategy::BestFit => self.find_best_fit(size),
275 AllocationStrategy::WorstFit => self.find_worst_fit(size),
276 AllocationStrategy::BuddySystem => self.find_buddy_block(size),
277 AllocationStrategy::SegregatedList => self.find_segregated_block(size),
278 AllocationStrategy::Adaptive => self.find_adaptive_block(size),
279 AllocationStrategy::MLBased => self.find_ml_based_block(size),
280 AllocationStrategy::Hybrid => self.find_hybrid_block(size),
281 };
282
283 let latency_us = start_time.elapsed().as_micros() as u64;
284 let cache_hit = result.is_some();
285
286 self.stats.record_allocation(size, cache_hit, latency_us);
287 self.allocation_history
288 .push_back(AllocationEvent::new(size, cache_hit, latency_us));
289
290 if self.allocation_history.len() > self.adaptive_config.history_window {
292 self.allocation_history.pop_front();
293 }
294
295 result
296 }
297
298 pub fn find_first_fit(&mut self, size: usize) -> Option<*mut u8> {
300 for (&block_size, blocks) in &mut self.free_blocks {
301 if block_size >= size && !blocks.is_empty() {
302 if let Some(mut block) = blocks.pop_front() {
303 block.mark_used();
304 return Some(block.ptr);
305 }
306 }
307 }
308 None
309 }
310
311 pub fn find_best_fit(&mut self, size: usize) -> Option<*mut u8> {
313 let mut best_size = None;
314 let mut best_fit_size = usize::MAX;
315
316 for (&block_size, blocks) in &self.free_blocks {
317 if block_size >= size && block_size < best_fit_size && !blocks.is_empty() {
318 best_fit_size = block_size;
319 best_size = Some(block_size);
320 }
321 }
322
323 if let Some(block_size) = best_size {
324 if let Some(blocks) = self.free_blocks.get_mut(&block_size) {
325 if let Some(mut block) = blocks.pop_front() {
326 block.mark_used();
327 return Some(block.ptr);
328 }
329 }
330 }
331
332 None
333 }
334
335 pub fn find_worst_fit(&mut self, size: usize) -> Option<*mut u8> {
337 let mut worst_size = None;
338 let mut worst_fit_size = 0;
339
340 for (&block_size, blocks) in &self.free_blocks {
341 if block_size >= size && block_size > worst_fit_size && !blocks.is_empty() {
342 worst_fit_size = block_size;
343 worst_size = Some(block_size);
344 }
345 }
346
347 if let Some(block_size) = worst_size {
348 if let Some(blocks) = self.free_blocks.get_mut(&block_size) {
349 if let Some(mut block) = blocks.pop_front() {
350 block.mark_used();
351 return Some(block.ptr);
352 }
353 }
354 }
355
356 None
357 }
358
359 pub fn find_buddy_block(&mut self, size: usize) -> Option<*mut u8> {
361 let buddy_size = size.next_power_of_two();
362
363 if let Some(blocks) = self.free_blocks.get_mut(&buddy_size) {
364 if let Some(mut block) = blocks.pop_front() {
365 block.mark_used();
366 return Some(block.ptr);
367 }
368 }
369
370 None
371 }
372
373 pub fn find_segregated_block(&mut self, size: usize) -> Option<*mut u8> {
375 let size_class = self.get_size_class(size);
376
377 let mut search_sizes: Vec<usize> = self
379 .free_blocks
380 .keys()
381 .filter(|&&s| s >= size_class)
382 .cloned()
383 .collect();
384 search_sizes.sort();
385
386 for class_size in search_sizes {
387 if let Some(blocks) = self.free_blocks.get_mut(&class_size) {
388 if let Some(mut block) = blocks.pop_front() {
389 block.mark_used();
390 return Some(block.ptr);
391 }
392 }
393 }
394
395 None
396 }
397
398 pub fn find_adaptive_block(&mut self, size: usize) -> Option<*mut u8> {
400 let pattern = self.analyze_allocation_patterns();
402
403 let chosen_strategy = match pattern {
405 AllocationPattern::SmallFrequent => AllocationStrategy::FirstFit,
406 AllocationPattern::LargeInfrequent => AllocationStrategy::BestFit,
407 AllocationPattern::Mixed => AllocationStrategy::WorstFit,
408 AllocationPattern::Sequential => AllocationStrategy::SegregatedList,
409 AllocationPattern::Random => AllocationStrategy::BuddySystem,
410 AllocationPattern::Unknown => AllocationStrategy::BestFit,
411 };
412
413 match chosen_strategy {
415 AllocationStrategy::FirstFit => self.find_first_fit(size),
416 AllocationStrategy::BestFit => self.find_best_fit(size),
417 AllocationStrategy::WorstFit => self.find_worst_fit(size),
418 AllocationStrategy::SegregatedList => self.find_segregated_block(size),
419 AllocationStrategy::BuddySystem => self.find_buddy_block(size),
420 _ => self.find_best_fit(size), }
422 }
423
424 pub fn find_ml_based_block(&mut self, size: usize) -> Option<*mut u8> {
426 if let Some(ml_config) = self.ml_config.clone() {
427 let features = self.extract_ml_features(size);
429
430 let prediction = self.predict_best_strategy(&features, &ml_config);
432
433 if prediction.confidence >= ml_config.prediction_confidence_threshold as f64 {
435 match prediction.strategy {
436 AllocationStrategy::FirstFit => self.find_first_fit(size),
437 AllocationStrategy::BestFit => self.find_best_fit(size),
438 AllocationStrategy::WorstFit => self.find_worst_fit(size),
439 AllocationStrategy::BuddySystem => self.find_buddy_block(size),
440 AllocationStrategy::SegregatedList => self.find_segregated_block(size),
441 _ => self.apply_fallback_strategy(size, &ml_config.fallback_strategy),
442 }
443 } else {
444 self.apply_fallback_strategy(size, &ml_config.fallback_strategy)
446 }
447 } else {
448 self.find_best_fit(size)
450 }
451 }
452
453 pub fn find_hybrid_block(&mut self, size: usize) -> Option<*mut u8> {
455 let fragmentation_level = self.calculate_fragmentation_level();
457 let utilization_level = self.calculate_utilization_level();
458
459 let chosen_strategy = if fragmentation_level
461 > self.hybrid_config.switch_threshold_fragmentation as f64
462 || utilization_level > self.hybrid_config.switch_threshold_utilization as f64
463 {
464 self.hybrid_config.secondary_strategy.clone()
465 } else {
466 self.hybrid_config.primary_strategy.clone()
467 };
468
469 self.apply_fallback_strategy(size, &chosen_strategy)
471 }
472
473 fn apply_fallback_strategy(
474 &mut self,
475 size: usize,
476 strategy: &AllocationStrategy,
477 ) -> Option<*mut u8> {
478 match strategy {
479 AllocationStrategy::FirstFit => self.find_first_fit(size),
480 AllocationStrategy::BestFit => self.find_best_fit(size),
481 AllocationStrategy::WorstFit => self.find_worst_fit(size),
482 AllocationStrategy::BuddySystem => self.find_buddy_block(size),
483 AllocationStrategy::SegregatedList => self.find_segregated_block(size),
484 AllocationStrategy::Adaptive => self.find_adaptive_block(size),
485 _ => self.find_best_fit(size), }
487 }
488
489 pub fn analyze_allocation_patterns(&self) -> AllocationPattern {
491 if self.allocation_history.len() < 10 {
492 return AllocationPattern::Unknown;
493 }
494
495 let recent_history: Vec<&AllocationEvent> =
496 self.allocation_history.iter().rev().take(50).collect();
497
498 let sizes: Vec<usize> = recent_history.iter().map(|e| e.size).collect();
500 let small_count = sizes
501 .iter()
502 .filter(|&&s| s < self.adaptive_config.small_allocation_threshold)
503 .count();
504 let large_count = sizes
505 .iter()
506 .filter(|&&s| s > self.adaptive_config.large_allocation_threshold)
507 .count();
508
509 let time_diffs: Vec<u128> = recent_history
511 .windows(2)
512 .map(|w| w[0].timestamp.duration_since(w[1].timestamp).as_millis())
513 .collect();
514 let avg_interval = if !time_diffs.is_empty() {
515 time_diffs.iter().sum::<u128>() / time_diffs.len() as u128
516 } else {
517 0
518 };
519
520 if small_count > recent_history.len() * 8 / 10 && avg_interval < 100 {
522 AllocationPattern::SmallFrequent
523 } else if large_count > recent_history.len() / 2 {
524 AllocationPattern::LargeInfrequent
525 } else if self.is_sequential_pattern(&sizes) {
526 AllocationPattern::Sequential
527 } else if self.is_random_pattern(&sizes) {
528 AllocationPattern::Random
529 } else {
530 AllocationPattern::Mixed
531 }
532 }
533
534 fn is_sequential_pattern(&self, sizes: &[usize]) -> bool {
535 if sizes.len() < 3 {
536 return false;
537 }
538
539 let mut increasing = 0;
540 let mut decreasing = 0;
541
542 for window in sizes.windows(2) {
543 if window[1] > window[0] {
544 increasing += 1;
545 } else if window[1] < window[0] {
546 decreasing += 1;
547 }
548 }
549
550 let trend_ratio = (increasing.max(decreasing) as f64) / (sizes.len() - 1) as f64;
552 trend_ratio > 0.7
553 }
554
555 fn is_random_pattern(&self, sizes: &[usize]) -> bool {
556 if sizes.len() < 5 {
557 return false;
558 }
559
560 let mean = sizes.iter().sum::<usize>() as f64 / sizes.len() as f64;
562 let variance = sizes
563 .iter()
564 .map(|&s| (s as f64 - mean).powi(2))
565 .sum::<f64>()
566 / sizes.len() as f64;
567 let std_dev = variance.sqrt();
568 let cv = std_dev / mean;
569
570 cv > 0.5
572 }
573
574 fn extract_ml_features(&self, size: usize) -> MLFeatures {
576 let recent_history: Vec<&AllocationEvent> = self
577 .allocation_history
578 .iter()
579 .rev()
580 .take(
581 self.ml_config
582 .as_ref()
583 .map(|c| c.feature_window)
584 .unwrap_or(20),
585 )
586 .collect();
587
588 let avg_size = if !recent_history.is_empty() {
589 recent_history.iter().map(|e| e.size).sum::<usize>() as f64
590 / recent_history.len() as f64
591 } else {
592 0.0
593 };
594
595 let avg_latency = if !recent_history.is_empty() {
596 recent_history.iter().map(|e| e.latency_us).sum::<u64>() as f64
597 / recent_history.len() as f64
598 } else {
599 0.0
600 };
601
602 MLFeatures {
603 requested_size: size as f64,
604 avg_recent_size: avg_size,
605 avg_recent_latency: avg_latency,
606 cache_hit_rate: self.stats.get_cache_hit_rate(),
607 fragmentation_level: self.calculate_fragmentation_level(),
608 utilization_level: self.calculate_utilization_level(),
609 allocation_frequency: recent_history.len() as f64,
610 }
611 }
612
613 fn predict_best_strategy(&self, features: &MLFeatures, ml_config: &MLConfig) -> MLPrediction {
615 let score_first_fit =
617 self.score_strategy_for_features(features, &AllocationStrategy::FirstFit);
618 let score_best_fit =
619 self.score_strategy_for_features(features, &AllocationStrategy::BestFit);
620 let score_worst_fit =
621 self.score_strategy_for_features(features, &AllocationStrategy::WorstFit);
622 let score_buddy =
623 self.score_strategy_for_features(features, &AllocationStrategy::BuddySystem);
624 let score_segregated =
625 self.score_strategy_for_features(features, &AllocationStrategy::SegregatedList);
626
627 let mut best_strategy = AllocationStrategy::BestFit;
628 let mut _best_score = score_best_fit;
629 let mut confidence = 0.5;
630
631 if score_first_fit > _best_score {
632 best_strategy = AllocationStrategy::FirstFit;
633 _best_score = score_first_fit;
634 }
635 if score_worst_fit > _best_score {
636 best_strategy = AllocationStrategy::WorstFit;
637 _best_score = score_worst_fit;
638 }
639 if score_buddy > _best_score {
640 best_strategy = AllocationStrategy::BuddySystem;
641 _best_score = score_buddy;
642 }
643 if score_segregated > _best_score {
644 best_strategy = AllocationStrategy::SegregatedList;
645 _best_score = score_segregated;
646 }
647
648 let mut scores = [
650 score_first_fit,
651 score_best_fit,
652 score_worst_fit,
653 score_buddy,
654 score_segregated,
655 ];
656 scores.sort_by(|a, b| b.total_cmp(a));
657 if scores.len() >= 2 {
658 confidence = (scores[0] - scores[1]).clamp(0.0, 1.0);
659 }
660
661 let strategy = if (confidence as f32) < ml_config.prediction_confidence_threshold {
665 ml_config.fallback_strategy.clone()
666 } else {
667 best_strategy
668 };
669
670 MLPrediction {
671 strategy,
672 confidence,
673 predicted_latency: features.avg_recent_latency,
674 }
675 }
676
677 fn score_strategy_for_features(
678 &self,
679 features: &MLFeatures,
680 strategy: &AllocationStrategy,
681 ) -> f64 {
682 match strategy {
684 AllocationStrategy::FirstFit => {
685 let size_score = if features.requested_size < 4096.0 {
687 0.8
688 } else {
689 0.3
690 };
691 let freq_score = if features.allocation_frequency > 10.0 {
692 0.9
693 } else {
694 0.4
695 };
696 (size_score + freq_score) / 2.0
697 }
698 AllocationStrategy::BestFit => {
699 let util_score = if features.utilization_level > 0.7 {
701 0.9
702 } else {
703 0.6
704 };
705 let frag_score = if features.fragmentation_level < 0.3 {
706 0.8
707 } else {
708 0.4
709 };
710 (util_score + frag_score) / 2.0
711 }
712 AllocationStrategy::WorstFit => {
713 if features.fragmentation_level > 0.4 {
716 0.8
717 } else {
718 0.3
719 }
720 }
721 AllocationStrategy::BuddySystem => {
722 if features.requested_size.log2().fract() < 0.1 {
725 0.9
726 } else {
727 0.4
728 }
729 }
730 AllocationStrategy::SegregatedList
731 if features.cache_hit_rate > 0.6 => {
734 0.7
735 }
736 _ => 0.5, }
738 }
739
740 fn calculate_fragmentation_level(&self) -> f64 {
741 if self.free_blocks.is_empty() {
743 return 0.0;
744 }
745
746 let total_free_space: usize = self
747 .free_blocks
748 .iter()
749 .map(|(size, blocks)| size * blocks.len())
750 .sum();
751
752 let free_block_count: usize = self.free_blocks.values().map(|blocks| blocks.len()).sum();
753
754 if total_free_space == 0 {
755 0.0
756 } else {
757 let avg_block_size = total_free_space as f64 / free_block_count as f64;
758 let fragmentation = 1.0 - (avg_block_size / total_free_space as f64);
759 fragmentation.clamp(0.0, 1.0)
760 }
761 }
762
763 fn calculate_utilization_level(&self) -> f64 {
764 let total_capacity = self.stats.peak_allocated_bytes as f64;
766 let current_allocated = self.stats.total_allocated_bytes as f64;
767
768 if total_capacity == 0.0 {
769 0.0
770 } else {
771 (current_allocated / total_capacity).clamp(0.0, 1.0)
772 }
773 }
774
775 pub fn get_size_class(&self, size: usize) -> usize {
777 match size {
778 0..=256 => 256,
779 257..=512 => 512,
780 513..=1024 => 1024,
781 1025..=2048 => 2048,
782 2049..=4096 => 4096,
783 4097..=8192 => 8192,
784 8193..=16384 => 16384,
785 16385..=32768 => 32768,
786 32769..=65536 => 65536,
787 65537..=131072 => 131072,
788 131073..=262144 => 262144,
789 262145..=524288 => 524288,
790 524289..=1048576 => 1048576,
791 _ => size.next_power_of_two(),
792 }
793 }
794
795 pub fn add_free_block(&mut self, block: MemoryBlock) {
797 let size_class = self.get_size_class(block.size);
798 self.free_blocks
799 .entry(size_class)
800 .or_default()
801 .push_back(block);
802 }
803
804 pub fn remove_free_block(&mut self, size: usize, ptr: *mut u8) -> Option<MemoryBlock> {
806 let size_class = self.get_size_class(size);
807 if let Some(blocks) = self.free_blocks.get_mut(&size_class) {
808 if let Some(pos) = blocks.iter().position(|block| block.ptr == ptr) {
809 return blocks.remove(pos);
810 }
811 }
812 None
813 }
814
815 pub fn get_stats(&self) -> &AllocationStats {
817 &self.stats
818 }
819
820 pub fn get_strategy(&self) -> &AllocationStrategy {
822 &self.strategy
823 }
824
825 pub fn set_strategy(&mut self, strategy: AllocationStrategy) {
827 self.strategy = strategy;
828 }
829
830 pub fn clear_history(&mut self) {
832 self.allocation_history.clear();
833 }
834
835 pub fn get_history(&self) -> &VecDeque<AllocationEvent> {
837 &self.allocation_history
838 }
839}
840
841#[derive(Debug, Clone, PartialEq, Eq, Hash)]
843pub enum AllocationPattern {
844 SmallFrequent,
845 LargeInfrequent,
846 Mixed,
847 Sequential,
848 Random,
849 Unknown,
850}
851
852#[derive(Debug, Clone)]
854pub struct MLFeatures {
855 pub requested_size: f64,
856 pub avg_recent_size: f64,
857 pub avg_recent_latency: f64,
858 pub cache_hit_rate: f64,
859 pub fragmentation_level: f64,
860 pub utilization_level: f64,
861 pub allocation_frequency: f64,
862}
863
864#[derive(Debug, Clone)]
866pub struct MLPrediction {
867 pub strategy: AllocationStrategy,
868 pub confidence: f64,
869 pub predicted_latency: f64,
870}
871
872#[cfg(test)]
873mod tests {
874 use super::*;
875
876 #[test]
877 fn test_predict_best_strategy_falls_back_below_confidence_threshold() {
878 let manager = AllocationStrategyManager::new(AllocationStrategy::BestFit);
879 let features = MLFeatures {
880 requested_size: 8192.0,
881 avg_recent_size: 8192.0,
882 avg_recent_latency: 10.0,
883 cache_hit_rate: 0.5,
884 fragmentation_level: 0.2,
885 utilization_level: 0.5,
886 allocation_frequency: 10.0,
887 };
888
889 let unreachable_threshold = MLConfig {
893 model_type: MLModelType::LinearRegression,
894 feature_window: 10,
895 training_interval: 100,
896 prediction_confidence_threshold: 1.1,
897 fallback_strategy: AllocationStrategy::WorstFit,
898 };
899 let prediction = manager.predict_best_strategy(&features, &unreachable_threshold);
900 assert_eq!(prediction.strategy, AllocationStrategy::WorstFit);
901
902 let always_reachable = MLConfig {
905 prediction_confidence_threshold: 0.0,
906 fallback_strategy: AllocationStrategy::WorstFit,
907 ..unreachable_threshold
908 };
909 let prediction = manager.predict_best_strategy(&features, &always_reachable);
910 assert_ne!(prediction.strategy, AllocationStrategy::WorstFit);
911 }
912
913 #[test]
914 fn test_allocation_strategies() {
915 let mut manager = AllocationStrategyManager::new(AllocationStrategy::BestFit);
916
917 for i in 0..5 {
919 let block = MemoryBlock::new((i * 1024) as *mut u8, 1024 * (i + 1));
920 manager.add_free_block(block);
921 }
922
923 let ptr = manager.find_free_block(1500);
925 assert!(ptr.is_some());
926
927 let stats = manager.get_stats();
929 assert_eq!(stats.total_allocations, 1);
930 }
931
932 #[test]
933 fn test_size_classes() {
934 let manager = AllocationStrategyManager::new(AllocationStrategy::SegregatedList);
935
936 assert_eq!(manager.get_size_class(100), 256);
937 assert_eq!(manager.get_size_class(300), 512);
938 assert_eq!(manager.get_size_class(1000), 1024);
939 assert_eq!(manager.get_size_class(2000000), 2097152);
940 }
941
942 #[test]
943 fn test_adaptive_strategy() {
944 let mut manager = AllocationStrategyManager::new(AllocationStrategy::Adaptive);
945
946 for _ in 0..20 {
948 let event = AllocationEvent::new(256, true, 10);
949 manager.allocation_history.push_back(event);
950 }
951
952 let pattern = manager.analyze_allocation_patterns();
953 assert_eq!(pattern, AllocationPattern::SmallFrequent);
954 }
955
956 #[test]
957 fn test_fragmentation_calculation() {
958 let mut manager = AllocationStrategyManager::new(AllocationStrategy::BestFit);
959
960 manager.add_free_block(MemoryBlock::new(0x1000 as *mut u8, 1024));
962 manager.add_free_block(MemoryBlock::new(0x2000 as *mut u8, 2048));
963 manager.add_free_block(MemoryBlock::new(0x3000 as *mut u8, 512));
964
965 let fragmentation = manager.calculate_fragmentation_level();
966 assert!((0.0..=1.0).contains(&fragmentation));
967 }
968}