monitoring kit
ping
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | battery/src/charge.rs | 3 | ||||
| -rw-r--r-- | cpu/src/cpu.rs | 22 | ||||
| -rw-r--r-- | cpu/src/temps.rs | 22 | ||||
| -rw-r--r-- | gpu/src/intel.rs | 22 | ||||
| -rw-r--r-- | grapher/src/lib.rs | 7 | ||||
| -rw-r--r-- | memory/src/main.rs | 3 | ||||
| -rw-r--r-- | ping/Cargo.toml | 21 | ||||
| -rw-r--r-- | ping/src/ping.rs | 133 |
9 files changed, 204 insertions, 31 deletions
@@ -1,5 +1,5 @@ [workspace] -members = ["cpu", "grapher", "memory", "gpu", "battery"] +members = ["cpu", "grapher", "memory", "gpu", "battery", "ping"] resolver = "3" [profile.release] diff --git a/battery/src/charge.rs b/battery/src/charge.rs index ecba756..66cd98d 100644 --- a/battery/src/charge.rs +++ b/battery/src/charge.rs @@ -11,6 +11,7 @@ use anyhow::*; use grapher::{truncwrite, Grapher}; use std::array; +use std::convert::identity; use std::fs::read_to_string as read; use std::io::Write; use std::io::{stdout, Read}; @@ -71,7 +72,7 @@ fn main() -> Result<()> { } } - g.draw(|_| None)?; + g.draw(|_| None, identity)?; let current = fetch("POWER_SUPPLY_CAPACITY", str::parse::<f64>)?; let whs = fetch("POWER_SUPPLY_ENERGY_NOW", str::parse::<f64>)? / 1e6; let usage = fetch("POWER_SUPPLY_POWER_NOW", str::parse::<f64>)? / 1e6; diff --git a/cpu/src/cpu.rs b/cpu/src/cpu.rs index 459eef3..00feb75 100644 --- a/cpu/src/cpu.rs +++ b/cpu/src/cpu.rs @@ -11,6 +11,7 @@ use comat::cwrite; use cpu::*; use grapher::Grapher; use std::array; +use std::convert::identity; use std::io::Write; use std::io::{stdout, Read}; use std::thread::sleep; @@ -62,16 +63,19 @@ fn main() -> Result<()> { } } - g.draw(|y| { - Some( - inter( - [243, 64, 64].map(|x| x as f32 / 255.0), // red - [228, 197, 63].map(|x| x as f32 / 255.0), // yellow - y as f32 / (h - 1) as f32, + g.draw( + |y| { + Some( + inter( + [243, 64, 64].map(|x| x as f32 / 255.0), // red + [228, 197, 63].map(|x| x as f32 / 255.0), // yellow + y as f32 / (h - 1) as f32, + ) + .map(|x| (x * 255.0) as u8), ) - .map(|x| (x * 255.0) as u8), - ) - })?; + }, + identity, + )?; write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; let name = &*info.name; diff --git a/cpu/src/temps.rs b/cpu/src/temps.rs index ea0031f..485b427 100644 --- a/cpu/src/temps.rs +++ b/cpu/src/temps.rs @@ -4,6 +4,7 @@ use comat::cwrite; use cpu::*; use grapher::Grapher; use std::array; +use std::convert::identity; use std::io::Write; use std::io::{stdout, Read}; use std::thread::sleep; @@ -55,16 +56,19 @@ fn main() -> Result<()> { } } - g.draw(|y| { - Some( - inter( - [228, 197, 63].map(|x| x as f32 / 255.0), // yellow - [0x5c, 0xc7, 0xdd].map(|x| x as f32 / 255.0), // blue - y as f32 / (h - 1) as f32, + g.draw( + |y| { + Some( + inter( + [228, 197, 63].map(|x| x as f32 / 255.0), // yellow + [0x5c, 0xc7, 0xdd].map(|x| x as f32 / 255.0), // blue + y as f32 / (h - 1) as f32, + ) + .map(|x| (x * 255.0) as u8), ) - .map(|x| (x * 255.0) as u8), - ) - })?; + }, + identity, + )?; write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; let name = &*info.name; diff --git a/gpu/src/intel.rs b/gpu/src/intel.rs index da71f72..1352fb0 100644 --- a/gpu/src/intel.rs +++ b/gpu/src/intel.rs @@ -16,6 +16,7 @@ use comat::cwrite; use grapher::Grapher; use parking_lot::Mutex; use std::array; +use std::convert::identity; use std::ffi::{c_char, CStr}; use std::fmt::Display; use std::fs::{read_dir, read_to_string as read}; @@ -172,16 +173,19 @@ fn main() -> Result<()> { } } - g.draw(|y| { - Some( - inter( - [243, 64, 64].map(|x| x as f32 / 255.0), // red - [228, 197, 63].map(|x| x as f32 / 255.0), // yellow - y as f32 / (h - 1) as f32, + g.draw( + |y| { + Some( + inter( + [243, 64, 64].map(|x| x as f32 / 255.0), // red + [228, 197, 63].map(|x| x as f32 / 255.0), // yellow + y as f32 / (h - 1) as f32, + ) + .map(|x| (x * 255.0) as u8), ) - .map(|x| (x * 255.0) as u8), - ) - })?; + }, + identity, + )?; write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; let [f_req, f_act, irq, _rc6, power_gpu, power_package, busy] = *last.lock(); diff --git a/grapher/src/lib.rs b/grapher/src/lib.rs index 354e41d..b6d2df2 100644 --- a/grapher/src/lib.rs +++ b/grapher/src/lib.rs @@ -31,7 +31,11 @@ impl Grapher { self.data.pop_back(); } - pub fn draw(&mut self, mut color: impl FnMut(u16) -> Option<[u8; 3]>) -> Result<&mut Vec<u8>> { + pub fn draw( + &mut self, + mut color: impl FnMut(u16) -> Option<[u8; 3]>, + mut mapping: impl FnMut(f64) -> f64, + ) -> Result<&mut Vec<u8>> { let Grapher { buffer: output, data, @@ -57,6 +61,7 @@ impl Grapher { .map(|column| { let mut data = [vec![false; (h * 4) as usize], vec![false; (h * 4) as usize]]; for (e, c) in zip(column, &mut data) { + let e = mapping(*e); let clen = c.len(); c[clen - ((h as f64 * e * 4.0).round().min(h as f64 * 4.0) as usize)..] .fill(true); diff --git a/memory/src/main.rs b/memory/src/main.rs index 94497a6..afb1d1c 100644 --- a/memory/src/main.rs +++ b/memory/src/main.rs @@ -4,6 +4,7 @@ use comat::cwrite; use grapher::Grapher; use std::array; use std::collections::HashMap; +use std::convert::identity; use std::fs::read_to_string as read; use std::io::Write; use std::io::{stdout, Read}; @@ -57,7 +58,7 @@ fn main() -> Result<()> { } let [tot, used] = info()?.map(|x| x as f64 / (1024. * 1024.)); let tot = tot.round(); - g.draw(|_| None)?; + g.draw(|_| None, identity)?; write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; let fps = (1f32 / d).round(); diff --git a/ping/Cargo.toml b/ping/Cargo.toml new file mode 100644 index 0000000..55b4516 --- /dev/null +++ b/ping/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ping" +version = "1.0.0" +edition = "2021" +authors = ["bend-n <[email protected]>"] +repository = "https://github.com/bend-n/monitorkit" +license = "MIT" +rust-version = "1.85" + +[dependencies] +anyhow = "1.0.97" +termion = "4.0.4" +grapher = { path = "../grapher" } +ping-rs = "0.1.2" +oneshot = { version = "0.1.11", default-features = false, features = ["std"] } + + +[[bin]] +name = "ping" +doc = false +path = "src/ping.rs" diff --git a/ping/src/ping.rs b/ping/src/ping.rs new file mode 100644 index 0000000..ec9a055 --- /dev/null +++ b/ping/src/ping.rs @@ -0,0 +1,133 @@ +#![feature( + generic_arg_infer, + import_trait_associated_functions, + string_deref_patterns, + let_chains, + iter_array_chunks, + array_chunks, + portable_simd, + iter_chain +)] +use anyhow::*; +use grapher::{truncwrite, Grapher}; +use ping_rs::PingError; +use std::array; +use std::io::Write; +use std::io::{stdout, Read}; +use std::net::{IpAddr, ToSocketAddrs}; +use std::result::Result::Ok as Rok; +use std::thread::sleep; +use std::time::Duration; +use termion::color::*; +use termion::cursor::Hide; +use termion::raw::IntoRawMode; +use termion::screen::IntoAlternateScreen; +use termion::{async_stdin, clear, cursor, style}; +fn ping(x: IpAddr) -> Result<u32> { + match ping_rs::send_ping(&x, Duration::from_secs(2), b"", None) { + Rok(x) => Ok(x.rtt), + Err(PingError::TimedOut | PingError::IoPending) => Ok(!0), + Err(x) => bail!("{x:?}"), + } +} + +fn resolve(host: &str) -> Result<IpAddr> { + (host, 80) + .to_socket_addrs() + .context("resolve")? + .map(|x| x.ip()) + .next() + .ok_or(anyhow!("no resolution")) +} + +fn main() -> Result<()> { + let who = std::env::args().nth(1).ok_or(anyhow!("who to ping?"))?; + let ip = resolve(&who)?; + eprintln!("pinging {ip}"); + let _ = ping(ip)?; + let [mut max, mut sum, mut points, mut dropped] = [0; _]; + let mut min = !0; + + let (tx, rx) = std::sync::mpsc::channel::<u32>(); + let (ftx, frx) = oneshot::channel::<()>(); + std::thread::spawn(move || { + let result = ping(ip).unwrap(); + tx.send(result).unwrap(); + _ = ftx.send(()); + loop { + std::thread::sleep(Duration::from_millis(100u64.saturating_sub(result as _))); + let result = ping(ip).unwrap(); + tx.send(result).unwrap(); + } + }); + frx.recv()?; + + let mut g = Grapher::new()?; + + let mut stdout = stdout().into_raw_mode()?.into_alternate_screen()?; + let mut stdin = async_stdin(); + write!(stdout, "{}{}{}", Hide, clear::All, style::Reset).unwrap(); + 'out: loop { + let mut key = 0; + while stdin.read(array::from_mut(&mut key)).unwrap() != 0 { + match key { + b'q' => break 'out, + _ => (), + } + } + + let r = rx.try_recv(); + if let Rok(r) = r + && r != !0 + { + sum += r; + points += 1; + min = min.min(r); + max = max.max(r); + } else { + dropped += 1; + } + let avg = sum / points; + let mut r = r.unwrap_or(avg); + if r == !0 { + r = avg; + } + + let dat = g.data.iter().copied().filter(|&x| x != 0.0); + let sum = dat + .clone() + .filter(|&x| x != 0.0) + .map(|x| x - avg as f64) + .sum::<f64>(); + let dev = (sum / (dat.count()) as f64).abs(); + + g.push_point(r as f64); + g.draw( + |_| None, + |x| { + match max { + ..90 => x / 100.0, + ..240 => x / 250.0, + ..490 => x / 500.0, + ..990 => x / 1000.0, + _ => x / (max as f64 + 10.0), + } + .min(1.0) + }, + )?; + + write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; + truncwrite!( + g.buffer, + " {who} ({ip}) ── last {r}ms ── min {min} avg {avg} max {max} dev ±{dev:.2}ms ── dropped {dropped} /{points}pckts ({:.1}%)", + (dropped as f64 /points as f64)*100.0, + )?; + write!(stdout, "{}", Rgb(40, 185, 119).fg_string())?; + stdout.write_all(&g.buffer)?; + stdout.flush()?; + + sleep(Duration::from_millis(100)); + } + println!("\x1B[?7l"); + Ok(()) +} |