1use std::io::BufRead;
7use std::io::BufReader;
8use thiserror::Error;
9
10#[derive(Debug, Error)]
12#[expect(missing_docs)]
13pub enum VpStatsError {
14 #[error("failed to read /proc/mshv")]
15 Read(#[source] std::io::Error),
16 #[error("failed to parse stats string")]
17 ParseString(#[source] std::io::Error),
18 #[error("failed to parse stats line")]
19 ParseLine,
20 #[error("a cpu was missing from the stats file")]
21 MissingCpu,
22}
23
24#[derive(Debug)]
26pub struct HclVpStats {
27 pub vtl_transitions: u64,
29}
30
31pub fn vp_stats() -> Result<Vec<HclVpStats>, VpStatsError> {
33 let v = std::fs::read("/proc/mshv").map_err(VpStatsError::Read)?;
34 let lines = BufReader::new(v.as_slice()).lines().skip(2);
36 let mut stats = Vec::new();
37 for line in lines {
38 let line = line.map_err(VpStatsError::ParseString)?;
39 let (cpu, rest) = line.split_once(' ').ok_or(VpStatsError::ParseLine)?;
40 let n: usize = cpu
41 .strip_prefix("cpu")
42 .ok_or(VpStatsError::ParseLine)?
43 .parse()
44 .map_err(|_| VpStatsError::ParseLine)?;
45
46 if n != stats.len() {
47 return Err(VpStatsError::MissingCpu);
48 }
49 let vtl_transitions = rest
50 .split(' ')
51 .next()
52 .ok_or(VpStatsError::ParseLine)?
53 .parse()
54 .map_err(|_| VpStatsError::ParseLine)?;
55
56 stats.push(HclVpStats { vtl_transitions })
57 }
58 Ok(stats)
59}