use sysinfo::{MemoryRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
use tracing::debug;
#[derive(Debug, Clone, Default)]
pub struct MemoryStats {
pub total: u64,
pub free: u64,
pub available: u64,
pub usage: u64,
pub used_percent: f64,
}
#[derive(Debug, Clone, Default)]
pub struct ProcessMemoryStats {
pub used_percent: f64,
}
#[derive(Debug, Clone, Default)]
pub struct CgroupMemoryStats {
pub limit: i64,
pub usage: u64,
pub used_percent: f64,
}
#[derive(Debug, Clone, Default)]
pub struct Memory {}
impl Memory {
pub fn get_stats(&self) -> MemoryStats {
let sys =
System::new_with_specifics(RefreshKind::new().with_memory(MemoryRefreshKind::new()));
let total_memory = sys.total_memory();
let free_memory = sys.free_memory();
let available_memory = sys.available_memory();
let used_memory = sys.used_memory();
let used_percent = (sys.used_memory() as f64 / sys.total_memory() as f64) * 100.0;
debug!(
"total memory: {} bytes, free memory: {} bytes, available memory: {} bytes, used memory: {} bytes, used percent: {}%",
total_memory,
free_memory,
available_memory,
used_memory,
used_percent
);
MemoryStats {
total: total_memory,
free: free_memory,
available: available_memory,
usage: used_memory,
used_percent: used_percent.clamp(0.0, 100.0),
}
}
pub fn get_process_stats(&self, pid: u32) -> ProcessMemoryStats {
let sys = System::new_with_specifics(
RefreshKind::new()
.with_memory(MemoryRefreshKind::new().with_ram())
.with_processes(ProcessRefreshKind::new().with_memory()),
);
let memory_usage = sys.process(Pid::from_u32(pid)).unwrap().memory();
let total_memory = sys.total_memory();
let used_percent = (memory_usage as f64 / total_memory as f64) * 100.0;
debug!(
"process {} memory usage: {} bytes, total memory: {} bytes, used percent: {}%",
pid, memory_usage, total_memory, used_percent
);
ProcessMemoryStats {
used_percent: used_percent.clamp(0.0, 100.0),
}
}
#[allow(unused_variables)]
pub fn get_cgroup_stats(&self, pid: u32) -> Option<CgroupMemoryStats> {
#[cfg(target_os = "linux")]
{
use crate::cgroups::get_cgroup_by_pid;
use cgroups_rs::fs::memory::MemController;
use tracing::error;
match get_cgroup_by_pid(pid) {
Ok(cgroup) => {
if let Some(memory_controller) = cgroup.controller_of::<MemController>() {
let memory_stats = memory_controller.memory_stat();
let used_percent = if memory_stats.limit_in_bytes > 0 {
(memory_stats.stat.rss as f64 / memory_stats.limit_in_bytes as f64)
* 100.0
} else {
(memory_stats.stat.rss as f64 / self.get_stats().total as f64) * 100.0
};
debug!(
"process {} cgroup memory limit: {} bytes, memory usage: {} bytes, used percent: {}%",
pid,
memory_stats.limit_in_bytes,
memory_stats.stat.rss,
used_percent,
);
return Some(CgroupMemoryStats {
limit: memory_stats.limit_in_bytes,
usage: memory_stats.stat.rss,
used_percent: used_percent.clamp(0.0, 100.0),
});
}
}
Err(err) => {
error!("failed to get cgroup for pid {}: {}", pid, err);
return None;
}
}
}
None
}
}