use std::fs;
pub struct SystemMetrics;
const PROC_KB: i64 = 1024;
impl SystemMetrics {
pub fn get_performance_info() -> bool {
false
}
pub fn get_total_memory(units: i64) -> i64 {
let units = units.max(1);
meminfo_kb("MemTotal:").map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_physical_available_memory(_units: i64) -> i64 {
-1
}
pub fn get_paged_memory_size(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmData:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_paged_system_memory_size(_units: i64) -> i64 {
-1
}
pub fn get_peak_paged_memory_size(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmData:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_virtual_memory_size64(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmSize:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_private_memory_size64(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmData:", "VmSwap:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_peak_virtual_memory_size64(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmPeak:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_physical_memory_usage(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmRSS:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
pub fn get_peak_physical_memory_usage(units: i64) -> i64 {
let units = units.max(1);
status_kb(&["VmHWM:"]).map_or(-1, |kb| kb * PROC_KB / units)
}
}
fn meminfo_kb(field: &str) -> Option<i64> {
let content = fs::read_to_string("/proc/meminfo").ok()?;
parse_proc_kb(&content, field)
}
fn status_kb(fields: &[&str]) -> Option<i64> {
let content = fs::read_to_string("/proc/self/status").ok()?;
fields
.iter()
.try_fold(0i64, |acc, f| Some(acc + parse_proc_kb(&content, f)?))
}
fn parse_proc_kb(content: &str, field: &str) -> Option<i64> {
content.lines().find_map(|line| {
let rest = line.strip_prefix(field)?;
rest
.split_whitespace()
.next()
.and_then(|token| token.parse::<i64>().ok())
})
}
#[cfg(test)]
mod tests {
use super::{SystemMetrics, parse_proc_kb};
#[test]
fn parse_proc_fields() {
let status =
"VmPeak:\t 13408844 kB\nVmSize:\t 13408840 kB\nVmData:\t 4031804 kB\nVmSwap:\t 0 kB\n";
assert_eq!(parse_proc_kb(status, "VmData:"), Some(4_031_804));
assert_eq!(parse_proc_kb(status, "VmSwap:"), Some(0));
assert_eq!(parse_proc_kb(status, "VmRss:"), None);
let meminfo = "MemTotal: 16384256 kB\nMemFree: 8422216 kB\n";
assert_eq!(parse_proc_kb(meminfo, "MemTotal:"), Some(16_384_256));
}
#[test]
fn metrics_contract() {
let total = SystemMetrics::get_total_memory(1);
assert!(total > 0 || total == -1);
assert_eq!(SystemMetrics::get_physical_available_memory(1), -1);
assert_eq!(SystemMetrics::get_paged_system_memory_size(1), -1);
assert!(!SystemMetrics::get_performance_info());
assert!(SystemMetrics::get_physical_memory_usage(0) >= -1);
}
}