cbtop/frequency_control/
controller.rs1use std::path::PathBuf;
2
3use super::governor::CpuGovernor;
4use super::info::CpuFrequencyInfo;
5use super::reading::FrequencyReading;
6use super::variance::FrequencyVariance;
7
8#[derive(Debug)]
10pub struct FrequencyController {
11 pub(crate) sysfs_path: PathBuf,
13 cpu_count: usize,
15 pub(crate) mock_mode: bool,
17 mock_frequency: u64,
19 mock_governor: CpuGovernor,
21}
22
23impl Default for FrequencyController {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl FrequencyController {
30 pub fn new() -> Self {
32 let cpu_count = super::num_cpus();
33 Self {
34 sysfs_path: PathBuf::from("/sys/devices/system/cpu"),
35 cpu_count,
36 mock_mode: false,
37 mock_frequency: 3_000_000, mock_governor: CpuGovernor::Performance,
39 }
40 }
41
42 pub fn with_mock(mut self, frequency_khz: u64, governor: CpuGovernor) -> Self {
44 self.mock_mode = true;
45 self.mock_frequency = frequency_khz;
46 self.mock_governor = governor;
47 self
48 }
49
50 pub fn cpu_count(&self) -> usize {
52 self.cpu_count
53 }
54
55 pub fn read_cpu_frequency(&self, cpu_id: usize) -> Option<CpuFrequencyInfo> {
57 Some(if self.mock_mode {
58 CpuFrequencyInfo::mock(cpu_id, self.mock_frequency, self.mock_governor)
59 } else {
60 CpuFrequencyInfo::from_sysfs(cpu_id, &self.sysfs_path)
61 })
62 }
63
64 pub fn read_all_frequencies(&self) -> FrequencyReading {
66 let timestamp_ns = std::time::SystemTime::now()
67 .duration_since(std::time::UNIX_EPOCH)
68 .map(|d| d.as_nanos() as u64)
69 .unwrap_or(0);
70
71 let cpus: Vec<CpuFrequencyInfo> = (0..self.cpu_count)
72 .filter_map(|id| self.read_cpu_frequency(id))
73 .collect();
74
75 FrequencyReading { cpus, timestamp_ns }
76 }
77
78 pub fn detect_governor(&self) -> CpuGovernor {
80 self.read_all_frequencies().common_governor()
81 }
82
83 pub fn can_control(&self) -> bool {
85 if self.mock_mode {
86 return true;
87 }
88
89 let reading = self.read_all_frequencies();
90 if reading.cpus.is_empty() {
91 return false;
92 }
93
94 let govs = &reading.cpus[0].available_governors;
95 govs.contains(&CpuGovernor::Userspace) || govs.contains(&CpuGovernor::Performance)
96 }
97
98 pub fn measure_variance(&self, samples: usize, interval_ms: u64) -> FrequencyVariance {
100 let mut readings = Vec::with_capacity(samples);
101 for _ in 0..samples {
102 readings.push(self.read_all_frequencies().average_mhz());
103 std::thread::sleep(std::time::Duration::from_millis(interval_ms));
104 }
105 FrequencyVariance::from_samples(&readings)
106 }
107}