use std::collections::{HashMap, VecDeque};
use std::time::Instant;
#[derive(Debug)]
pub struct MemoryPressureMonitor {
pub pressure_level: MemoryPressureLevel,
pressure_history: VecDeque<MemoryPressurePoint>,
warning_thresholds: HashMap<MemoryPressureLevel, usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MemoryPressureLevel {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone)]
pub struct MemoryPressurePoint {
pub timestamp: Instant,
pub level: MemoryPressureLevel,
pub usage: usize,
}
impl Default for MemoryPressureMonitor {
fn default() -> Self {
Self::new()
}
}
impl MemoryPressureMonitor {
pub fn new() -> Self {
let mut warning_thresholds = HashMap::new();
warning_thresholds.insert(MemoryPressureLevel::Medium, 1024 * 1024 * 100); warning_thresholds.insert(MemoryPressureLevel::High, 1024 * 1024 * 500); warning_thresholds.insert(MemoryPressureLevel::Critical, 1024 * 1024 * 1000);
Self {
pressure_level: MemoryPressureLevel::Low,
pressure_history: VecDeque::new(),
warning_thresholds,
}
}
pub fn with_thresholds(thresholds: HashMap<MemoryPressureLevel, usize>) -> Self {
Self {
pressure_level: MemoryPressureLevel::Low,
pressure_history: VecDeque::new(),
warning_thresholds: thresholds,
}
}
pub fn update_pressure(&mut self, current_usage: usize) -> MemoryPressureLevel {
let new_level = self.calculate_pressure_level(current_usage);
if new_level != self.pressure_level {
let point = MemoryPressurePoint {
timestamp: Instant::now(),
level: new_level,
usage: current_usage,
};
if self.pressure_history.len() >= 1000 {
self.pressure_history.pop_front();
}
self.pressure_history.push_back(point);
self.pressure_level = new_level;
}
new_level
}
pub fn calculate_pressure_level(&self, usage: usize) -> MemoryPressureLevel {
if let Some(&critical_threshold) = self.warning_thresholds.get(&MemoryPressureLevel::Critical) {
if usage >= critical_threshold {
return MemoryPressureLevel::Critical;
}
}
if let Some(&high_threshold) = self.warning_thresholds.get(&MemoryPressureLevel::High) {
if usage >= high_threshold {
return MemoryPressureLevel::High;
}
}
if let Some(&medium_threshold) = self.warning_thresholds.get(&MemoryPressureLevel::Medium) {
if usage >= medium_threshold {
return MemoryPressureLevel::Medium;
}
}
MemoryPressureLevel::Low
}
pub fn current_level(&self) -> MemoryPressureLevel {
self.pressure_level
}
pub fn set_threshold(&mut self, level: MemoryPressureLevel, threshold: usize) {
self.warning_thresholds.insert(level, threshold);
}
pub fn get_threshold(&self, level: MemoryPressureLevel) -> Option<usize> {
self.warning_thresholds.get(&level).copied()
}
pub fn get_history(&self) -> &VecDeque<MemoryPressurePoint> {
&self.pressure_history
}
pub fn get_recent_history(&self, count: usize) -> Vec<&MemoryPressurePoint> {
self.pressure_history.iter().rev().take(count).collect()
}
pub fn clear_history(&mut self) {
self.pressure_history.clear();
}
pub fn is_pressure_sustained(&self, level: MemoryPressureLevel, duration: std::time::Duration) -> bool {
let threshold_time = Instant::now() - duration;
self.pressure_history.iter()
.filter(|p| p.timestamp >= threshold_time)
.all(|p| p.level >= level)
}
pub fn get_statistics(&self) -> PressureStatistics {
let mut stats = PressureStatistics {
low_count: 0,
medium_count: 0,
high_count: 0,
critical_count: 0,
total_points: self.pressure_history.len(),
average_usage: 0.0,
};
if stats.total_points == 0 {
return stats;
}
let mut total_usage = 0;
for point in &self.pressure_history {
total_usage += point.usage;
match point.level {
MemoryPressureLevel::Low => stats.low_count += 1,
MemoryPressureLevel::Medium => stats.medium_count += 1,
MemoryPressureLevel::High => stats.high_count += 1,
MemoryPressureLevel::Critical => stats.critical_count += 1,
}
}
stats.average_usage = total_usage as f64 / stats.total_points as f64;
stats
}
}
#[derive(Debug, Clone)]
pub struct PressureStatistics {
pub low_count: usize,
pub medium_count: usize,
pub high_count: usize,
pub critical_count: usize,
pub total_points: usize,
pub average_usage: f64,
}
impl MemoryPressureLevel {
pub fn priority(&self) -> u8 {
match self {
MemoryPressureLevel::Low => 0,
MemoryPressureLevel::Medium => 1,
MemoryPressureLevel::High => 2,
MemoryPressureLevel::Critical => 3,
}
}
pub fn name(&self) -> &'static str {
match self {
MemoryPressureLevel::Low => "Low",
MemoryPressureLevel::Medium => "Medium",
MemoryPressureLevel::High => "High",
MemoryPressureLevel::Critical => "Critical",
}
}
pub fn is_stressed(&self) -> bool {
matches!(self, MemoryPressureLevel::High | MemoryPressureLevel::Critical)
}
pub fn requires_action(&self) -> bool {
matches!(self, MemoryPressureLevel::Critical)
}
pub fn all_levels() -> &'static [MemoryPressureLevel] {
&[
MemoryPressureLevel::Low,
MemoryPressureLevel::Medium,
MemoryPressureLevel::High,
MemoryPressureLevel::Critical,
]
}
}
impl PartialOrd for MemoryPressureLevel {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MemoryPressureLevel {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.priority().cmp(&other.priority())
}
}
impl MemoryPressurePoint {
pub fn new(level: MemoryPressureLevel, usage: usize) -> Self {
Self {
timestamp: Instant::now(),
level,
usage,
}
}
pub fn age(&self) -> std::time::Duration {
Instant::now() - self.timestamp
}
pub fn usage_mb(&self) -> f64 {
self.usage as f64 / (1024.0 * 1024.0)
}
pub fn usage_kb(&self) -> f64 {
self.usage as f64 / 1024.0
}
}
impl PressureStatistics {
pub fn level_percentages(&self) -> HashMap<MemoryPressureLevel, f64> {
if self.total_points == 0 {
return HashMap::new();
}
let total = self.total_points as f64;
let mut percentages = HashMap::new();
percentages.insert(MemoryPressureLevel::Low, self.low_count as f64 / total * 100.0);
percentages.insert(MemoryPressureLevel::Medium, self.medium_count as f64 / total * 100.0);
percentages.insert(MemoryPressureLevel::High, self.high_count as f64 / total * 100.0);
percentages.insert(MemoryPressureLevel::Critical, self.critical_count as f64 / total * 100.0);
percentages
}
pub fn stress_percentage(&self) -> f64 {
if self.total_points == 0 {
return 0.0;
}
let stressed_count = self.high_count + self.critical_count;
stressed_count as f64 / self.total_points as f64 * 100.0
}
pub fn average_usage_mb(&self) -> f64 {
self.average_usage / (1024.0 * 1024.0)
}
}