scx_utils/
energy_model.rs1use crate::Cpumask;
15use crate::compat;
16use crate::misc::read_from_file;
17use anyhow::Result;
18use anyhow::bail;
19use glob::glob;
20use std::collections::BTreeMap;
21use std::fmt;
22use std::path::Path;
23use std::sync::Arc;
24
25#[derive(Debug)]
26pub struct PerfState {
27 pub cost: usize,
28 pub frequency: usize,
29 pub inefficient: usize,
30 pub performance: usize,
31 pub power: usize,
32}
33
34#[derive(Debug)]
35pub struct PerfDomain {
36 pub id: usize,
38 pub span: Cpumask,
40 pub perf_table: BTreeMap<usize, Arc<PerfState>>,
42}
43
44#[derive(Debug)]
45pub struct EnergyModel {
46 pub perf_doms: BTreeMap<usize, Arc<PerfDomain>>,
48}
49
50impl EnergyModel {
51 pub fn new() -> Result<EnergyModel> {
53 let mut perf_doms = BTreeMap::new();
54 let pd_paths = match get_pd_paths() {
55 Ok(pd_paths) => pd_paths,
56 Err(_) => {
57 bail!("Fail to locate the energy model directory");
58 }
59 };
60
61 for (pd_id, pd_path) in pd_paths {
62 let pd = PerfDomain::new(pd_id, pd_path).unwrap();
63 perf_doms.insert(pd.id, pd.into());
64 }
65
66 Ok(EnergyModel { perf_doms })
67 }
68
69 pub fn get_pd(&self, cpu_id: usize) -> Option<&PerfDomain> {
70 for (_, pd) in self.perf_doms.iter() {
71 if pd.span.test_cpu(cpu_id) {
72 return Some(&pd);
73 }
74 }
75 None
76 }
77}
78
79impl PerfDomain {
80 pub fn new(id: usize, root: String) -> Result<PerfDomain> {
82 let mut perf_table = BTreeMap::new();
83 let cpulist = std::fs::read_to_string(root.clone() + "/cpus")?;
84 let span = Cpumask::from_cpulist(&cpulist)?;
85
86 for ps_path in get_ps_paths(root).unwrap() {
87 let ps = PerfState::new(ps_path).unwrap();
88 perf_table.insert(ps.performance, ps.into());
89 }
90
91 Ok(PerfDomain {
92 id,
93 span,
94 perf_table,
95 })
96 }
97}
98
99impl PerfState {
100 pub fn new(root: String) -> Result<PerfState> {
102 let cost = read_from_file(Path::new(&(root.clone() + "/cost")))?;
103 let frequency = read_from_file(Path::new(&(root.clone() + "/frequency")))?;
104 let inefficient = read_from_file(Path::new(&(root.clone() + "/inefficient")))?;
105 let performance = read_from_file(Path::new(&(root.clone() + "/performance")))?;
106 let power = read_from_file(Path::new(&(root.clone() + "/power")))?;
107
108 Ok(PerfState {
109 cost,
110 frequency,
111 inefficient,
112 performance,
113 power,
114 })
115 }
116}
117
118impl fmt::Display for EnergyModel {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 for (_, pd) in self.perf_doms.iter() {
121 writeln!(f, "{:#}", pd)?;
122 }
123 Ok(())
124 }
125}
126
127impl fmt::Display for PerfDomain {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 writeln!(f, "# perf domain: {:#}, cpus: {:#}", self.id, self.span)?;
130 writeln!(f, "cost, frequency, inefficient, performance, power")?;
131 for (_, ps) in self.perf_table.iter() {
132 writeln!(f, "{:#}", ps)?;
133 }
134 Ok(())
135 }
136}
137
138impl fmt::Display for PerfState {
139 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 write!(
141 f,
142 "{}, {}, {}, {}, {}",
143 self.cost, self.frequency, self.inefficient, self.performance, self.power
144 )?;
145 Ok(())
146 }
147}
148
149fn get_ps_paths(root: String) -> Result<Vec<String>> {
153 let ps_paths = glob(&(root.clone() + "/ps:[0-9]*"))?;
154 let mut ps_vec = vec![];
155 for ps_path in ps_paths.filter_map(Result::ok) {
156 let ps_str = ps_path.into_os_string().into_string().unwrap();
157 ps_vec.push(ps_str);
158 }
159
160 Ok(ps_vec)
161}
162
163fn get_pd_paths() -> Result<Vec<(usize, String)>> {
164 let prefix = get_em_root().unwrap() + "/cpu";
165 let pd_paths = glob(&(prefix.clone() + "[0-9]*"))?;
166
167 let mut pd_vec = vec![];
168 for pd_path in pd_paths.filter_map(Result::ok) {
169 let pd_str = pd_path.into_os_string().into_string().unwrap();
170 let pd_id: usize = pd_str[prefix.len()..].parse().unwrap();
171 pd_vec.push((pd_id, pd_str));
172 }
173 if pd_vec.is_empty() {
174 bail!("There is no performance domain.");
175 }
176 pd_vec.sort();
177
178 let mut pd_vec2 = vec![];
179 for (id, (_, pd_str)) in pd_vec.into_iter().enumerate() {
180 pd_vec2.push((id, pd_str));
181 }
182
183 Ok(pd_vec2)
184}
185
186fn get_em_root() -> Result<String> {
187 let root = compat::debugfs_mount().unwrap().join("energy_model");
188 Ok(root.display().to_string())
189}