cbtop/frequency_control/
info.rs1use super::governor::CpuGovernor;
2use super::sysfs::{read_sysfs_string, read_sysfs_value};
3
4#[derive(Debug, Clone)]
6pub struct CpuFrequencyInfo {
7 pub cpu_id: usize,
9 pub current_khz: u64,
11 pub min_khz: u64,
13 pub max_khz: u64,
15 pub governor: CpuGovernor,
17 pub available_governors: Vec<CpuGovernor>,
19}
20
21impl CpuFrequencyInfo {
22 fn khz_to_mhz(khz: u64) -> f64 {
24 khz as f64 / 1_000.0
25 }
26
27 pub fn current_mhz(&self) -> f64 {
29 Self::khz_to_mhz(self.current_khz)
30 }
31
32 pub fn current_ghz(&self) -> f64 {
34 Self::khz_to_mhz(self.current_khz) / 1_000.0
35 }
36
37 pub fn utilization(&self) -> f64 {
39 if self.max_khz > 0 {
40 self.current_khz as f64 / self.max_khz as f64
41 } else {
42 1.0
43 }
44 }
45
46 pub(crate) fn mock(cpu_id: usize, frequency_khz: u64, governor: CpuGovernor) -> Self {
48 Self {
49 cpu_id,
50 current_khz: frequency_khz,
51 min_khz: 800_000,
52 max_khz: 4_000_000,
53 governor,
54 available_governors: vec![CpuGovernor::Performance, CpuGovernor::Powersave],
55 }
56 }
57
58 pub(crate) fn from_sysfs(cpu_id: usize, sysfs_path: &std::path::Path) -> Self {
60 let cpu_path = sysfs_path.join(format!("cpu{cpu_id}/cpufreq"));
61
62 let read_khz = |name: &str| read_sysfs_value(&cpu_path.join(name)).unwrap_or(0);
63
64 let governor = read_sysfs_string(&cpu_path.join("scaling_governor"))
65 .map(|s| CpuGovernor::parse(&s))
66 .unwrap_or(CpuGovernor::Unknown);
67
68 let available_governors: Vec<CpuGovernor> =
69 read_sysfs_string(&cpu_path.join("scaling_available_governors"))
70 .unwrap_or_default()
71 .split_whitespace()
72 .map(CpuGovernor::parse)
73 .collect();
74
75 Self {
76 cpu_id,
77 current_khz: read_khz("scaling_cur_freq"),
78 min_khz: read_khz("scaling_min_freq"),
79 max_khz: read_khz("scaling_max_freq"),
80 governor,
81 available_governors,
82 }
83 }
84}