//! adlermon — Alder Lake monitor. //! //! Currently a dump tool: prints a one-shot sensor snapshot to stdout. The //! TUI consumes the same `sensors` layer once the vCore source spike is done. mod sensors; mod ui; use std::thread::sleep; use std::time::{Duration, Instant}; use sensors::{cpu_frequencies, discover_chips, rapl_domains, rapl_energy_uj}; fn main() { let args: Vec = std::env::args().collect(); if args.iter().any(|a| a == "--vid") { vid_spike(); return; } if args.iter().any(|a| a == "--tui") { ui::run_tui(); return; } println!("== hwmon =="); for chip in discover_chips() { println!("[{}] {}", chip.name, chip.path.display()); for (label, volts) in sensors::voltages(&chip) { println!(" {:>18}: {:8.3} V", label, volts); } for (label, temp) in sensors::temperatures(&chip) { println!(" {:>18}: {:7.1} °C", label, temp); } for (label, rpm) in sensors::fans(&chip) { println!(" {:>18}: {:7.0} RPM", label, rpm); } } println!("\n== cpu frequency (MHz) =="); for (cpu, khz) in cpu_frequencies() { println!(" cpu{:>2}: {:8.1} MHz", cpu, khz as f64 / 1000.0); } println!("\n== RAPL power (sampled over 500 ms) =="); let domains = rapl_domains(); let first: Vec> = domains.iter().map(|d| rapl_energy_uj(&d.id)).collect(); let start = Instant::now(); sleep(Duration::from_millis(500)); let elapsed = start.elapsed().as_secs_f64(); for (domain, first) in domains.iter().zip(first) { match (first, rapl_energy_uj(&domain.id)) { (Some(a), Some(b)) if b >= a => { let watts = (b - a) as f64 / 1_000_000.0 / elapsed; println!(" {:>18} ({}): {:6.2} W", domain.name, domain.id, watts); } _ => println!(" {:>18} ({}): unreadable", domain.name, domain.id), } } } /// VID cross-check spike: compare SIO in0 (delivered rail) with the CPU's /// reported VID (IA32_PERF_STATUS) per sample. Requires root + msr module. fn vid_spike() { println!("== VID cross-check (needs root: /dev/cpu/*/msr) =="); for round in 0..5 { let vcore = sensors::sio_vcore(); let vids: Vec> = (0..16).map(sensors::vid_volts).collect(); println!("-- sample {} --", round); match vcore { Some(v) => println!(" SIO in0 (vCore): {:?}", v), None => println!(" SIO in0 (vCore): UNAVAILABLE"), } for (cpu, vid) in vids.iter().enumerate() { match vid { Some(v) => println!(" cpu{:>2} VID: {:?}", cpu, v), None => println!(" cpu{:>2} VID: unreadable", cpu), } } std::thread::sleep(std::time::Duration::from_millis(400)); } }