use serde::{Deserialize, Serialize};
use std::fmt;
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
use std::ops::Sub;
#[derive(Deserialize, Serialize, Debug, Copy, Clone, Default)]
pub struct CpuTime {
pub usr: i64,
pub nice: i64,
pub system: i64,
pub idle: i64,
pub iowait: i64,
pub irq: i64,
pub softirq: i64,
}
impl fmt::Display for CpuTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s: Vec<String> = Vec::new();
s.push(format!("{} usr,", self.usr));
s.push(format!("{} nice,", self.nice));
s.push(format!("{} system,", self.system));
s.push(format!("{} idle,", self.idle));
s.push(format!("{} iowait,", self.iowait));
s.push(format!("{} irq,", self.irq));
s.push(format!("{} softirq,", self.softirq));
write!(f, "CPU: {}", s.join(" ").trim_end_matches(','))
}
}
impl CpuTime {
pub fn load() -> Result<Self> {
let f = fs::OpenOptions::new()
.read(true)
.open("/proc/stat")
.map_err(|e| Error::new(ErrorKind::Other, format!("{}", e)))?;
let mut reader = BufReader::new(f);
loop {
let mut line = String::new();
reader.read_line(&mut line)?;
let mut entries = line.split_whitespace();
if let Some("cpu") = entries.next() {
let mut value = || -> i64 { entries.next().unwrap().parse().unwrap() };
return Ok(CpuTime {
usr: value(),
nice: value(),
system: value(),
idle: value(),
iowait: value(),
irq: value(),
softirq: value(),
});
}
}
}
pub fn new() -> Result<Self> {
CpuTime::load()
}
}
impl Sub for CpuTime {
type Output = CpuTimeDiff;
fn sub(self, other: Self) -> Self::Output {
let diff = |a: i64, b: i64| -> f32 { (a - b).abs() as f32 };
CpuTimeDiff {
usr: diff(self.usr, other.usr),
system: diff(self.system, other.system),
nice: diff(self.nice, other.nice),
idle: diff(self.idle, other.idle),
iowait: diff(self.iowait, other.iowait),
irq: diff(self.irq, other.irq),
softirq: diff(self.softirq, other.softirq),
}
}
}
pub struct CpuTimeDiff {
pub usr: f32,
pub nice: f32,
pub system: f32,
pub idle: f32,
pub iowait: f32,
pub irq: f32,
pub softirq: f32,
}
impl CpuTimeDiff {
pub fn total(&self) -> f32 {
self.usr + self.system + self.nice + self.idle + self.iowait + self.irq + self.softirq
}
pub fn cpu_report(&mut self) -> CpuReport {
let total = self.total();
CpuReport {
usr: Some(self.usr / total),
sys: Some(self.system / total),
nic: Some(self.nice / total),
idle: Some(self.idle / total),
io: Some(self.iowait / total),
irq: Some(self.irq / total),
sirq: Some(self.softirq / total),
}
}
}
#[derive(Deserialize, Serialize, Debug, Copy, Clone, Default)]
pub struct CpuReport {
pub usr: Option<f32>,
pub sys: Option<f32>,
pub nic: Option<f32>,
pub idle: Option<f32>,
pub io: Option<f32>,
pub irq: Option<f32>,
pub sirq: Option<f32>,
}
impl fmt::Display for CpuReport {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s: Vec<String> = Vec::new();
let round_up = |f: f32| -> f32 { (f * 1000_f32).round() / 10_f32 };
if let Some(a) = self.usr {
s.push(format!("{} us,", round_up(a)));
}
if let Some(a) = self.sys {
s.push(format!("{} sy,", round_up(a)));
}
if let Some(a) = self.nic {
s.push(format!("{} ni,", round_up(a)));
}
if let Some(a) = self.idle {
s.push(format!("{} id,", round_up(a)));
}
if let Some(a) = self.io {
s.push(format!("{} io,", round_up(a)));
}
if let Some(a) = self.irq {
s.push(format!("{} irq,", round_up(a)));
}
if let Some(a) = self.sirq {
s.push(format!("{} sirq,", round_up(a)));
}
write!(f, "CPU(%): {}", s.join(" ").trim_end_matches(','))
}
}