1use super::resource_types::{
7 AllocatedResources, MemoryUsage, ResourceAllocation, ResourcePoolType, ResourceUsage,
8};
9use super::simd_operations;
10use crate::task_definitions::TaskRequirements;
11use sklears_core::error::{Result as SklResult, SklearsError};
12use std::collections::{HashMap, VecDeque};
13use std::time::{Duration, SystemTime};
14
15#[derive(Debug)]
17pub struct ResourceOptimizer {
18 config: OptimizerConfig,
20 strategies: Vec<Box<dyn OptimizationStrategy>>,
22 state: OptimizerState,
24 history: OptimizationHistory,
26}
27
28#[derive(Debug, Clone)]
30pub struct OptimizerConfig {
31 pub strategy: OptimizationStrategyType,
33 pub rebalancing_interval: Duration,
35 pub enable_predictive_scaling: bool,
37 pub enable_energy_optimization: bool,
39 pub enable_thermal_management: bool,
41 pub aggressiveness: f64,
43 pub performance_weight: f64,
45 pub energy_weight: f64,
47 pub fairness_weight: f64,
49}
50
51#[derive(Debug, Clone)]
53pub enum OptimizationStrategyType {
54 MaxUtilization,
56 MinEnergy,
58 Balanced,
60 MaxThroughput,
62 MinLatency,
64 FairShare,
66 Custom(String),
68}
69
70pub trait OptimizationStrategy: Send + Sync + std::fmt::Debug {
72 fn name(&self) -> &str;
74
75 fn optimize(
77 &self,
78 current_allocations: &[ResourceAllocation],
79 available_resources: &ResourceUsage,
80 pending_requests: &[TaskRequirements],
81 ) -> SklResult<OptimizationResult>;
82
83 fn score(&self, allocations: &[ResourceAllocation], usage: &ResourceUsage) -> f64;
85}
86
87#[derive(Debug, Clone)]
89pub struct OptimizationResult {
90 pub actions: Vec<OptimizationAction>,
92 pub expected_improvement: f64,
94 pub confidence: f64,
96 pub metadata: HashMap<String, String>,
98}
99
100#[derive(Debug, Clone)]
102pub enum OptimizationAction {
103 Reallocate {
105 task_id: String,
106 old_allocation: ResourceAllocation,
107 new_allocation: ResourceAllocation,
108 },
109 Migrate {
111 task_id: String,
112 from_resources: AllocatedResources,
113 to_resources: AllocatedResources,
114 },
115 ScaleUp {
117 resource_type: ResourcePoolType,
118 amount: u64,
119 },
120 ScaleDown {
122 resource_type: ResourcePoolType,
123 amount: u64,
124 },
125 Consolidate {
127 task_ids: Vec<String>,
128 consolidated_allocation: ResourceAllocation,
129 },
130 AdjustFrequency { resource_id: String, frequency: f64 },
132}
133
134#[derive(Debug, Clone)]
136pub struct OptimizerState {
137 pub running: bool,
139 pub last_optimization: SystemTime,
141 pub cycle_count: u64,
143 pub current_score: f64,
145 pub best_score: f64,
147 pub optimizations_performed: u64,
149 pub failed_optimizations: u64,
151}
152
153#[derive(Debug)]
155pub struct OptimizationHistory {
156 events: VecDeque<OptimizationEvent>,
158 performance_trends: VecDeque<PerformanceMeasurement>,
160 energy_trends: VecDeque<EnergyMeasurement>,
162 config: HistoryConfig,
164}
165
166#[derive(Debug, Clone)]
168pub struct OptimizationEvent {
169 pub timestamp: SystemTime,
171 pub event_type: OptimizationEventType,
173 pub actions: Vec<OptimizationAction>,
175 pub impact: OptimizationImpact,
177 pub duration: Duration,
179}
180
181#[derive(Debug, Clone)]
183pub enum OptimizationEventType {
184 ScheduledOptimization,
186 ReactiveOptimization,
188 PredictiveOptimization,
190 EmergencyOptimization,
192 UserTriggered,
194}
195
196#[derive(Debug, Clone)]
198pub struct OptimizationImpact {
199 pub performance_delta: f64,
201 pub energy_delta: f64,
203 pub utilization_delta: f64,
205 pub cost_delta: f64,
207}
208
209#[derive(Debug, Clone)]
211pub struct PerformanceMeasurement {
212 pub timestamp: SystemTime,
214 pub performance_score: f64,
216 pub throughput: f64,
218 pub avg_latency: Duration,
220 pub p95_latency: Duration,
222 pub resource_efficiency: f64,
224}
225
226#[derive(Debug, Clone)]
228pub struct EnergyMeasurement {
229 pub timestamp: SystemTime,
231 pub total_power: f64,
233 pub cpu_power: f64,
235 pub gpu_power: f64,
237 pub memory_power: f64,
239 pub network_power: f64,
241 pub storage_power: f64,
243 pub power_efficiency: f64,
245}
246
247#[derive(Debug, Clone)]
249pub struct HistoryConfig {
250 pub max_history_size: usize,
252 pub measurement_interval: Duration,
254 pub detailed_tracking: bool,
256}
257
258#[derive(Debug)]
260pub struct ResourcePredictionEngine {
261 models: HashMap<String, Box<dyn PredictionModel>>,
263 config: PredictionConfig,
265 historical_data: PredictionHistory,
267 current_predictions: HashMap<String, ResourcePrediction>,
269}
270
271#[derive(Debug, Clone)]
273pub struct PredictionConfig {
274 pub prediction_horizon: Duration,
276 pub model_update_interval: Duration,
278 pub confidence_threshold: f64,
280 pub enable_ensemble: bool,
282 pub historical_window: Duration,
284}
285
286pub trait PredictionModel: Send + Sync + std::fmt::Debug {
288 fn name(&self) -> &str;
290
291 fn train(&mut self, data: &PredictionHistory) -> SklResult<()>;
293
294 fn predict(&self, context: &PredictionContext) -> SklResult<ResourcePrediction>;
296
297 fn accuracy(&self) -> f64;
299
300 fn update(&mut self, actual: &ResourceUsage, predicted: &ResourcePrediction) -> SklResult<()>;
302}
303
304#[derive(Debug, Clone)]
306pub struct PredictionContext {
307 pub current_usage: ResourceUsage,
309 pub time_of_day: u32, pub day_of_week: u8,
313 pub workload_characteristics: WorkloadCharacteristics,
315 pub external_factors: HashMap<String, f64>,
317}
318
319#[derive(Debug, Clone)]
321pub struct WorkloadCharacteristics {
322 pub active_tasks: u32,
324 pub avg_complexity: f64,
326 pub workload_types: HashMap<String, f64>,
328 pub requirement_pattern: ResourceRequirementPattern,
330}
331
332#[derive(Debug, Clone)]
334pub struct ResourceRequirementPattern {
335 pub cpu_intensity: f64,
337 pub memory_intensity: f64,
339 pub gpu_intensity: f64,
341 pub network_intensity: f64,
343 pub storage_intensity: f64,
345 pub temporal_pattern: TemporalPattern,
347}
348
349#[derive(Debug, Clone)]
351pub enum TemporalPattern {
352 Constant,
354 Periodic { period: Duration },
356 Trending { trend: f64 },
358 Burst { burst_duration: Duration },
360 Random,
362}
363
364#[derive(Debug, Clone)]
366pub struct ResourcePrediction {
367 pub predicted_usage: ResourceUsage,
369 pub confidence: f64,
371 pub horizon: Duration,
373 pub timestamp: SystemTime,
375 pub model_name: String,
377 pub intervals: PredictionIntervals,
379}
380
381#[derive(Debug, Clone)]
383pub struct PredictionIntervals {
384 pub lower: ResourceUsage,
386 pub upper: ResourceUsage,
388 pub std_dev: ResourceUsageVariance,
390}
391
392#[derive(Debug, Clone)]
394pub struct ResourceUsageVariance {
395 pub cpu_variance: f64,
397 pub memory_variance: f64,
399 pub gpu_variance: Vec<f64>,
401 pub network_variance: f64,
403 pub storage_variance: f64,
405}
406
407#[derive(Debug)]
409pub struct PredictionHistory {
410 usage_samples: VecDeque<UsageSample>,
412 workload_samples: VecDeque<WorkloadSample>,
414 performance_samples: VecDeque<PerformanceSample>,
416}
417
418#[derive(Debug, Clone)]
420pub struct UsageSample {
421 pub timestamp: SystemTime,
423 pub usage: ResourceUsage,
425 pub context: PredictionContext,
427}
428
429#[derive(Debug, Clone)]
431pub struct WorkloadSample {
432 pub timestamp: SystemTime,
434 pub characteristics: WorkloadCharacteristics,
436 pub queue_length: u32,
438}
439
440#[derive(Debug, Clone)]
442pub struct PerformanceSample {
443 pub timestamp: SystemTime,
445 pub metrics: PerformanceMeasurement,
447}
448
449impl Default for ResourceOptimizer {
450 fn default() -> Self {
451 Self::new()
452 }
453}
454
455impl ResourceOptimizer {
456 #[must_use]
458 pub fn new() -> Self {
459 Self {
460 config: OptimizerConfig::default(),
461 strategies: Vec::new(),
462 state: OptimizerState {
463 running: false,
464 last_optimization: SystemTime::now(),
465 cycle_count: 0,
466 current_score: 0.0,
467 best_score: 0.0,
468 optimizations_performed: 0,
469 failed_optimizations: 0,
470 },
471 history: OptimizationHistory {
472 events: VecDeque::new(),
473 performance_trends: VecDeque::new(),
474 energy_trends: VecDeque::new(),
475 config: HistoryConfig {
476 max_history_size: 10000,
477 measurement_interval: Duration::from_secs(60),
478 detailed_tracking: true,
479 },
480 },
481 }
482 }
483
484 pub fn add_strategy(&mut self, strategy: Box<dyn OptimizationStrategy>) {
486 self.strategies.push(strategy);
487 }
488
489 pub fn start_optimization(&mut self) -> SklResult<()> {
491 self.state.running = true;
492 Ok(())
493 }
494
495 pub fn stop_optimization(&mut self) -> SklResult<()> {
497 self.state.running = false;
498 Ok(())
499 }
500
501 pub fn optimize(
503 &mut self,
504 current_allocations: &[ResourceAllocation],
505 available_resources: &ResourceUsage,
506 pending_requests: &[TaskRequirements],
507 ) -> SklResult<OptimizationResult> {
508 let mut best_result = OptimizationResult {
509 actions: Vec::new(),
510 expected_improvement: 0.0,
511 confidence: 0.0,
512 metadata: HashMap::new(),
513 };
514
515 for strategy in &self.strategies {
517 let result =
518 strategy.optimize(current_allocations, available_resources, pending_requests)?;
519 if result.expected_improvement > best_result.expected_improvement {
520 best_result = result;
521 }
522 }
523
524 self.state.cycle_count += 1;
526 self.state.last_optimization = SystemTime::now();
527
528 Ok(best_result)
529 }
530
531 #[must_use]
533 pub fn calculate_optimization_score(
534 &self,
535 allocations: &[ResourceAllocation],
536 usage: &ResourceUsage,
537 ) -> f64 {
538 let cpu_utils = vec![usage.cpu_percent];
540 let avg_cpu = simd_operations::simd_average_utilization(&cpu_utils);
541
542 let memory_util = usage.memory_usage.used as f64 / usage.memory_usage.total as f64 * 100.0;
544 let memory_utils = [memory_util];
545
546 let gpu_utils: Vec<f64> = usage
548 .gpu_usage
549 .iter()
550 .map(|gpu| gpu.utilization_percent)
551 .collect();
552
553 let avg_gpu = if gpu_utils.is_empty() {
554 0.0
555 } else {
556 simd_operations::simd_average_utilization(&gpu_utils)
557 };
558
559 let utilizations = vec![avg_cpu, memory_util, avg_gpu];
561 let weights = vec![
562 self.config.performance_weight,
563 self.config.performance_weight * 0.8,
564 self.config.performance_weight * 1.2,
565 ];
566
567 let efficiency = simd_operations::simd_efficiency_score(&utilizations, &weights);
568
569 let balance_score = simd_operations::simd_load_balance_score(&utilizations);
571
572 efficiency * 0.7 + balance_score * 0.3
574 }
575}
576
577impl Default for ResourcePredictionEngine {
578 fn default() -> Self {
579 Self::new()
580 }
581}
582
583impl ResourcePredictionEngine {
584 #[must_use]
586 pub fn new() -> Self {
587 Self {
588 models: HashMap::new(),
589 config: PredictionConfig {
590 prediction_horizon: Duration::from_secs(60 * 60), model_update_interval: Duration::from_secs(5 * 60), confidence_threshold: 0.7,
593 enable_ensemble: true,
594 historical_window: Duration::from_secs(7 * 24 * 60 * 60), },
596 historical_data: PredictionHistory {
597 usage_samples: VecDeque::new(),
598 workload_samples: VecDeque::new(),
599 performance_samples: VecDeque::new(),
600 },
601 current_predictions: HashMap::new(),
602 }
603 }
604
605 pub fn add_model(&mut self, name: String, model: Box<dyn PredictionModel>) {
607 self.models.insert(name, model);
608 }
609
610 pub fn predict(&mut self, context: &PredictionContext) -> SklResult<ResourcePrediction> {
612 let mut predictions = Vec::new();
613
614 for (name, model) in &self.models {
616 if let Ok(prediction) = model.predict(context) {
617 predictions.push((name.clone(), prediction));
618 }
619 }
620
621 if predictions.is_empty() {
622 return Err(SklearsError::ResourceAllocationError(
623 "No models available for prediction".to_string(),
624 ));
625 }
626
627 if self.config.enable_ensemble && predictions.len() > 1 {
629 self.ensemble_predict(&predictions)
630 } else {
631 let best_prediction = predictions
633 .into_iter()
634 .max_by(|a, b| {
635 a.1.confidence
636 .partial_cmp(&b.1.confidence)
637 .unwrap_or(std::cmp::Ordering::Equal)
638 })
639 .unwrap();
640
641 Ok(best_prediction.1)
642 }
643 }
644
645 fn ensemble_predict(
647 &self,
648 predictions: &[(String, ResourcePrediction)],
649 ) -> SklResult<ResourcePrediction> {
650 let total_confidence: f64 = predictions.iter().map(|(_, p)| p.confidence).sum();
652
653 if total_confidence == 0.0 {
654 return Err(SklearsError::ResourceAllocationError(
655 "All predictions have zero confidence".to_string(),
656 ));
657 }
658
659 let weighted_cpu: f64 = predictions
661 .iter()
662 .map(|(_, p)| p.predicted_usage.cpu_percent * p.confidence)
663 .sum::<f64>()
664 / total_confidence;
665
666 let weighted_memory_used: f64 = predictions
668 .iter()
669 .map(|(_, p)| p.predicted_usage.memory_usage.used as f64 * p.confidence)
670 .sum::<f64>()
671 / total_confidence;
672
673 let reference_prediction = &predictions[0].1;
674
675 Ok(ResourcePrediction {
676 predicted_usage: ResourceUsage {
677 cpu_percent: weighted_cpu,
678 memory_usage: MemoryUsage {
679 total: reference_prediction.predicted_usage.memory_usage.total,
680 used: weighted_memory_used as u64,
681 free: reference_prediction.predicted_usage.memory_usage.total
682 - weighted_memory_used as u64,
683 cached: reference_prediction.predicted_usage.memory_usage.cached,
684 swap_used: reference_prediction.predicted_usage.memory_usage.swap_used,
685 },
686 gpu_usage: reference_prediction.predicted_usage.gpu_usage.clone(),
687 network_usage: reference_prediction.predicted_usage.network_usage.clone(),
688 storage_usage: reference_prediction.predicted_usage.storage_usage.clone(),
689 },
690 confidence: total_confidence / predictions.len() as f64,
691 horizon: reference_prediction.horizon,
692 timestamp: SystemTime::now(),
693 model_name: "Ensemble".to_string(),
694 intervals: reference_prediction.intervals.clone(),
695 })
696 }
697
698 pub fn update_models(
700 &mut self,
701 actual: &ResourceUsage,
702 predictions: &[ResourcePrediction],
703 ) -> SklResult<()> {
704 for prediction in predictions {
705 if let Some(model) = self.models.get_mut(&prediction.model_name) {
706 model.update(actual, prediction)?;
707 }
708 }
709 Ok(())
710 }
711}
712
713impl Default for OptimizerConfig {
714 fn default() -> Self {
715 Self {
716 strategy: OptimizationStrategyType::Balanced,
717 rebalancing_interval: Duration::from_secs(30),
718 enable_predictive_scaling: true,
719 enable_energy_optimization: true,
720 enable_thermal_management: true,
721 aggressiveness: 0.5,
722 performance_weight: 0.4,
723 energy_weight: 0.3,
724 fairness_weight: 0.3,
725 }
726 }
727}
728
729#[allow(non_snake_case)]
730#[cfg(test)]
731mod tests {
732 use super::*;
733
734 #[test]
735 fn test_optimizer_creation() {
736 let optimizer = ResourceOptimizer::new();
737 assert!(!optimizer.state.running);
738 assert_eq!(optimizer.state.cycle_count, 0);
739 }
740
741 #[test]
742 fn test_prediction_engine_creation() {
743 let engine = ResourcePredictionEngine::new();
744 assert!(engine.models.is_empty());
745 assert_eq!(
746 engine.config.prediction_horizon,
747 Duration::from_secs(60 * 60)
748 ); }
750}