use scirs2_core::numeric::Float;
use std::collections::HashMap;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use super::config::{
HardwareResources, ResourceConstraints, ResourceViolationHandling, TimeConstraints,
};
use super::results::{ResourceUsage, ResourceUsageSummary};
use crate::error::{OptimError, Result};
pub struct ResourceMonitor<T: Float + Debug + Send + Sync + 'static> {
constraints: ResourceConstraints<T>,
current_usage: Arc<Mutex<ResourceUsage<T>>>,
usage_history: Arc<Mutex<Vec<ResourceSnapshot<T>>>>,
monitoring_config: MonitoringConfig,
monitors: Vec<Box<dyn ResourceTracker<T>>>,
alert_handlers: Vec<Box<dyn AlertHandler<T>>>,
monitoring_state: MonitoringState,
optimization_strategies: Vec<Box<dyn ResourceOptimizer<T>>>,
}
impl<T: Float + Debug + Send + Sync + 'static> Debug for ResourceMonitor<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ResourceMonitor")
.field("constraints", &self.constraints)
.field("current_usage", &self.current_usage)
.field("usage_history", &self.usage_history)
.field("monitoring_config", &self.monitoring_config)
.field("monitoring_state", &self.monitoring_state)
.field("monitors_count", &self.monitors.len())
.field("alert_handlers_count", &self.alert_handlers.len())
.field(
"optimization_strategies_count",
&self.optimization_strategies.len(),
)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct ResourceSnapshot<T: Float + Debug + Send + Sync + 'static> {
pub timestamp: Instant,
pub usage: ResourceUsage<T>,
pub system_metrics: SystemMetrics<T>,
pub active_processes: usize,
pub memory_pressure: MemoryPressure,
pub cpu_load_average: T,
pub gpu_utilization: T,
}
#[derive(Debug, Clone)]
pub struct SystemMetrics<T: Float + Debug + Send + Sync + 'static> {
pub available_memory_gb: T,
pub available_cpu_cores: usize,
pub available_gpu_devices: usize,
pub available_disk_gb: T,
pub network_bandwidth: T,
pub system_temperature: T,
pub power_consumption: T,
}
#[derive(Debug, Clone, Copy)]
pub enum MemoryPressure {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone)]
pub struct MonitoringConfig {
pub monitoring_interval: Duration,
pub history_retention: Duration,
pub enable_detailed_monitoring: bool,
pub enable_predictive_monitoring: bool,
pub alert_thresholds: AlertThresholds,
pub enable_auto_optimization: bool,
}
#[derive(Debug, Clone)]
pub struct AlertThresholds {
pub memory_threshold: f64,
pub cpu_threshold: f64,
pub gpu_threshold: f64,
pub disk_threshold: f64,
pub temperature_threshold: f64,
pub power_threshold: f64,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MonitoringState {
Stopped,
Starting,
Running,
Paused,
Stopping,
Error,
}
pub trait ResourceTracker<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn get_current_usage(&self) -> Result<ResourceUsage<T>>;
fn get_system_metrics(&self) -> Result<SystemMetrics<T>>;
fn check_limits(
&self,
constraints: &ResourceConstraints<T>,
) -> Result<Vec<ResourceViolation<T>>>;
fn name(&self) -> &str;
fn initialize(&mut self) -> Result<()>;
fn cleanup(&mut self) -> Result<()>;
}
#[derive(Debug, Clone)]
pub struct ResourceViolation<T: Float + Debug + Send + Sync + 'static> {
pub violation_type: ViolationType,
pub current_value: T,
pub limit_value: T,
pub severity: ViolationSeverity,
pub violation_time: Instant,
pub affected_resources: Vec<String>,
pub suggested_actions: Vec<String>,
}
#[derive(Debug, Clone, Copy)]
pub enum ViolationType {
MemoryExceeded,
CPUExceeded,
GPUExceeded,
DiskExceeded,
TimeExceeded,
EnergyExceeded,
TemperatureExceeded,
PowerExceeded,
NetworkExceeded,
ComputationTimeExceeded,
CostExceeded,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ViolationSeverity {
Low,
Medium,
High,
Critical,
}
pub trait AlertHandler<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn handle_violation(&self, violation: &ResourceViolation<T>) -> Result<()>;
fn handle_warning(&self, warning: &ResourceWarning<T>) -> Result<()>;
fn name(&self) -> &str;
}
#[derive(Debug, Clone)]
pub struct ResourceWarning<T: Float + Debug + Send + Sync + 'static> {
pub warning_type: WarningType,
pub current_value: T,
pub threshold_value: T,
pub trend: TrendDirection,
pub time_to_violation: Option<Duration>,
pub message: String,
}
#[derive(Debug, Clone, Copy)]
pub enum WarningType {
MemoryApproachingLimit,
CPUApproachingLimit,
GPUApproachingLimit,
DiskApproachingLimit,
TimeApproachingLimit,
EnergyApproachingLimit,
TemperatureRising,
PowerIncreasing,
}
#[derive(Debug, Clone, Copy)]
pub enum TrendDirection {
Increasing,
Decreasing,
Stable,
Volatile,
}
pub trait ResourceOptimizer<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn optimize(
&self,
current_usage: &ResourceUsage<T>,
constraints: &ResourceConstraints<T>,
) -> Result<OptimizationAction<T>>;
fn name(&self) -> &str;
fn priority(&self) -> OptimizationPriority;
}
#[derive(Debug, Clone)]
pub struct OptimizationAction<T: Float + Debug + Send + Sync + 'static> {
pub action_type: ActionType,
pub parameters: HashMap<String, T>,
pub expected_savings: ResourceUsage<T>,
pub implementation_cost: T,
pub description: String,
pub priority: OptimizationPriority,
}
#[derive(Debug, Clone, Copy)]
pub enum ActionType {
ReduceMemoryUsage,
OptimizeCPUUsage,
OptimizeGPUUsage,
ClearCaches,
GarbageCollection,
ProcessThrottling,
ResourceReallocation,
TaskMigration,
PowerManagement,
TemperatureControl,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum OptimizationPriority {
Low,
Medium,
High,
Critical,
}
pub struct SystemResourceTracker {
name: String,
monitoring_interval: Duration,
last_update: Instant,
cached_metrics: Option<SystemMetrics<f64>>,
}
impl SystemResourceTracker {
pub fn new(name: String, monitoring_interval: Duration) -> Self {
Self {
name,
monitoring_interval,
last_update: Instant::now(),
cached_metrics: None,
}
}
fn get_memory_info(&self) -> Result<(f64, f64)> {
let total_memory = 32.0; let used_memory = 16.0; Ok((total_memory, used_memory))
}
fn get_cpu_info(&self) -> Result<(usize, f64)> {
let total_cores = num_cpus::get();
let cpu_usage = 0.6; Ok((total_cores, cpu_usage))
}
fn get_gpu_info(&self) -> Result<(usize, f64)> {
let gpu_devices = 4;
let gpu_usage = 0.8; Ok((gpu_devices, gpu_usage))
}
fn get_disk_info(&self) -> Result<(f64, f64)> {
let total_disk = 1000.0; let used_disk = 500.0; Ok((total_disk, used_disk))
}
fn get_network_info(&self) -> Result<f64> {
let bandwidth = 1000.0; Ok(bandwidth)
}
fn get_temperature_info(&self) -> Result<f64> {
let temperature = 65.0; Ok(temperature)
}
fn get_power_info(&self) -> Result<f64> {
let power = 250.0; Ok(power)
}
}
impl<T: Float + Debug + Send + Sync + 'static> ResourceTracker<T> for SystemResourceTracker
where
T: From<f64> + std::fmt::Debug,
{
fn get_current_usage(&self) -> Result<ResourceUsage<T>> {
let (total_memory, used_memory) = self.get_memory_info()?;
let (total_cores, cpu_usage) = self.get_cpu_info()?;
let (gpu_devices, gpu_usage) = self.get_gpu_info()?;
Ok(ResourceUsage {
memory_gb: scirs2_core::numeric::NumCast::from(used_memory)
.unwrap_or_else(|| T::zero()),
cpu_time_seconds: scirs2_core::numeric::NumCast::from(cpu_usage * 3600.0)
.unwrap_or_else(|| T::zero()), gpu_time_seconds: scirs2_core::numeric::NumCast::from(gpu_usage * 3600.0)
.unwrap_or_else(|| T::zero()), energy_kwh: scirs2_core::numeric::NumCast::from(0.25).unwrap_or_else(|| T::zero()), network_io_gb: scirs2_core::numeric::NumCast::from(1.0).unwrap_or_else(|| T::zero()), disk_io_gb: scirs2_core::numeric::NumCast::from(2.0).unwrap_or_else(|| T::zero()), peak_memory_gb: scirs2_core::numeric::NumCast::from(used_memory * 1.2)
.unwrap_or_else(|| T::zero()), efficiency_score: scirs2_core::numeric::NumCast::from(0.8).unwrap_or_else(|| T::zero()), cost_usd: scirs2_core::numeric::NumCast::from(0.5).unwrap_or_else(|| T::zero()), network_gb: scirs2_core::numeric::NumCast::from(1.0).unwrap_or_else(|| T::zero()), })
}
fn get_system_metrics(&self) -> Result<SystemMetrics<T>> {
let (total_memory, used_memory) = self.get_memory_info()?;
let (total_cores, _cpu_usage) = self.get_cpu_info()?;
let (gpu_devices, _gpu_usage) = self.get_gpu_info()?;
let (total_disk, used_disk) = self.get_disk_info()?;
let bandwidth = self.get_network_info()?;
let temperature = self.get_temperature_info()?;
let power = self.get_power_info()?;
Ok(SystemMetrics {
available_memory_gb: scirs2_core::numeric::NumCast::from(total_memory - used_memory)
.unwrap_or_else(|| T::zero()),
available_cpu_cores: total_cores,
available_gpu_devices: gpu_devices,
available_disk_gb: scirs2_core::numeric::NumCast::from(total_disk - used_disk)
.unwrap_or_else(|| T::zero()),
network_bandwidth: scirs2_core::numeric::NumCast::from(bandwidth)
.unwrap_or_else(|| T::zero()),
system_temperature: scirs2_core::numeric::NumCast::from(temperature)
.unwrap_or_else(|| T::zero()),
power_consumption: scirs2_core::numeric::NumCast::from(power)
.unwrap_or_else(|| T::zero()),
})
}
fn check_limits(
&self,
constraints: &ResourceConstraints<T>,
) -> Result<Vec<ResourceViolation<T>>> {
let current_usage = self.get_current_usage()?;
let mut violations = Vec::new();
let memory_limit =
scirs2_core::numeric::NumCast::from(constraints.hardware_resources.max_memory_gb)
.unwrap_or_else(|| T::zero());
if current_usage.memory_gb > memory_limit {
violations.push(ResourceViolation {
violation_type: ViolationType::MemoryExceeded,
current_value: current_usage.memory_gb,
limit_value: memory_limit,
severity: ViolationSeverity::High,
violation_time: Instant::now(),
affected_resources: vec!["Memory".to_string()],
suggested_actions: vec![
"Clear caches".to_string(),
"Reduce batch size".to_string(),
"Enable memory optimization".to_string(),
],
});
}
let system_metrics = self.get_system_metrics()?;
let power_limit = scirs2_core::numeric::NumCast::from(1000.0).unwrap_or_else(|| T::zero()); if system_metrics.power_consumption > power_limit {
violations.push(ResourceViolation {
violation_type: ViolationType::PowerExceeded,
current_value: system_metrics.power_consumption,
limit_value: power_limit,
severity: ViolationSeverity::Medium,
violation_time: Instant::now(),
affected_resources: vec!["Power".to_string()],
suggested_actions: vec![
"Reduce clock speeds".to_string(),
"Throttle processes".to_string(),
"Enable power saving mode".to_string(),
],
});
}
let temp_limit = scirs2_core::numeric::NumCast::from(80.0).unwrap_or_else(|| T::zero()); if system_metrics.system_temperature > temp_limit {
violations.push(ResourceViolation {
violation_type: ViolationType::TemperatureExceeded,
current_value: system_metrics.system_temperature,
limit_value: temp_limit,
severity: ViolationSeverity::Critical,
violation_time: Instant::now(),
affected_resources: vec!["CPU".to_string(), "GPU".to_string()],
suggested_actions: vec![
"Increase cooling".to_string(),
"Reduce workload".to_string(),
"Enable thermal throttling".to_string(),
],
});
}
Ok(violations)
}
fn name(&self) -> &str {
&self.name
}
fn initialize(&mut self) -> Result<()> {
self.last_update = Instant::now();
println!("Initialized system resource tracker: {}", self.name);
Ok(())
}
fn cleanup(&mut self) -> Result<()> {
self.cached_metrics = None;
println!("Cleaned up system resource tracker: {}", self.name);
Ok(())
}
}
pub struct ConsoleAlertHandler {
name: String,
verbose: bool,
}
impl ConsoleAlertHandler {
pub fn new(name: String, verbose: bool) -> Self {
Self { name, verbose }
}
}
impl<T: Float + Debug + Send + Sync + 'static> AlertHandler<T> for ConsoleAlertHandler
where
T: std::fmt::Display + std::fmt::Debug,
{
fn handle_violation(&self, violation: &ResourceViolation<T>) -> Result<()> {
println!(
"[VIOLATION] {:?}: Current={}, Limit={}, Severity={:?}",
violation.violation_type,
violation.current_value,
violation.limit_value,
violation.severity
);
if self.verbose {
println!(" Time: {:?}", violation.violation_time);
println!(" Affected resources: {:?}", violation.affected_resources);
println!(" Suggested actions: {:?}", violation.suggested_actions);
}
Ok(())
}
fn handle_warning(&self, warning: &ResourceWarning<T>) -> Result<()> {
println!(
"[WARNING] {:?}: Current={}, Threshold={}, Trend={:?}",
warning.warning_type, warning.current_value, warning.threshold_value, warning.trend
);
if self.verbose {
if let Some(time_to_violation) = warning.time_to_violation {
println!(" Time to violation: {:?}", time_to_violation);
}
println!(" Message: {}", warning.message);
}
Ok(())
}
fn name(&self) -> &str {
&self.name
}
}
pub struct MemoryOptimizer {
name: String,
aggressiveness: f64,
}
impl MemoryOptimizer {
pub fn new(name: String, aggressiveness: f64) -> Self {
Self {
name,
aggressiveness,
}
}
}
impl<T: Float + Debug + Send + Sync + 'static> ResourceOptimizer<T> for MemoryOptimizer
where
T: From<f64> + std::cmp::PartialOrd,
{
fn optimize(
&self,
current_usage: &ResourceUsage<T>,
constraints: &ResourceConstraints<T>,
) -> Result<OptimizationAction<T>> {
let memory_limit =
scirs2_core::numeric::NumCast::from(constraints.hardware_resources.max_memory_gb)
.unwrap_or_else(|| T::zero());
if current_usage.memory_gb
> memory_limit * scirs2_core::numeric::NumCast::from(0.8).unwrap_or_else(|| T::zero())
{
let reduction_target = current_usage.memory_gb
* scirs2_core::numeric::NumCast::from(self.aggressiveness * 0.2)
.unwrap_or_else(|| T::zero());
let mut parameters = HashMap::new();
parameters.insert("memory_reduction_gb".to_string(), reduction_target);
parameters.insert(
"aggressiveness".to_string(),
scirs2_core::numeric::NumCast::from(self.aggressiveness)
.unwrap_or_else(|| T::zero()),
);
Ok(OptimizationAction {
action_type: ActionType::ReduceMemoryUsage,
parameters,
expected_savings: ResourceUsage {
memory_gb: reduction_target,
cpu_time_seconds: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
gpu_time_seconds: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
energy_kwh: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
network_io_gb: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
disk_io_gb: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
peak_memory_gb: reduction_target,
efficiency_score: scirs2_core::numeric::NumCast::from(0.1)
.unwrap_or_else(|| T::zero()),
cost_usd: scirs2_core::numeric::NumCast::from(0.0).unwrap_or_else(|| T::zero()),
network_gb: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
},
implementation_cost: scirs2_core::numeric::NumCast::from(0.05)
.unwrap_or_else(|| T::zero()),
description: "Reduce memory usage through cache clearing and optimization"
.to_string(),
priority: OptimizationPriority::High,
})
} else {
Ok(OptimizationAction {
action_type: ActionType::ReduceMemoryUsage,
parameters: HashMap::new(),
expected_savings: ResourceUsage::default(),
implementation_cost: scirs2_core::numeric::NumCast::from(0.0)
.unwrap_or_else(|| T::zero()),
description: "No memory optimization needed".to_string(),
priority: OptimizationPriority::Low,
})
}
}
fn name(&self) -> &str {
&self.name
}
fn priority(&self) -> OptimizationPriority {
OptimizationPriority::High
}
}
impl<T: Float + Debug + Send + Sync + 'static> ResourceMonitor<T>
where
T: From<f64> + std::fmt::Display,
{
pub fn new(constraints: ResourceConstraints<T>) -> Self {
let monitoring_config = MonitoringConfig {
monitoring_interval: Duration::from_secs(5),
history_retention: Duration::from_secs(3600), enable_detailed_monitoring: true,
enable_predictive_monitoring: false,
alert_thresholds: AlertThresholds {
memory_threshold: 0.8,
cpu_threshold: 0.9,
gpu_threshold: 0.9,
disk_threshold: 0.9,
temperature_threshold: 75.0,
power_threshold: 800.0,
},
enable_auto_optimization: true,
};
let monitors: Vec<Box<dyn ResourceTracker<T>>> =
vec![Box::new(SystemResourceTracker::new(
"SystemTracker".to_string(),
monitoring_config.monitoring_interval,
))];
let alert_handlers: Vec<Box<dyn AlertHandler<T>>> = vec![Box::new(
ConsoleAlertHandler::new("ConsoleHandler".to_string(), true),
)];
let optimization_strategies: Vec<Box<dyn ResourceOptimizer<T>>> = vec![Box::new(
MemoryOptimizer::new("MemoryOptimizer".to_string(), 0.8),
)];
Self {
constraints,
current_usage: Arc::new(Mutex::new(ResourceUsage::default())),
usage_history: Arc::new(Mutex::new(Vec::new())),
monitoring_config,
monitors,
alert_handlers,
monitoring_state: MonitoringState::Stopped,
optimization_strategies,
}
}
pub fn start_monitoring(&mut self) -> Result<()> {
self.monitoring_state = MonitoringState::Starting;
for monitor in &mut self.monitors {
monitor.initialize()?;
}
self.monitoring_state = MonitoringState::Running;
println!("Resource monitoring started");
Ok(())
}
pub fn stop_monitoring(&mut self) -> Result<()> {
self.monitoring_state = MonitoringState::Stopping;
for monitor in &mut self.monitors {
monitor.cleanup()?;
}
self.monitoring_state = MonitoringState::Stopped;
println!("Resource monitoring stopped");
Ok(())
}
pub fn update_usage(&self) -> Result<()> {
if self.monitoring_state != MonitoringState::Running {
return Ok(());
}
let mut total_usage = ResourceUsage::default();
let mut system_metrics = None;
for monitor in &self.monitors {
let usage = monitor.get_current_usage()?;
total_usage.memory_gb = total_usage.memory_gb + usage.memory_gb;
total_usage.cpu_time_seconds = total_usage.cpu_time_seconds + usage.cpu_time_seconds;
total_usage.gpu_time_seconds = total_usage.gpu_time_seconds + usage.gpu_time_seconds;
total_usage.energy_kwh = total_usage.energy_kwh + usage.energy_kwh;
if system_metrics.is_none() {
system_metrics = Some(monitor.get_system_metrics()?);
}
}
{
let mut current = self.current_usage.lock().expect("lock poisoned");
*current = total_usage.clone();
}
if let Some(metrics) = system_metrics {
let snapshot = ResourceSnapshot {
timestamp: Instant::now(),
usage: total_usage,
system_metrics: metrics,
active_processes: 1, memory_pressure: MemoryPressure::Low, cpu_load_average: scirs2_core::numeric::NumCast::from(0.6)
.unwrap_or_else(|| T::zero()),
gpu_utilization: scirs2_core::numeric::NumCast::from(0.8)
.unwrap_or_else(|| T::zero()),
};
{
let mut history = self.usage_history.lock().expect("lock poisoned");
history.push(snapshot);
let cutoff_time = Instant::now() - self.monitoring_config.history_retention;
history.retain(|s| s.timestamp > cutoff_time);
}
}
Ok(())
}
pub fn check_violations(&self) -> Result<Vec<ResourceViolation<T>>> {
let mut all_violations = Vec::new();
for monitor in &self.monitors {
let violations = monitor.check_limits(&self.constraints)?;
all_violations.extend(violations);
}
for violation in &all_violations {
for handler in &self.alert_handlers {
handler.handle_violation(violation)?;
}
}
Ok(all_violations)
}
pub fn optimize_resources(&self) -> Result<Vec<OptimizationAction<T>>> {
if !self.monitoring_config.enable_auto_optimization {
return Ok(Vec::new());
}
let current_usage = {
let usage = self.current_usage.lock().expect("lock poisoned");
usage.clone()
};
let mut optimization_actions = Vec::new();
for optimizer in &self.optimization_strategies {
let action = optimizer.optimize(¤t_usage, &self.constraints)?;
if action.priority >= OptimizationPriority::Medium {
optimization_actions.push(action);
}
}
optimization_actions.sort_by_key(|a| a.priority);
Ok(optimization_actions)
}
pub fn get_current_usage(&self) -> ResourceUsage<T> {
let usage = self.current_usage.lock().expect("lock poisoned");
usage.clone()
}
pub fn get_usage_history(&self) -> Vec<ResourceSnapshot<T>> {
let history = self.usage_history.lock().expect("lock poisoned");
history.clone()
}
pub fn get_monitoring_state(&self) -> MonitoringState {
self.monitoring_state
}
pub fn update_constraints(&mut self, constraints: ResourceConstraints<T>) {
self.constraints = constraints;
}
pub fn generate_report(&self) -> ResourceReport<T> {
let current_usage = self.get_current_usage();
let history = self.get_usage_history();
let usage_trend = self.calculate_usage_trend(&history);
let efficiency_score = self.calculate_efficiency_score(¤t_usage);
let recommendations = self.generate_recommendations(¤t_usage, &history);
ResourceReport {
timestamp: Instant::now(),
current_usage,
usage_trend,
efficiency_score,
total_samples: history.len(),
monitoring_duration: if !history.is_empty() {
history
.last()
.expect("unwrap failed")
.timestamp
.duration_since(history.first().expect("unwrap failed").timestamp)
} else {
Duration::from_secs(0)
},
recommendations,
constraint_violations: self.check_violations().unwrap_or_default(),
}
}
fn calculate_usage_trend(&self, history: &[ResourceSnapshot<T>]) -> UsageTrend<T> {
if history.len() < 2 {
return UsageTrend::default();
}
let recent_window = history.len().min(10);
let recent = &history[history.len() - recent_window..];
let memory_trend =
self.calculate_metric_trend(recent.iter().map(|s| s.usage.memory_gb).collect());
let cpu_trend =
self.calculate_metric_trend(recent.iter().map(|s| s.usage.cpu_time_seconds).collect());
let gpu_trend =
self.calculate_metric_trend(recent.iter().map(|s| s.usage.gpu_time_seconds).collect());
UsageTrend {
memory_trend,
cpu_trend,
gpu_trend,
energy_trend: TrendDirection::Stable, overall_trend: TrendDirection::Stable, _phantom: std::marker::PhantomData,
}
}
fn calculate_metric_trend(&self, values: Vec<T>) -> TrendDirection {
if values.len() < 2 {
return TrendDirection::Stable;
}
let first_half_avg = values.iter().take(values.len() / 2).fold(
scirs2_core::numeric::NumCast::from(0.0).unwrap_or_else(|| T::zero()),
|acc, &x| acc + x,
) / scirs2_core::numeric::NumCast::from(values.len() / 2)
.unwrap_or_else(|| T::one());
let second_half_avg =
values.iter().skip(values.len() / 2).fold(
scirs2_core::numeric::NumCast::from(0.0).unwrap_or_else(|| T::zero()),
|acc, &x| acc + x,
) / scirs2_core::numeric::NumCast::from(values.len() - values.len() / 2)
.unwrap_or_else(|| T::one());
let change_threshold =
scirs2_core::numeric::NumCast::from(0.05).unwrap_or_else(|| T::zero());
if second_half_avg > first_half_avg + change_threshold {
TrendDirection::Increasing
} else if second_half_avg < first_half_avg - change_threshold {
TrendDirection::Decreasing
} else {
TrendDirection::Stable
}
}
fn calculate_efficiency_score(&self, usage: &ResourceUsage<T>) -> T {
usage.efficiency_score
}
fn generate_recommendations(
&self,
_usage: &ResourceUsage<T>,
_history: &[ResourceSnapshot<T>],
) -> Vec<String> {
vec![
"Consider enabling memory optimization".to_string(),
"Monitor GPU utilization for potential improvements".to_string(),
"Review energy consumption patterns".to_string(),
]
}
pub fn check_resource_violations(&self) -> Result<Vec<ResourceViolation<T>>> {
let current_usage = self.get_current_usage();
let mut violations = Vec::new();
if current_usage.memory_gb > self.constraints.max_memory_gb {
violations.push(ResourceViolation {
violation_type: ViolationType::MemoryExceeded,
severity: ViolationSeverity::High,
current_value: current_usage.memory_gb,
limit_value: self.constraints.max_memory_gb,
violation_time: Instant::now(),
affected_resources: vec!["System Memory".to_string(), "RAM".to_string()],
suggested_actions: vec![
"Reduce batch size".to_string(),
"Clear memory cache".to_string(),
"Enable memory optimization".to_string(),
],
});
}
if current_usage.cpu_time_seconds
> self.constraints.max_computation_hours
* scirs2_core::numeric::NumCast::from(3600.0).unwrap_or_else(|| T::zero())
{
violations.push(ResourceViolation {
violation_type: ViolationType::ComputationTimeExceeded,
severity: ViolationSeverity::Medium,
current_value: current_usage.cpu_time_seconds,
limit_value: self.constraints.max_computation_hours
* scirs2_core::numeric::NumCast::from(3600.0).unwrap_or_else(|| T::zero()),
violation_time: Instant::now(),
affected_resources: vec!["CPU".to_string(), "Computation Time".to_string()],
suggested_actions: vec![
"Optimize algorithms".to_string(),
"Enable parallelization".to_string(),
"Reduce search space".to_string(),
],
});
}
if current_usage.energy_kwh > self.constraints.max_energy_kwh {
violations.push(ResourceViolation {
violation_type: ViolationType::EnergyExceeded,
severity: ViolationSeverity::Low,
current_value: current_usage.energy_kwh,
limit_value: self.constraints.max_energy_kwh,
violation_time: Instant::now(),
affected_resources: vec!["Energy".to_string(), "Power Consumption".to_string()],
suggested_actions: vec![
"Enable power-saving mode".to_string(),
"Reduce GPU usage".to_string(),
"Optimize computation schedule".to_string(),
],
});
}
if current_usage.cost_usd > self.constraints.max_cost_usd {
violations.push(ResourceViolation {
violation_type: ViolationType::CostExceeded,
severity: ViolationSeverity::High,
current_value: current_usage.cost_usd,
limit_value: self.constraints.max_cost_usd,
violation_time: Instant::now(),
affected_resources: vec!["Budget".to_string(), "Cost".to_string()],
suggested_actions: vec![
"Stop non-critical tasks".to_string(),
"Switch to cheaper resources".to_string(),
"Optimize resource allocation".to_string(),
],
});
}
Ok(violations)
}
pub fn get_usage_summary(&self) -> ResourceUsageSummary<T> {
let current_usage = self.get_current_usage();
let history = self.get_usage_history();
let mut total_cpu_hours = T::zero();
let mut total_gpu_hours = T::zero();
let mut total_energy_kwh = T::zero();
let mut total_cost_usd = T::zero();
for snapshot in &history {
total_cpu_hours = total_cpu_hours
+ snapshot.usage.cpu_time_seconds
/ scirs2_core::numeric::NumCast::from(3600.0).unwrap_or_else(|| T::one());
total_gpu_hours = total_gpu_hours
+ snapshot.usage.gpu_time_seconds
/ scirs2_core::numeric::NumCast::from(3600.0).unwrap_or_else(|| T::one());
total_energy_kwh = total_energy_kwh + snapshot.usage.energy_kwh;
total_cost_usd = total_cost_usd + snapshot.usage.cost_usd;
}
ResourceUsageSummary {
total_memory_gb: current_usage.memory_gb,
total_cpu_hours,
total_gpu_hours,
total_energy_kwh,
total_cost_usd,
average_efficiency: current_usage.efficiency_score,
}
}
}
#[derive(Debug, Clone)]
pub struct UsageTrend<T: Float + Debug + Send + Sync + 'static> {
pub memory_trend: TrendDirection,
pub cpu_trend: TrendDirection,
pub gpu_trend: TrendDirection,
pub energy_trend: TrendDirection,
pub overall_trend: TrendDirection,
_phantom: PhantomData<T>,
}
impl<T: Float + Debug + Send + Sync + 'static> Default for UsageTrend<T> {
fn default() -> Self {
Self {
memory_trend: TrendDirection::Stable,
cpu_trend: TrendDirection::Stable,
gpu_trend: TrendDirection::Stable,
energy_trend: TrendDirection::Stable,
overall_trend: TrendDirection::Stable,
_phantom: PhantomData,
}
}
}
#[derive(Debug, Clone)]
pub struct ResourceReport<T: Float + Debug + Send + Sync + 'static> {
pub timestamp: Instant,
pub current_usage: ResourceUsage<T>,
pub usage_trend: UsageTrend<T>,
pub efficiency_score: T,
pub total_samples: usize,
pub monitoring_duration: Duration,
pub recommendations: Vec<String>,
pub constraint_violations: Vec<ResourceViolation<T>>,
}
impl Default for MonitoringConfig {
fn default() -> Self {
Self {
monitoring_interval: Duration::from_secs(5),
history_retention: Duration::from_secs(3600),
enable_detailed_monitoring: true,
enable_predictive_monitoring: false,
alert_thresholds: AlertThresholds::default(),
enable_auto_optimization: true,
}
}
}
impl Default for AlertThresholds {
fn default() -> Self {
Self {
memory_threshold: 0.8,
cpu_threshold: 0.9,
gpu_threshold: 0.9,
disk_threshold: 0.9,
temperature_threshold: 75.0,
power_threshold: 800.0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resource_monitor_creation() {
let constraints = ResourceConstraints::default();
let monitor = ResourceMonitor::<f64>::new(constraints);
assert_eq!(monitor.get_monitoring_state(), MonitoringState::Stopped);
}
#[test]
fn test_system_resource_tracker() {
use super::ResourceTracker;
let mut tracker =
SystemResourceTracker::new("TestTracker".to_string(), Duration::from_secs(1));
assert!(<SystemResourceTracker as ResourceTracker<f64>>::initialize(&mut tracker).is_ok());
let usage = <SystemResourceTracker as ResourceTracker<f64>>::get_current_usage(&tracker);
assert!(usage.is_ok());
let metrics = <SystemResourceTracker as ResourceTracker<f64>>::get_system_metrics(&tracker);
assert!(metrics.is_ok());
assert!(<SystemResourceTracker as ResourceTracker<f64>>::cleanup(&mut tracker).is_ok());
}
#[test]
fn test_memory_optimizer() {
let optimizer = MemoryOptimizer::new("TestOptimizer".to_string(), 0.5);
let usage = ResourceUsage {
memory_gb: 20.0,
cpu_time_seconds: 100.0,
gpu_time_seconds: 50.0,
energy_kwh: 1.0,
network_io_gb: 1.0,
disk_io_gb: 2.0,
peak_memory_gb: 22.0,
efficiency_score: 0.8,
cost_usd: 0.0,
network_gb: 1.0,
};
let constraints = ResourceConstraints::default();
let action = optimizer.optimize(&usage, &constraints);
assert!(action.is_ok());
}
#[test]
fn test_alert_handler() {
let handler = ConsoleAlertHandler::new("TestHandler".to_string(), false);
let violation = ResourceViolation {
violation_type: ViolationType::MemoryExceeded,
current_value: 25.0,
limit_value: 20.0,
severity: ViolationSeverity::High,
violation_time: Instant::now(),
affected_resources: vec!["Memory".to_string()],
suggested_actions: vec!["Clear cache".to_string()],
};
assert!(handler.handle_violation(&violation).is_ok());
}
#[test]
fn test_trend_calculation() {
let constraints = ResourceConstraints::default();
let monitor = ResourceMonitor::<f64>::new(constraints);
let values = vec![1.0, 1.1, 1.2, 1.3, 1.4];
let trend = monitor.calculate_metric_trend(values);
assert!(matches!(trend, TrendDirection::Increasing));
let stable_values = vec![1.0, 1.0, 1.0, 1.0, 1.0];
let stable_trend = monitor.calculate_metric_trend(stable_values);
assert!(matches!(stable_trend, TrendDirection::Stable));
}
}