use std::time::Instant;
use sysinfo::{Networks, Pid, ProcessRefreshKind, ProcessesToUpdate, System};
fn phys_footprint(pid: u32) -> Option<u64> {
let mut info: libc::rusage_info_v4 = unsafe { std::mem::zeroed() };
let r = unsafe {
libc::proc_pid_rusage(
pid as libc::c_int,
libc::RUSAGE_INFO_V4,
&mut info as *mut _ as *mut libc::rusage_info_t,
)
};
(r == 0).then_some(info.ri_phys_footprint)
}
pub struct Sys {
sys: System,
nets: Networks,
last: Instant,
pub cpu: f32, pub mem: f32, pub miner_cpu: f32,
pub miner_mem: f32,
pub down_kbs: f64, pub up_kbs: f64, }
impl Sys {
pub fn new() -> Self {
let mut sys = System::new();
sys.refresh_cpu_usage();
sys.refresh_memory();
Sys {
sys,
nets: Networks::new_with_refreshed_list(),
last: Instant::now(),
cpu: 0.0,
mem: 0.0,
miner_cpu: 0.0,
miner_mem: 0.0,
down_kbs: 0.0,
up_kbs: 0.0,
}
}
pub fn refresh(&mut self, miner_pid: Option<u32>) {
let dt = self.last.elapsed().as_secs_f64();
if dt < 1.0 {
return;
}
self.sys.refresh_cpu_usage();
self.sys.refresh_memory();
self.cpu = (self.sys.global_cpu_usage() / 100.0).clamp(0.0, 1.0);
let total = self.sys.total_memory().max(1) as f32;
self.mem = (self.sys.used_memory() as f32 / total).clamp(0.0, 1.0);
self.nets.refresh(true);
let (mut rx, mut tx) = (0u64, 0u64);
for (_, d) in self.nets.iter() {
rx += d.received();
tx += d.transmitted();
}
self.down_kbs = rx as f64 / 1024.0 / dt;
self.up_kbs = tx as f64 / 1024.0 / dt;
self.miner_cpu = 0.0;
self.miner_mem = 0.0;
if let Some(pid) = miner_pid {
let pid = Pid::from_u32(pid);
self.sys.refresh_processes_specifics(
ProcessesToUpdate::Some(&[pid]),
true,
ProcessRefreshKind::nothing().with_cpu().with_memory(),
);
if let Some(proc) = self.sys.process(pid) {
let cores = self.sys.cpus().len().max(1) as f32;
self.miner_cpu = (proc.cpu_usage() / 100.0 / cores).clamp(0.0, 1.0);
let total = self.sys.total_memory().max(1) as f32;
let bytes = phys_footprint(miner_pid.unwrap_or(0)).unwrap_or(proc.memory());
self.miner_mem = (bytes as f32 / total).clamp(0.0, 1.0);
}
}
self.last = Instant::now();
}
}