From 293293aa9b3e8ee5188dfa7cd7711b375a79f6eb Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 25 May 2020 11:07:24 +0200 Subject: [PATCH] procfs: add loadavg reader Signed-off-by: Wolfgang Bumiller --- proxmox/src/sys/linux/procfs.rs | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/proxmox/src/sys/linux/procfs.rs b/proxmox/src/sys/linux/procfs.rs index b95d68f0..85f87f73 100644 --- a/proxmox/src/sys/linux/procfs.rs +++ b/proxmox/src/sys/linux/procfs.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; use std::convert::TryFrom; +use std::fmt; use std::fs::OpenOptions; use std::io::{BufRead, BufReader}; use std::net::{Ipv4Addr, Ipv6Addr}; @@ -730,3 +731,59 @@ mod tests { read_proc_net_ipv6_route().unwrap(); } } + +/// Read the load avage from `/proc/loadavg`. +pub fn read_loadavg() -> Result { + Loadavg::read() +} + +/// Load avarage: floating point values for 1, 5 and 15 minutes of runtime. +#[derive(Clone, Debug)] +pub struct Loadavg(pub f64, pub f64, pub f64); + +impl Loadavg { + /// Read the load avage from `/proc/loadavg`. + pub fn read() -> Result { + Self::parse(unsafe { std::str::from_utf8_unchecked(&std::fs::read("/proc/loadavg")?) }) + } + + /// Parse the value triplet. + fn parse(line: &str) -> Result { + let mut parts = line.trim_start().split_ascii_whitespace(); + let missing = || format_err!("missing field in /proc/loadavg"); + let one: f64 = parts.next().ok_or_else(missing)?.parse()?; + let five: f64 = parts.next().ok_or_else(missing)?.parse()?; + let fifteen: f64 = parts.next().ok_or_else(missing)?.parse()?; + Ok(Self(one, five, fifteen)) + } + + /// Named method for the one minute load average. + pub fn one(&self) -> f64 { + self.0 + } + + /// Named method for the five minute load average. + pub fn five(&self) -> f64 { + self.1 + } + + /// Named method for the fifteen minute load average. + pub fn fifteen(&self) -> f64 { + self.2 + } +} + +impl fmt::Display for Loadavg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {}, {})", self.0, self.1, self.2) + } +} + +#[test] +fn test_loadavg() { + let avg = Loadavg::parse("0.44 0.48 0.44 2/1062 18549") + .expect("loadavg parser failed"); + assert_eq!((avg.one() * 1000.0) as u64, 440u64); + assert_eq!((avg.five() * 1000.0) as u64, 480u64); + assert_eq!((avg.fifteen() * 1000.0) as u64, 440u64); +}