cpu_freq/
lib.rs

1//! A crate to obtain CPU frequency information
2//!
3//! The crates attempts to obtain the information with as little permissions as
4//! possible, in the fastest way possible, while still returning a result.
5//!
6//! ## Examples
7//!
8//! Fetch CPU frequency
9//!
10//! ```
11//! let cpus = cpu_freq::get();
12//! ```
13#[derive(Clone, Debug)]
14/// Struct for CPU frequencies, you can get the current frequency as well as the
15/// minimum and maximum values available. When a value is not available it return None
16pub struct CpuFreqs {
17    pub min: Option<f32>,
18    pub max: Option<f32>,
19    pub cur: Option<f32>,
20}
21
22/// Returns cpu frequency
23pub fn get() -> Vec<CpuFreqs> {
24    get_cpu_freqs()
25}
26
27#[cfg(target_os = "linux")]
28/// Return CPU frequency on Linux system. First
29fn get_cpu_freqs() -> Vec<CpuFreqs> {
30    use std::fs;
31    use std::path::Path;
32
33    fn get_path(num: usize) -> Option<String> {
34        let policy_path = format!("/sys/devices/system/cpu/cpufreq/policy{}", num);
35        let cpu_path = format!("/sys/devices/system/cpu/cpu{}/cpufreq", num);
36        let base_path = match (
37            Path::new(&policy_path).exists(),
38            Path::new(&cpu_path).exists(),
39        ) {
40            (true, true) => Some(cpu_path),
41            (true, false) => Some(policy_path),
42            (false, true) => Some(cpu_path),
43            (false, false) => None,
44        };
45        base_path
46    }
47
48    fn get_measurement(cpu: usize, measurement_file: &str) -> Option<f32> {
49        let base_path = get_path(cpu);
50        match base_path {
51            Some(path) => {
52                let val_ = fs::read_to_string(Path::new(&path).join(measurement_file));
53                let val = match val_ {
54                    Ok(val) => Some(val.trim().parse::<f32>().unwrap() / 1000.0),
55                    Err(_) => None,
56                };
57                val
58            }
59            None => None,
60        }
61    }
62
63    let mut res: Vec<CpuFreqs> = vec![];
64    let num_cpus = num_cpus::get();
65    if Path::new("/sys/devices/system/cpu/cpufreq").exists()
66        || Path::new("/sys/devices/system/cpu/cpu0/cpufreq").exists()
67    {
68        for cpu in 0..num_cpus {
69            let min = get_measurement(cpu, "scaling_min_freq");
70            let max = get_measurement(cpu, "scaling_max_freq");
71            let cur = get_measurement(cpu, "scaling_cur_freq");
72            let r = CpuFreqs {
73                min: min,
74                max: max,
75                cur: cur,
76            };
77            res.push(r);
78        }
79    } else {
80        // Read from /proc/cpuinfo
81        let data = fs::read_to_string("/proc/cpuinfo");
82        match data {
83            Ok(data) => {
84                for line in data.lines() {
85                    if line.to_lowercase().starts_with("cpu mhz") {
86                        let fields: Vec<&str> = line.split_whitespace().collect();
87                        // Expect 4 tokens - 'cpu', 'mhz', ':', <val>
88                        let cur = Some(fields[3].parse::<f32>().unwrap());
89                        res.push(CpuFreqs {
90                            cur: cur,
91                            min: None,
92                            max: None,
93                        })
94                    }
95                }
96            }
97            Err(_) => (),
98        }
99    }
100    res
101}
102
103#[cfg(not(target_os = "linux"))]
104fn get_cpu_freqs() -> Vec<CpuFreqs> {
105    unimplemented!("cpu-freq is not yet supported on this system")
106}
107
108#[cfg(test)]
109mod tests {
110    use super::get;
111
112    #[test]
113    fn test_cpu_freq() {
114        get().iter().for_each(|x| assert!(x.cur > Some(0.0)));
115    }
116}