rfann 0.1.0

A pure Rust implementation of the Fast Artificial Neural Network (FANN) library
Documentation
//! Simple Memory Pressure Monitoring for GPU Memory Management
//!
//! This module provides basic memory pressure monitoring for GPU memory management
//! without autonomous agent features. It focuses on:
//! - Memory pressure detection
//! - Circuit breaker protection
//! - Performance monitoring
//! - Basic cleanup strategies

use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};

use super::buffer_pool::{AdvancedBufferPool, MemoryPressure};
use super::error::ComputeError;

/// Configuration for memory pressure monitoring
#[derive(Debug, Clone)]
pub struct MonitorConfig {
    /// Sampling interval for pressure readings
    pub sampling_interval: Duration,
    /// Window size for pressure history
    pub history_window_size: usize,
    /// Threshold for triggering cleanup
    pub cleanup_threshold: MemoryPressure,
    /// Enable circuit breaker protection
    pub enable_circuit_breaker: bool,
}

impl Default for MonitorConfig {
    fn default() -> Self {
        Self {
            sampling_interval: Duration::from_millis(100),
            history_window_size: 100,
            cleanup_threshold: MemoryPressure::High,
            enable_circuit_breaker: true,
        }
    }
}

/// Simple memory pressure monitor for GPU memory management
#[derive(Debug)]
pub struct MemoryPressureMonitor {
    config: MonitorConfig,
    pressure_history: Arc<Mutex<VecDeque<PressureReading>>>,
    current_pressure: Arc<Mutex<MemoryPressure>>,
    monitoring_active: bool,
    statistics: Arc<Mutex<MonitoringStatistics>>,
}

/// Basic pressure reading
#[derive(Debug, Clone)]
pub struct PressureReading {
    pub timestamp: Instant,
    pub pressure: MemoryPressure,
    pub memory_usage_ratio: f32,
    pub total_allocations: u64,
    pub active_buffers: u64,
}

/// Monitoring statistics
#[derive(Debug, Clone)]
pub struct MonitoringStatistics {
    pub readings_taken: u64,
    pub average_pressure: f32,
    pub peak_pressure: MemoryPressure,
    pub cleanup_events: u64,
    pub circuit_breaker_activations: u64,
}

impl Default for MonitoringStatistics {
    fn default() -> Self {
        Self {
            readings_taken: 0,
            average_pressure: 0.0,
            peak_pressure: MemoryPressure::None,
            cleanup_events: 0,
            circuit_breaker_activations: 0,
        }
    }
}

/// Monitoring report for external consumption
#[derive(Debug, Clone)]
pub struct MonitoringReport {
    pub current_pressure: MemoryPressure,
    pub monitoring_stats: MonitoringStatistics,
    pub recent_readings: Vec<PressureReading>,
}

impl MemoryPressureMonitor {
    /// Create new pressure monitor
    pub fn new(config: MonitorConfig) -> Self {
        Self {
            config,
            pressure_history: Arc::new(Mutex::new(VecDeque::new())),
            current_pressure: Arc::new(Mutex::new(MemoryPressure::None)),
            monitoring_active: false,
            statistics: Arc::new(Mutex::new(MonitoringStatistics::default())),
        }
    }

    /// Start monitoring with buffer pool
    pub fn start_monitoring(
        &mut self,
        _buffer_pool: Arc<AdvancedBufferPool>,
    ) -> Result<(), ComputeError> {
        self.monitoring_active = true;
        // In a real implementation, this would start a background thread
        // For now, just mark as active
        Ok(())
    }

    /// Stop monitoring
    pub fn stop_monitoring(&mut self) -> Result<(), ComputeError> {
        self.monitoring_active = false;
        Ok(())
    }

    /// Record a pressure reading
    pub fn record_pressure(&self, pressure: MemoryPressure, memory_usage_ratio: f32) {
        let reading = PressureReading {
            timestamp: Instant::now(),
            pressure,
            memory_usage_ratio,
            total_allocations: 0, // Would be populated from buffer pool
            active_buffers: 0,    // Would be populated from buffer pool
        };

        // Update current pressure
        *self.current_pressure.lock().unwrap() = pressure;

        // Add to history
        let mut history = self.pressure_history.lock().unwrap();
        history.push_back(reading);

        // Trim history to window size
        while history.len() > self.config.history_window_size {
            history.pop_front();
        }

        // Update statistics
        let mut stats = self.statistics.lock().unwrap();
        stats.readings_taken += 1;
        if pressure > stats.peak_pressure {
            stats.peak_pressure = pressure;
        }

        // Trigger cleanup if needed
        if pressure >= self.config.cleanup_threshold {
            stats.cleanup_events += 1;
        }
    }

    /// Get current pressure level
    pub fn get_current_pressure(&self) -> MemoryPressure {
        *self.current_pressure.lock().unwrap()
    }

    /// Generate monitoring report
    pub fn generate_report(&self) -> MonitoringReport {
        let current_pressure = *self.current_pressure.lock().unwrap();
        let monitoring_stats = self.statistics.lock().unwrap().clone();
        let recent_readings = self
            .pressure_history
            .lock()
            .unwrap()
            .iter()
            .cloned()
            .collect();

        MonitoringReport {
            current_pressure,
            monitoring_stats,
            recent_readings,
        }
    }

    /// Check if circuit breaker should be activated
    pub fn should_activate_circuit_breaker(&self) -> bool {
        if !self.config.enable_circuit_breaker {
            return false;
        }

        let current_pressure = *self.current_pressure.lock().unwrap();
        current_pressure >= MemoryPressure::Critical
    }

    /// Get monitoring statistics
    pub fn get_statistics(&self) -> MonitoringStatistics {
        self.statistics.lock().unwrap().clone()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pressure_monitor_creation() {
        let config = MonitorConfig::default();
        let monitor = MemoryPressureMonitor::new(config);
        assert!(!monitor.monitoring_active);
        assert_eq!(monitor.get_current_pressure(), MemoryPressure::None);
    }

    #[test]
    fn test_pressure_recording() {
        let config = MonitorConfig::default();
        let monitor = MemoryPressureMonitor::new(config);

        monitor.record_pressure(MemoryPressure::Medium, 0.7);
        assert_eq!(monitor.get_current_pressure(), MemoryPressure::Medium);

        let stats = monitor.get_statistics();
        assert_eq!(stats.readings_taken, 1);
        assert_eq!(stats.peak_pressure, MemoryPressure::Medium);
    }

    #[test]
    fn test_circuit_breaker() {
        let config = MonitorConfig::default();
        let monitor = MemoryPressureMonitor::new(config);

        // Should not activate for low pressure
        monitor.record_pressure(MemoryPressure::Low, 0.4);
        assert!(!monitor.should_activate_circuit_breaker());

        // Should activate for critical pressure
        monitor.record_pressure(MemoryPressure::Critical, 0.95);
        assert!(monitor.should_activate_circuit_breaker());
    }
}