1use anyhow::{Result, anyhow};
24use serde::{Deserialize, Serialize};
25use std::{
26 ffi::OsString,
27 fs::{read_dir, read_to_string},
28 path::{Path, PathBuf},
29};
30
31use crate::traits::ToJson;
32
33#[derive(Debug, Deserialize, Serialize, Clone)]
34pub struct CpuFreq {
35 pub policy: Vec<Policy>,
36 pub boost: Option<bool>,
37}
38
39const CPU_FREQ_DIR: &str = "/sys/devices/system/cpu/cpufreq/";
40
41impl CpuFreq {
42 pub fn new() -> Result<Self> {
43 let pth = Path::new(CPU_FREQ_DIR);
44 let boost = match read_to_string(pth.join("boost")).ok() {
45 Some(boost) => Some(&boost == "1"),
46 None => None,
47 };
48
49 let mut policy = Vec::new();
50 for dir in read_dir(CPU_FREQ_DIR)? {
51 let dir = dir?;
52 let fname = dir.file_name();
53 if fname.to_string_lossy().contains("policy") {
54 policy.push(Policy::new(fname)?);
55 }
56 }
57
58 Ok(Self { policy, boost })
59 }
60}
61
62impl ToJson for CpuFreq {}
63
64#[derive(Debug, Deserialize, Serialize, Default, Clone)]
65pub struct Policy {
66 pub bios_limit: Option<u32>,
68
69 pub cpb: Option<bool>,
71
72 pub cpu_max_freq: Option<u32>,
74
75 pub cpu_min_freq: Option<u32>,
77
78 pub cpuinfo_transition_latency: Option<bool>,
80
81 pub scaling_available_frequencies: Option<Vec<u32>>,
83
84 pub scaling_available_governors: Option<Vec<String>>,
86
87 pub scaling_cur_freq: Option<u32>,
89
90 pub scaling_driver: Option<String>,
92
93 pub scaling_governor: Option<String>,
95
96 pub scaling_max_freq: Option<u32>,
97 pub scaling_min_freq: Option<u32>,
98 pub scaling_setspeed: Option<String>,
99}
100
101impl Policy {
102 pub fn new(policy: OsString) -> Result<Self> {
103 let dir = Path::new(CPU_FREQ_DIR);
104 let tgt = dir.join(policy);
105 if !dir.exists() || !tgt.exists() {
106 return Err(anyhow!("Directory {} does not exists!", dir.display()));
107 }
108
109 let read = |path: &PathBuf, name: &str| read_to_string(path.join(name));
110 let get_bool = |num: Option<u8>| match num {
111 Some(num) => Some(if num != 0 { true } else { false }),
112 None => None,
113 };
114
115 Ok(Self {
116 bios_limit: read(&tgt, "bios_limit")?.trim().parse().ok(),
117 cpb: get_bool(read(&tgt, "cpb")?.trim().parse().ok()),
118 cpu_max_freq: read(&tgt, "cpuinfo_max_freq")?.trim().parse().ok(),
119 cpu_min_freq: read(&tgt, "cpuinfo_min_freq")?.trim().parse().ok(),
120 cpuinfo_transition_latency: get_bool(
121 read(&tgt, "cpuinfo_transition_latency")?
122 .trim()
123 .parse()
124 .ok(),
125 ),
126 scaling_available_frequencies: Some(
127 read(&tgt, "scaling_available_frequencies")?
128 .split_whitespace()
129 .map(|freq| freq.parse::<u32>().ok())
130 .filter(|freq| freq.is_some())
131 .map(|freq| freq.unwrap())
132 .collect::<Vec<_>>(),
133 ),
134 scaling_available_governors: Some(
135 read(&tgt, "scaling_available_governors")?
136 .trim()
137 .split_whitespace()
138 .map(|gov| gov.to_string())
139 .collect(),
140 ),
141 scaling_cur_freq: read(&tgt, "scaling_cur_freq")?.trim().parse().ok(),
142 scaling_driver: read(&tgt, "scaling_driver")
143 .ok()
144 .and_then(|s| Some(s.trim().to_string())),
145 scaling_governor: read(&tgt, "scaling_governor")
146 .ok()
147 .and_then(|s| Some(s.trim().to_string())),
148 scaling_max_freq: read(&tgt, "scaling_max_freq")?.trim().parse().ok(),
149 scaling_min_freq: read(&tgt, "scaling_min_freq")?.trim().parse().ok(),
150 scaling_setspeed: read(&tgt, "scaling_setspeed")
151 .ok()
152 .and_then(|s| Some(s.trim().to_string())),
153 })
154 }
155}