use serde::Serialize;
use std::sync::{Arc, Mutex};
#[derive(Clone, Default, Serialize)]
pub struct Snapshot {
pub ts: u64,
pub cpu_percent: f32,
pub cores: usize,
pub load1: f64,
pub ram_total: u64,
pub ram_used: u64,
pub disk_total: u64,
pub disk_free: u64,
pub process_rss: u64,
}
pub struct SysMon {
snap: Mutex<Snapshot>,
}
impl SysMon {
pub fn snapshot(&self) -> Snapshot {
self.snap.lock().unwrap().clone()
}
}
fn now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}
pub fn spawn(models_dir: String) -> Arc<SysMon> {
let mon = Arc::new(SysMon {
snap: Mutex::new(Snapshot::default()),
});
let ret = mon.clone();
tokio::task::spawn_blocking(move || {
use sysinfo::{Disks, ProcessesToUpdate, System};
let mut sys = System::new();
let pid = sysinfo::Pid::from_u32(std::process::id());
let models_abs = std::fs::canonicalize(&models_dir)
.unwrap_or_else(|_| std::path::PathBuf::from(&models_dir));
loop {
sys.refresh_cpu_usage();
sys.refresh_memory();
let _ = sys.refresh_processes(ProcessesToUpdate::Some(&[pid]), true);
let disks = Disks::new_with_refreshed_list();
let mut best: Option<(usize, u64, u64)> = None;
for d in disks.list() {
let mp = d.mount_point();
if models_abs.starts_with(mp) {
let len = mp.as_os_str().len();
if best.map(|(l, _, _)| len > l).unwrap_or(true) {
best = Some((len, d.total_space(), d.available_space()));
}
}
}
let (disk_total, disk_free) = best.map(|(_, t, f)| (t, f)).unwrap_or((0, 0));
let snap = Snapshot {
ts: now(),
cpu_percent: sys.global_cpu_usage(),
cores: sys.cpus().len(),
load1: System::load_average().one,
ram_total: sys.total_memory(),
ram_used: sys.used_memory(),
disk_total,
disk_free,
process_rss: sys.process(pid).map(|p| p.memory()).unwrap_or(0),
};
*mon.snap.lock().unwrap() = snap;
std::thread::sleep(std::time::Duration::from_secs(2));
}
});
ret
}