1#[macro_use]
2extern crate log;
3extern crate serde;
4#[macro_use]
5extern crate serde_derive;
6
7use std::fs;
8use std::io;
9use std::io::{Error, ErrorKind, Write};
10use std::path::PathBuf;
11
12macro_rules! parse_num {
13 ($g:ident, $op:expr) => {{
14 let mut chars = fs::read_to_string($g.join($op))?;
15 chars.retain(|c| c.is_digit(10));
16
17 match chars.parse() {
18 Ok(x) => x,
19 Err(e) => {
20 return Err(io::Error::new(
21 io::ErrorKind::InvalidData,
22 format!("Cause{}", e),
23 ));
24 }
25 }
26 }};
27}
28
29pub fn discover_core_settings() -> io::Result<Vec<Core>> {
31 let cpu_root = fs::read_dir("/sys/devices/system/cpu/")?;
32 debug!("Content of /sys/devices/system/cpu/ {:#?}", cpu_root);
33
34 let is_core = |p: &fs::DirEntry| {
35 let f = p
36 .file_name()
37 .into_string()
38 .expect("Encountered invalid path while discovering core directories");
39 f.contains("cpu") && !(f.contains("cpuidle") || f.contains("cpufreq"))
40 };
41
42 cpu_root
43 .filter_map(|e| e.ok())
45 .filter(|p| is_core(p))
46 .map(|p| p.path())
47 .inspect(|c| debug!("Found core: {:?}", c))
48 .try_fold(Vec::new(), |mut cores, c| {
49 let c = Core::discover(c)?;
50 cores.push(c);
51 Ok(cores)
52 })
53}
54
55#[derive(Clone, Debug, Serialize, Deserialize)]
58pub struct Core {
59 core: PathBuf,
61 num: u32,
63 cpuinfo_max_freq: u32,
65 cpuinfo_min_freq: u32,
67 scaling_available_governors: Vec<String>,
69 scaling_max_freq: u32,
71 scaling_min_freq: u32,
73 scaling_governor: String,
75}
76
77impl Core {
78 pub fn discover(core: PathBuf) -> io::Result<Core> {
80 let g = core.join("cpufreq");
81
82 let cpuinfo_min_freq: u32 = parse_num!(g, "cpuinfo_min_freq");
83 let cpuinfo_max_freq: u32 = parse_num!(g, "cpuinfo_max_freq");
84 let scaling_min_freq: u32 = parse_num!(g, "scaling_min_freq");
85 let scaling_max_freq: u32 = parse_num!(g, "scaling_max_freq");
86 let scaling_governor = {
87 let mut chars = fs::read_to_string(g.join("scaling_governor"))?;
88 chars.retain(|c| !c.is_control());
89 chars
90 };
91
92 let scaling_available_governors = {
93 let mut chars = fs::read_to_string(g.join("scaling_available_governors"))?;
94 chars.retain(|c| !c.is_control());
95 chars.split(&" ").map(|s| s.into()).collect()
96 };
97
98 let num = core
100 .to_str()
101 .expect("Failed to convert PathBuf to String")
102 .rsplit("cpu")
103 .next()
104 .expect("Core name did not contain 'cpu'")
105 .parse()
106 .expect("Failed to parse the u32 core number");
107
108 let c = Core {
109 core,
110 num,
111 cpuinfo_max_freq,
112 cpuinfo_min_freq,
113 scaling_available_governors,
114 scaling_governor,
115 scaling_min_freq,
116 scaling_max_freq,
117 };
118 debug!("Read settings : {:#?}", c);
119
120 Ok(c)
121 }
122
123 pub fn num(&self) -> u32 {
125 self.num
126 }
127
128 pub fn cpu_min(&self) -> u32 {
130 self.cpuinfo_min_freq
131 }
132
133 pub fn cpu_max(&self) -> u32 {
135 self.cpuinfo_max_freq
136 }
137
138 pub fn curr_min(&self) -> u32 {
140 self.scaling_min_freq
141 }
142
143 pub fn curr_max(&self) -> u32 {
145 self.scaling_max_freq
146 }
147
148 pub fn curr_gov(&self) -> &str {
150 self.scaling_governor.as_ref()
151 }
152
153 pub fn available_govs(&self) -> &[String] {
155 self.scaling_available_governors.as_ref()
156 }
157
158 pub fn validate_min(&self, freq: u32) -> io::Result<u32> {
160 if self.cpuinfo_min_freq <= freq && freq <= self.scaling_max_freq {
161 Ok(freq)
162 } else {
163 Err(Error::new(
164 ErrorKind::InvalidInput,
165 format!(
166 "Min Frequency {} not in ({},{}]",
167 freq, self.cpuinfo_min_freq, self.scaling_max_freq
168 ),
169 ))
170 }
171 }
172
173 pub fn validate_max(&self, freq: u32) -> io::Result<u32> {
175 if (self.cpuinfo_min_freq <= freq && self.scaling_min_freq <= freq)
176 && freq <= self.cpuinfo_max_freq
177 {
178 Ok(freq)
179 } else {
180 Err(Error::new(
181 ErrorKind::InvalidInput,
182 format!(
183 "Max Frequency {} not in min({},{})..={}",
184 freq, self.cpuinfo_min_freq, self.scaling_min_freq, self.cpuinfo_max_freq
185 ),
186 ))
187 }
188 }
189
190 pub fn validate_governor<'a>(&self, governor: &'a str) -> io::Result<&'a str> {
192 if self
193 .scaling_available_governors
194 .iter()
195 .any(|g| g.as_str().eq(governor))
196 {
197 Ok(governor)
198 } else {
199 Err(Error::new(
200 ErrorKind::InvalidInput,
201 format!(
202 "Governor {} not available. Must be one of {:?}",
203 governor, self.scaling_available_governors
204 ),
205 ))
206 }
207 }
208
209 pub fn set_min(&mut self, freq: u32) -> io::Result<()> {
213 debug!("Setting minimum scaling frequency {} on {}", freq, self.num);
214 let mut f = fs::OpenOptions::new()
215 .write(true)
216 .open(self.core.join("cpufreq/scaling_min_freq"))?;
217 f.write_all(format!("{}", freq).as_ref())?;
218 Ok(())
219 }
220
221 pub fn set_max(&mut self, freq: u32) -> io::Result<()> {
225 debug!("Setting maximum scaling frequency {} on {}", freq, self.num);
226 let mut f = fs::OpenOptions::new()
227 .write(true)
228 .open(self.core.join("cpufreq/scaling_max_freq"))?;
229 f.write_all(format!("{}", freq).as_ref())?;
230 Ok(())
231 }
232
233 pub fn set_governor(&mut self, guvnor: &str) -> io::Result<()> {
237 debug!("Setting governor {} on {}", guvnor, self.num);
238 fs::OpenOptions::new()
239 .write(true)
240 .read(false)
241 .open(self.core.join("cpufreq/scaling_governor"))
242 .and_then(|mut f| f.write_all(guvnor.as_bytes()))
243 .map(|_| ())
244 }
245}
246
247#[cfg(test)]
248mod test {
249 use io::{ErrorKind, Result};
250 use std::path::PathBuf;
251 use Core;
252
253 #[test]
254 fn freq_validation() {
255 let s = Core {
256 core: PathBuf::from("/sys/devices/system/cpu/cpu0"),
257 num: 0,
258 cpuinfo_min_freq: 800000,
259 cpuinfo_max_freq: 2500000,
260 scaling_available_governors: vec![],
261 scaling_governor: "".into(),
262 scaling_min_freq: 850000,
263 scaling_max_freq: 900000,
264 };
265
266 let check_val = |x, v| match x {
267 Ok(u) => v == u,
268 Err(_) => false,
269 };
270
271 let check_err = |x: Result<u32>| match x {
272 Ok(_) => false,
273 Err(ref e) if e.kind() == ErrorKind::InvalidInput => true,
274 _ => false,
275 };
276
277 assert!(check_val(s.validate_min(800000), 800000));
278 assert!(check_val(s.validate_min(850000), 850000));
279 assert!(check_err(s.validate_min(1000000)));
280
281 assert!(check_val(s.validate_max(1000000), 1000000));
282 assert!(check_err(s.validate_max(8000000)));
283 }
284
285 #[test]
286 fn govnor_validation() {
287 let s = Core {
288 core: PathBuf::from(&"/sys/devices/system/cpu/cpu0"),
289 num: 0,
290 cpuinfo_min_freq: 800000,
291 cpuinfo_max_freq: 2500000,
292 scaling_available_governors: vec!["performance".into(), "powersave".into()],
293 scaling_governor: "powersave".into(),
294 scaling_min_freq: 850000,
295 scaling_max_freq: 900000,
296 };
297
298 assert!(s.validate_governor(&"performance").is_ok());
299 assert!(s.validate_governor(&"conservative").is_err());
300 }
301
302}