8a5e218ccd2639f734d2b70bd52a0fc0f1e7a87f / src/main.rs · 2889 bytes · raw
//! 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<String> = 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<Option<u64>> = 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<Option<f64>> = (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));
}
}