monitoring kit
Diffstat (limited to 'gpu/src/intel.rs')
| -rw-r--r-- | gpu/src/intel.rs | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/gpu/src/intel.rs b/gpu/src/intel.rs new file mode 100644 index 0000000..b9c7dc8 --- /dev/null +++ b/gpu/src/intel.rs @@ -0,0 +1,201 @@ +#![feature( + generic_arg_infer, + import_trait_associated_functions, + string_deref_patterns, + deref_patterns, + let_chains, + iter_array_chunks, + array_chunks, + generic_const_exprs, + portable_simd, + iter_chain +)] +use anyhow::*; +use collar::CollectArray as _; +use comat::cwrite; +use grapher::Grapher; +use parking_lot::Mutex; +use std::array; +use std::ffi::{c_char, CStr}; +use std::fmt::Display; +use std::fs::{read_dir, read_to_string as read}; +use std::io::{stdout, Read}; +use std::io::{BufRead, BufReader, Write}; +use std::process::{Command, Stdio}; +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}; + +#[repr(C)] +#[derive(Default)] +struct igt_devices_print_format { + ty: u32, + option: u32, + numeric: bool, + codename: bool, +} +#[repr(C)] +struct strong<const N: usize>([c_char; N]); +impl<const N: usize> Default for strong<N> { + fn default() -> Self { + Self([0; N]) + } +} +impl<const N: usize> Display for strong<N> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", unsafe { + CStr::from_ptr(self.0.as_ptr()).to_str().unwrap() + }) + } +} + +#[repr(C)] +#[derive(Default)] +struct igt_device_card { + subsystem: strong<256>, + card: strong<256>, + render: strong<256>, + pci_slot_name: strong<13>, + pci_vendor: u16, + pci_device: u16, +} + +unsafe extern "C" { + fn igt_devices_scan(); + fn igt_devices_print(opts: *const igt_devices_print_format); + fn igt_device_find_integrated_card(card: *mut igt_device_card) -> bool; + fn igt_device_get_pretty_name(card: *const igt_device_card, numeric: bool) -> *const c_char; + +} + +fn uh() -> Result<()> { + dbg!("???"); + let x = std::fs::read_dir("/sys/devices")? + .filter_map(Result::ok) + .filter(|x| { + x.file_name() + .into_string() + .is_ok_and(|x| x.starts_with("pci")) + }) + .filter_map(|x| read_dir(x.path()).ok()) + .flatten() + .filter_map(Result::ok) + .find(|x| read(x.path().join("uevent")).is_ok_and(|x| x.contains("i915"))) + .ok_or(anyhow!("intelless"))? + .path(); + + // println!("{:?}", x.location().unwrap()); + let pciid = read(x.join("uevent")) + .unwrap() + .lines() + .find(|x| x.starts_with("PCI_ID")) + .ok_or(anyhow!("eh"))? + .split_once("=") + .unwrap() + .1 + .split_once(":") + .unwrap() + .1 + .to_lowercase(); + + let name = read("/usr/share/hwdata/pci.ids")? + .lines() + .filter(|x| x.starts_with('\t')) + .find(|x| x[1..].starts_with(&pciid)) + .map(|x| x[1 + pciid.len()..].trim().to_string()) + .unwrap(); + dbg!(name); + Ok(()) +} +fn main() -> Result<()> { + use atools::Join; + + let mut c = Command::new("intel_gpu_top") + .args(["-s", "100", "-c"]) + .stdout(Stdio::piped()) + .stdin(Stdio::inherit()) + .spawn()?; + let r = c.stdout.take().unwrap(); + static last: Mutex<[f64; 7]> = Mutex::new([f64::NAN; _]); + std::thread::spawn(move || { + // Freq MHz req,Freq MHz act,IRQ /s,RC6 %,Power W gpu,Power W pkg,RCS %,RCS se,RCS wa,BCS %,BCS se,BCS wa,VCS %,VCS se,VCS wa,VECS %,VECS se,VECS wa + for line in BufReader::new(r).lines().skip(1) { + let line = line.unwrap(); + let mut splat = line.split(",").map(|x| x.parse::<f64>().unwrap()); + let x = splat.collect_array::<6>(); + let busy = splat.array_chunks::<3>().map(|x| x[0]).sum::<f64>(); + *last.lock() = x.join(busy / 100.); + } + }); + + // [f_req, f_act, irq, rc6, power_gpu, power_package, busy] + unsafe { igt_devices_scan() }; + let mut card = igt_device_card::default(); + let ret = unsafe { igt_device_find_integrated_card(&mut card) }; + if !ret { + bail!("igpuless!! (i dont have an arc gpu it should be simple to add that tho)") + } + let name = unsafe { + CStr::from_ptr(igt_device_get_pretty_name(&card, false)) + .to_str() + .unwrap() + }; + + fn inter([a, b, c]: [f32; 3], [d, e, f]: [f32; 3], fc: f32) -> [f32; 3] { + [a + (d - a) * fc, b + (e - b) * fc, c + (f - c) * fc] + } + + let mut g = Grapher::new()?; + sleep(Duration::from_secs_f32(0.5)); + if let std::result::Result::Ok(Some(_)) = c.try_wait() { + return Ok(()); + } + let 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(); + 'out: loop { + if let std::result::Result::Ok(Some(_)) = c.try_wait() { + return Ok(()); + } + let (_, h) = termion::terminal_size()?; + + let mut key = 0; + while stdin.read(array::from_mut(&mut key)).unwrap() != 0 { + match key { + b'q' => break 'out, + + _ => (), + } + } + + 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), + ) + })?; + + write!(g.buffer, "{}{}", White.fg_str(), cursor::Goto(1, 1))?; + let [f_req, f_act, irq, _rc6, power_gpu, power_package, busy] = *last.lock(); + cwrite!( + g.buffer, + " {name} @ {f_req:.0}/ {f_act:.0} MHz ─── {power_gpu:.1}/ {power_package:.1} W ─── {irq:.0} irqs/s" + )?; + stdout.write_all(&g.buffer)?; + stdout.flush()?; + + sleep(Duration::from_secs_f32(d)); + g.push_point(busy); + } + println!("\x1B[?7l"); + Ok(()) +} |