pub fn host_memory_pressure() -> Option<f64> {
#[cfg(target_os = "linux")]
{
linux_rss_fraction()
}
#[cfg(not(target_os = "linux"))]
{
None
}
}
#[cfg(target_os = "linux")]
fn linux_rss_fraction() -> Option<f64> {
let status = std::fs::read_to_string("/proc/self/status").ok()?;
let vm_rss_kb: u64 = status
.lines()
.find(|l| l.starts_with("VmRSS:"))?
.split_whitespace()
.nth(1)?
.parse()
.ok()?;
let vm_rss = vm_rss_kb * 1024;
let meminfo = std::fs::read_to_string("/proc/meminfo").ok()?;
let mem_total_kb: u64 = meminfo
.lines()
.find(|l| l.starts_with("MemTotal:"))?
.split_whitespace()
.nth(1)?
.parse()
.ok()?;
let mem_total = mem_total_kb * 1024;
if mem_total == 0 {
return None;
}
Some(vm_rss as f64 / mem_total as f64)
}
#[derive(Debug, Clone)]
pub struct MemoryPressureProbe {
pub high_watermark: f64,
pub low_watermark: f64,
}
impl Default for MemoryPressureProbe {
fn default() -> Self {
Self {
high_watermark: 0.90,
low_watermark: 0.75,
}
}
}
impl MemoryPressureProbe {
pub fn new(high_watermark: f64, low_watermark: f64) -> Self {
debug_assert!(
low_watermark < high_watermark,
"low_watermark ({low_watermark}) must be less than high_watermark ({high_watermark})"
);
Self {
high_watermark,
low_watermark,
}
}
pub fn is_high(&self) -> bool {
host_memory_pressure()
.map(|p| p >= self.high_watermark)
.unwrap_or(false)
}
pub fn is_low(&self) -> bool {
host_memory_pressure()
.map(|p| p < self.low_watermark)
.unwrap_or(true)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_watermarks() {
let probe = MemoryPressureProbe::default();
assert!((probe.high_watermark - 0.90).abs() < 1e-9);
assert!((probe.low_watermark - 0.75).abs() < 1e-9);
}
#[test]
fn new_probe_stores_watermarks() {
let probe = MemoryPressureProbe::new(0.85, 0.60);
assert!((probe.high_watermark - 0.85).abs() < 1e-9);
assert!((probe.low_watermark - 0.60).abs() < 1e-9);
}
#[test]
fn host_memory_pressure_returns_option() {
if let Some(p) = host_memory_pressure() {
assert!(
(0.0..=1.0).contains(&p),
"memory pressure {p} must be in [0.0, 1.0]"
);
}
}
#[test]
fn is_high_does_not_panic() {
let probe = MemoryPressureProbe::default();
let _ = probe.is_high();
}
#[test]
fn is_low_does_not_panic() {
let probe = MemoryPressureProbe::default();
let _ = probe.is_low();
}
#[test]
fn probe_clone_is_independent() {
let original = MemoryPressureProbe::new(0.95, 0.80);
let cloned = original.clone();
assert!((cloned.high_watermark - 0.95).abs() < 1e-9);
assert!((cloned.low_watermark - 0.80).abs() < 1e-9);
}
}