monitoring kit
Diffstat (limited to 'cpu/src/lib.rs')
| -rw-r--r-- | cpu/src/lib.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs new file mode 100644 index 0000000..5ddb34c --- /dev/null +++ b/cpu/src/lib.rs @@ -0,0 +1,173 @@ +#![feature( + let_chains, + iter_array_chunks, + array_chunks, + generic_const_exprs, + portable_simd, + iter_chain +)] +use anyhow::*; +use atools::prelude::*; +use collar::CollectArray; +use parking_lot::Mutex; +use std::collections::HashMap; +use std::fmt::Display; +use std::fs::{read_to_string as read, File}; +use std::io::Read; +use std::io::Seek; +use std::mem::replace; +use std::path::Path; +use std::sync::OnceLock; + +#[derive(Copy, Clone, Debug)] +pub enum ViewCore { + All(u64), + One(u64), +} +impl Display for ViewCore { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ViewCore::All(x) => write!(f, "..#{x}"), + ViewCore::One(x) => write!(f, "#{x}"), + } + } +} + +pub static CORE: OnceLock<ViewCore> = OnceLock::new(); + +#[derive(Debug, Clone, Default, PartialEq)] +pub struct CpuInfo { + pub name: String, + pub speed: f64, + pub count: u64, +} + +pub struct Temps(File); +impl Temps { + pub fn load() -> Result<Self> { + for hwmon in std::fs::read_dir("/sys/class/hwmon/")?.filter_map(Result::ok) { + if !read(Path::join(&hwmon.path(), "name"))?.starts_with("coretemp") { + continue; + } + for f in std::fs::read_dir(hwmon.path())?.filter_map(Result::ok) { + if let Some(n) = f.file_name().to_str() + && n.starts_with("temp") + && n.ends_with("input") + { + let i = n + .bytes() + .filter(u8::is_ascii_digit) + .fold(0, |acc, x| acc * 10 + (x - b'0') as u64); + + let name = read(Path::join(&hwmon.path(), format!("temp{i}_label"))) + .context("alas")?; + if let Some(c) = core() { + if !name.contains(&c.to_string()) { + continue; + } + } else if !name.contains("Package") { + continue; + } + + let f = File::open(f.path())?; + return Ok(Self(f)); + } + } + } + bail!("h") + } + pub fn read(&mut self) -> Result<f64> { + let mut o = String::default(); + self.0.seek(std::io::SeekFrom::Start(0))?; + self.0.read_to_string(&mut o)?; + Ok(o.trim().parse::<f64>().context("reading temps")? / 1000.0) + } +} + +impl CpuInfo { + pub fn read() -> Result<Self> { + let x = String::from_utf8( + std::process::Command::new("lscpu") + .env("LC_ALL", "C") + .output() + .context("lscpuless")? + .stdout, + ) + .context("unable to parse lscpu output to UTF-8")?; + let x = x + .lines() + .filter_map(|l| l.split_once(":").map(|(a, b)| (a, b.trim()))) + .collect::<HashMap<_, _>>(); + let name = x["Model name"] + .replace("Core", "") + .replace("(TM)", "") + .replace("Intel", "") + .replace("(R)", ""); + let name = regex::Regex::new(r"@ [0-9]+\.[0-9]+GHz") + .unwrap() + .replace(&name, ""); + let name = regex::Regex::new(r"[0-9]+th Gen") + .unwrap() + .replace(&name, "") + .replace(" ", " ") + .trim() + .replace(" ", " ") + .to_lowercase(); + Ok(Self { + name: name, + speed: x["CPU max MHz"].parse::<f64>().context("cpu mhz??")? / 1000.0, + count: x["CPU(s)"].parse()?, + }) + } +} + +pub fn sped(core: u64) -> Result<f64> { + Ok(read(format!( + "/sys/devices/system/cpu/cpu{core}/cpufreq/scaling_cur_freq" + )) + .context("speed")? + .replace('\n', "") + .parse::<u64>() + .context("reading speeds")? as f64 + / 1e6) +} + +pub fn speed() -> Result<f64> { + Ok(match *CORE.get().unwrap() { + ViewCore::All(x) => (0..x).map(sped).sum::<Result<f64, _>>()? / x as f64, + ViewCore::One(x) => sped(x)?, + }) +} + +pub fn core() -> Option<u64> { + CORE.get().copied().and_then(|x| match x { + ViewCore::One(x) => Some(x), + _ => None, + }) +} + +pub fn usage() -> Result<f64> { + let x = read("/proc/stat")?; + let x = x + .lines() + .nth(core().map_or(0, |x| x as usize + 1)) + .ok_or(anyhow!("no procstat"))?; + + // https://www.linuxhowtos.org/System/procstat.htm + let x @ [_user, _nice, _system, idle, iowait, _irq, _softirq] = x + .split_whitespace() + .skip(1) + .map(|x| x.parse::<u64>()) + .try_collect_array()?; + + static LAST: Mutex<[u64; 2]> = Mutex::new([0; 2]); + let [pi, pt] = &mut *LAST.lock(); + + let idle = idle + iowait; + let tot = x.sum(); + + let idle = (idle - replace(pi, idle)) as f64; + let tot = (tot - replace(pt, tot)) as f64; + let r = (tot - idle) / tot; + Ok((r == r).then_some(r).unwrap_or(0.0)) +} |