use std::collections::VecDeque;
use std::time::{Duration, Instant};
#[derive(Debug)]
pub struct PredictiveScaler {
workload_history: VecDeque<WorkloadMeasurement>,
model_params: PredictionModel,
scaling_predictions: VecDeque<ScalingPrediction>,
current_scaling: ScalingState,
}
#[derive(Debug, Clone)]
pub struct WorkloadMeasurement {
pub timestamp: Instant,
pub processing_load: f64,
pub input_complexity: f64,
pub required_resources: ResourceRequirement,
}
#[derive(Debug, Clone)]
pub struct ResourceRequirement {
pub cpu_cores: f64,
pub memory_mb: f64,
pub gpu_utilization: f64,
}
#[derive(Debug, Clone)]
pub struct PredictionModel {
pub model_type: ModelType,
pub parameters: Vec<f64>,
pub _predictionwindow: f64,
pub accuracy: f64,
}
#[derive(Debug, Clone)]
pub enum ModelType {
LinearRegression,
ARIMA {
p: usize,
d: usize,
q: usize,
},
NeuralNetwork {
hidden_layers: Vec<usize>,
},
Ensemble {
models: Vec<ModelType>,
},
}
#[derive(Debug, Clone)]
pub struct ScalingPrediction {
pub horizon: Duration,
pub predicted_resources: ResourceRequirement,
pub confidence: f64,
pub timestamp: Instant,
}
#[derive(Debug, Clone)]
pub struct ScalingState {
pub active_cores: usize,
pub allocated_memory: f64,
pub gpu_utilization: f64,
pub last_scaling: Instant,
}
impl PredictiveScaler {
pub fn new(_predictionwindow: f64) -> Self {
Self {
workload_history: VecDeque::with_capacity(10000),
model_params: PredictionModel {
model_type: ModelType::LinearRegression,
parameters: vec![0.0, 1.0], _predictionwindow,
accuracy: 0.7,
},
scaling_predictions: VecDeque::with_capacity(100),
current_scaling: ScalingState {
active_cores: 1,
allocated_memory: 512.0,
gpu_utilization: 0.0,
last_scaling: Instant::now(),
},
}
}
pub fn record_workload(&mut self, measurement: WorkloadMeasurement) {
self.workload_history.push_back(measurement);
if self.workload_history.len() > 10000 {
self.workload_history.pop_front();
}
if self.workload_history.len() > 100 {
self.update_prediction_model();
}
}
fn update_prediction_model(&mut self) {
match &self.model_params.model_type {
ModelType::LinearRegression => {
self.update_linear_regression();
}
ModelType::ARIMA { .. } => {
self.update_arima_model();
}
_ => {
}
}
}
fn update_linear_regression(&mut self) {
if self.workload_history.len() < 10 {
return;
}
let recent_data: Vec<_> = self.workload_history.iter().rev().take(100).collect();
let n = recent_data.len() as f64;
let mut sum_x = 0.0;
let mut sum_y = 0.0;
let mut sum_xy = 0.0;
let mut sum_x2 = 0.0;
for (i, measurement) in recent_data.iter().enumerate() {
let x = i as f64;
let y = measurement.processing_load;
sum_x += x;
sum_y += y;
sum_xy += x * y;
sum_x2 += x * x;
}
let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x);
let intercept = (sum_y - slope * sum_x) / n;
self.model_params.parameters = vec![intercept, slope];
}
fn update_arima_model(&mut self) {
}
pub fn generate_predictions(&mut self, horizons: Vec<Duration>) -> Vec<ScalingPrediction> {
let mut predictions = Vec::new();
let current_time = Instant::now();
for horizon in horizons {
let predictedload = self.predict_load(horizon);
let predicted_resources = self.load_to_resources(predictedload);
let confidence = self.calculate_confidence(horizon);
predictions.push(ScalingPrediction {
horizon,
predicted_resources,
confidence,
timestamp: current_time,
});
}
for prediction in &predictions {
self.scaling_predictions.push_back(prediction.clone());
}
if self.scaling_predictions.len() > 100 {
self.scaling_predictions.pop_front();
}
predictions
}
fn predict_load(&self, horizon: Duration) -> f64 {
let horizon_secs = horizon.as_secs_f64();
match &self.model_params.model_type {
ModelType::LinearRegression => {
let intercept = self.model_params.parameters[0];
let slope = self.model_params.parameters[1];
let current_index = self.workload_history.len() as f64;
let future_index = current_index + horizon_secs / 60.0;
(intercept + slope * future_index).clamp(0.0, 1.0)
}
_ => {
self.workload_history
.back()
.map(|m| m.processing_load)
.unwrap_or(0.5)
}
}
}
fn load_to_resources(&self, predictedload: f64) -> ResourceRequirement {
ResourceRequirement {
cpu_cores: (predictedload * 8.0).ceil(), memory_mb: 512.0 + predictedload * 1536.0, gpu_utilization: (predictedload * 0.8).min(1.0), }
}
fn calculate_confidence(&self, horizon: Duration) -> f64 {
let base_confidence = self.model_params.accuracy;
let horizon_penalty = (horizon.as_secs_f64() / 3600.0) * 0.1;
(base_confidence - horizon_penalty).max(0.1)
}
pub fn get_scaling_recommendations(&self) -> Vec<ScalingRecommendation> {
let mut recommendations = Vec::new();
if let Some(latest_prediction) = self.scaling_predictions.back() {
let current_resources = &self.current_scaling;
let predicted_resources = &latest_prediction.predicted_resources;
if predicted_resources.cpu_cores > current_resources.active_cores as f64 + 1.0 {
recommendations.push(ScalingRecommendation {
resource_type: ResourceType::CPU,
action_: ScalingAction::ScaleUp,
magnitude: (predicted_resources.cpu_cores
- current_resources.active_cores as f64)
as usize,
confidence: latest_prediction.confidence,
reason: "Predicted CPU demand increase".to_string(),
});
} else if predicted_resources.cpu_cores < current_resources.active_cores as f64 - 1.0 {
recommendations.push(ScalingRecommendation {
resource_type: ResourceType::CPU,
action_: ScalingAction::ScaleDown,
magnitude: (current_resources.active_cores as f64
- predicted_resources.cpu_cores) as usize,
confidence: latest_prediction.confidence,
reason: "Predicted CPU demand decrease".to_string(),
});
}
if predicted_resources.memory_mb > current_resources.allocated_memory * 1.2 {
recommendations.push(ScalingRecommendation {
resource_type: ResourceType::Memory,
action_: ScalingAction::ScaleUp,
magnitude: (predicted_resources.memory_mb - current_resources.allocated_memory)
as usize,
confidence: latest_prediction.confidence,
reason: "Predicted memory demand increase".to_string(),
});
}
}
recommendations
}
}
#[derive(Debug, Clone)]
pub struct ScalingRecommendation {
pub resource_type: ResourceType,
pub action_: ScalingAction,
pub magnitude: usize,
pub confidence: f64,
pub reason: String,
}
#[derive(Debug, Clone)]
pub enum ResourceType {
CPU,
Memory,
GPU,
Network,
}
#[derive(Debug, Clone)]
pub enum ScalingAction {
ScaleUp,
ScaleDown,
Maintain,
}