monitoring kit
Diffstat (limited to 'disk/src/disk.rs')
| -rw-r--r-- | disk/src/disk.rs | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/disk/src/disk.rs b/disk/src/disk.rs new file mode 100644 index 0000000..677fd1c --- /dev/null +++ b/disk/src/disk.rs @@ -0,0 +1,112 @@ +#![feature(portable_simd, string_deref_patterns, duration_millis_float)] +use anyhow::*; +use collar::CollectArray; +use grapher::{Grapher, truncwrite}; +use human_bytes::human_bytes; +use std::array; +use std::fs::read_to_string as read; +use std::io::Write; +use std::io::{Read, stdout}; +use std::process::exit; +use std::thread::sleep; +use std::time::{Duration, Instant}; +use termion::color::*; +use termion::cursor::Hide; +use termion::raw::IntoRawMode; +use termion::screen::IntoAlternateScreen; +use termion::{async_stdin, clear, cursor, style}; +#[implicit_fn::implicit_fn] +fn main() -> Result<()> { + let disk = match std::env::args().nth(1) { + None => { + let fs = std::fs::read_dir("/sys/block")? + .filter_map(Result::ok) + .filter_map(_.file_name().into_string().ok()) + .collect::<Vec<_>>(); + eprintln!("no args! must be one of {fs:?}"); + exit(1) + } + Some(x) => x, + }; + let write = match std::env::args().nth(2) { + Some("r") => false, + Some("w") => true, + Some(_) | None => { + eprintln!("requires r/w arg"); + exit(1) + } + }; + let drive = std::fs::read_dir("/sys/block")? + .filter_map(Result::ok) + .find(_.file_name().to_string_lossy().starts_with(&disk)) + .ok_or(anyhow!("no network"))? + .path(); + + let name = read(drive.join("device").join("model"))?; + let name = name.trim(); + + // https://www.kernel.org/doc/html/latest/block/stat.html + let ticks = || { + let [_rio, _rm, rs, _rt, _wio, _wm, ws, _wt] = read(drive.join("stat"))? + .split_whitespace() + .filter_map(_.parse::<u32>().ok()) + .collect_array(); + + Ok(write.then_some(ws).unwrap_or(rs)) + }; + + let mut g = Grapher::new()?; + let mut d = 0.1; + + let mut stdout = stdout().into_raw_mode()?.into_alternate_screen()?; + let mut stdin = async_stdin(); + write!(stdout, "{}{}{}", Hide, clear::All, style::Reset).unwrap(); + let mut max = 1f64; + let mut last = ticks()?; + + let mut i = Instant::now(); + 'out: loop { + sleep(Duration::from_secs_f32(d)); + + let pass = i.elapsed().as_millis_f64(); + let new = ticks()?; + i = Instant::now(); + + let δ = (new - last) * 512; + let r = δ as f64 / pass; + g.push_point(r); + max = max.max(r); + last = new; + + let mut key = 0; + while stdin.read(array::from_mut(&mut key)).unwrap() != 0 { + match key { + b'q' => break 'out, + b'+' => d = (d + 0.1f32).min(1.0), + b'-' if d >= 0.2 => d -= 0.1, + b'-' if d >= 0.02 => d -= 0.01, + b'-' => d = 0.00833, + _ => (), + } + } + + g.draw(|_| None, _ / max as f64)?; + write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; + + let fps = (1f32 / d).round(); + truncwrite!( + g.buffer, + " {fps}fps ──── {name} ──── ceil {}/s ──── curr {}/s ─ {}", + human_bytes(max as f64 * 1e3), + human_bytes(r as f64 * 1e3), // 1e3 + ["read", "write"][write as usize], + )?; + + write!(stdout, "{}", Rgb(106, 186, 212).fg_string())?; + + stdout.write_all(&g.buffer)?; + stdout.flush()?; + } + println!("\x1B[?7l"); + return Ok(()); +} |