uconsole_sleep/hardware/
cpu.rs1use std::path::PathBuf;
3
4use log::debug;
5
6pub const CPU_POLICY_PATH: &str = "/sys/devices/system/cpu/cpufreq/policy0";
7
8#[derive(Clone, Debug)]
9pub struct CpuFreqConfig {
10 pub policy_path: PathBuf,
11 pub default_min: Option<String>,
12 pub default_max: Option<String>,
13 pub saving_min: Option<String>,
14 pub saving_max: Option<String>,
15}
16
17impl CpuFreqConfig {
18 pub fn new(saving_cpu_freq: Option<String>) -> Self {
19 let policy_path = PathBuf::from(CPU_POLICY_PATH);
20 Self::with_policy_path(policy_path, saving_cpu_freq)
21 }
22
23 pub fn with_policy_path(policy_path: PathBuf, saving_cpu_freq: Option<String>) -> Self {
24 let policy_path_clone = policy_path.clone();
25 let default_min = std::fs::read_to_string(policy_path_clone.join("scaling_min_freq"))
26 .ok()
27 .map(|s| s.trim().to_string());
28 let default_max = std::fs::read_to_string(policy_path_clone.join("scaling_max_freq"))
29 .ok()
30 .map(|s| s.trim().to_string());
31
32 let (saving_min, saving_max) = if let Some(s) = saving_cpu_freq {
33 let parts: Vec<&str> = s.split(',').collect();
34 if parts.len() == 2 {
35 let min = format!("{}000", parts[0].trim());
36 let max = format!("{}000", parts[1].trim());
37 (Some(min), Some(max))
38 } else {
39 (None, None)
40 }
41 } else {
42 (None, None)
43 };
44
45 CpuFreqConfig {
46 policy_path,
47 default_min,
48 default_max,
49 saving_min,
50 saving_max,
51 }
52 }
53
54 pub fn apply_saving_mode(&self, dry_run: bool) {
55 if let (Some(min), Some(max)) = (&self.saving_min, &self.saving_max) {
56 if dry_run {
57 debug!(
58 "DRY-RUN: Would write CPU saving mode {}/{} to {}",
59 min,
60 max,
61 self.policy_path.display()
62 );
63 } else {
64 let _ = std::fs::write(self.policy_path.join("scaling_min_freq"), min);
65 let _ = std::fs::write(self.policy_path.join("scaling_max_freq"), max);
66 }
67 debug!("CPU: saving mode {}/{}", min, max);
68 }
69 }
70
71 pub fn apply_normal_mode(&self, dry_run: bool) {
72 if let (Some(min), Some(max)) = (&self.default_min, &self.default_max) {
73 if dry_run {
74 debug!(
75 "DRY-RUN: Would write CPU normal mode {}/{} to {}",
76 min.trim(),
77 max.trim(),
78 self.policy_path.display()
79 );
80 } else {
81 let _ = std::fs::write(self.policy_path.join("scaling_min_freq"), min.trim());
82 let _ = std::fs::write(self.policy_path.join("scaling_max_freq"), max.trim());
83 }
84 debug!("CPU: normal mode {}/{}", min.trim(), max.trim());
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use std::env;
93 use std::fs;
94
95 #[test]
96 fn test_cpu_apply_modes_writes_files() {
97 let tmp = env::temp_dir().join(format!(
98 "uconsole_sleep_test_{}",
99 std::time::SystemTime::now()
100 .duration_since(std::time::UNIX_EPOCH)
101 .unwrap()
102 .as_millis()
103 ));
104 let _ = fs::create_dir_all(&tmp);
105
106 let cpu = CpuFreqConfig::with_policy_path(tmp.clone(), Some(String::from("100,400")));
107 cpu.apply_saving_mode(false);
108 let min = fs::read_to_string(tmp.join("scaling_min_freq")).unwrap();
109 let max = fs::read_to_string(tmp.join("scaling_max_freq")).unwrap();
110 assert_eq!(min, "100000");
111 assert_eq!(max, "400000");
112
113 cpu.apply_normal_mode(false);
114 let min2 = fs::read_to_string(tmp.join("scaling_min_freq")).unwrap();
115 let max2 = fs::read_to_string(tmp.join("scaling_max_freq")).unwrap();
116 assert_eq!(min2.trim(), "100000");
117 assert_eq!(max2.trim(), "400000");
118 }
119}