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>,
67 pub boost: Option<bool>,
68 pub cpb: Option<bool>,
69 pub cpu_max_freq: Option<u32>,
70 pub cpu_min_freq: Option<u32>,
71 pub cpuinfo_transition_latency: Option<bool>,
72 pub scaling_available_frequencies: Option<Vec<u32>>,
73 pub scaling_available_governors: Option<String>,
74 pub scaling_cur_freq: Option<u32>,
75 pub scaling_driver: Option<String>,
76 pub scaling_governor: Option<String>,
77 pub scaling_max_freq: Option<u32>,
78 pub scaling_min_freq: Option<u32>,
79 pub scaling_setspeed: Option<String>,
80}
81
82impl Policy {
83 pub fn new(policy: OsString) -> Result<Self> {
84 let dir = Path::new(CPU_FREQ_DIR);
85 let tgt = dir.join(policy);
86 if !dir.exists() || !tgt.exists() {
87 return Err(anyhow!("Directory {} does not exists!", dir.display()));
88 }
89
90 let read = |path: &PathBuf, name: &str| read_to_string(path.join(name));
91 let get_bool = |num: Option<u8>| match num {
92 Some(num) => Some(if num != 0 { true } else { false }),
93 None => None,
94 };
95
96 Ok(Self {
97 bios_limit: read(&tgt, "bios_limit")?.trim().parse().ok(),
98 boost: get_bool(read(&tgt, "boost")?.trim().parse().ok()),
99 cpb: get_bool(read(&tgt, "cpb")?.trim().parse().ok()),
100 cpu_max_freq: read(&tgt, "cpu_max_freq")?.trim().parse().ok(),
101 cpu_min_freq: read(&tgt, "cpu_min_freq")?.trim().parse().ok(),
102 cpuinfo_transition_latency: get_bool(
103 read(&tgt, "cpuinfo_transition_latency")?
104 .trim()
105 .parse()
106 .ok(),
107 ),
108 scaling_available_frequencies: Some(
109 read(&tgt, "scaling_available_frequencies")?
110 .split_whitespace()
111 .map(|freq| freq.parse::<u32>().ok())
112 .filter(|freq| freq.is_some())
113 .map(|freq| freq.unwrap())
114 .collect::<Vec<_>>(),
115 ),
116 scaling_available_governors: Some(
117 read(&tgt, "scaling_available_governors")?
118 .trim()
119 .split_whitespace()
120 .map(|gov| gov.to_string())
121 .collect(),
122 ),
123 scaling_cur_freq: read(&tgt, "scaling_cur_freq")?.trim().parse().ok(),
124 scaling_driver: read(&tgt, "scaling_driver").ok(),
125 scaling_governor: read(&tgt, "scaling_governor").ok(),
126 scaling_max_freq: read(&tgt, "scaling_max_freq")?.trim().parse().ok(),
127 scaling_min_freq: read(&tgt, "scaling_min_freq")?.trim().parse().ok(),
128 scaling_setspeed: read(&tgt, "scaling_setspeed").ok(),
129 })
130 }
131}