sysfs/api/cpu.rs
1//! <https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html?highlight=schedutil#policy-interface-in-sysfs>
2use crate::lib::sysfs_attrs;
3
4pub fn count_cpus() -> crate::Result<usize> {
5 use std::fs::DirEntry;
6 let is_cpu_obj = |inode: &DirEntry| {
7 let name = inode.file_name();
8 let name = name.to_string_lossy();
9 name.starts_with("policy") && name["policy".len()..].chars().all(|ch| ch.is_ascii_digit())
10 };
11 let count = std::fs::read_dir("/sys/devices/system/cpu/cpufreq")?
12 .filter(|res| matches!(res, Ok(inode) if is_cpu_obj(inode)))
13 .count();
14 Ok(count)
15}
16
17/// <https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html#policy-interface-in-sysfs>
18#[sysfs_attrs(in "/sys/devices/system/cpu/cpufreq/policy{cpu}")]
19pub mod cpufreq {
20 use crate::lib::sysfs;
21
22 /// List of online CPUs belonging to this policy (i.e. sharing the
23 /// hardware performance scaling interface represented by the policyX
24 /// policy object).
25 #[sysfs]
26 pub fn affected_cpus(cpu: usize) -> Vec<usize> {
27 let read = |text: &str| text.split(' ').map(|int| int.parse().unwrap()).collect();
28 ..
29 }
30
31 /// If the platform firmware (BIOS) tells the OS to apply an upper limit
32 /// to CPU frequencies, that limit will be reported through this
33 /// attribute (if present).
34 ///
35 /// The existence of the limit may be a result of some (often
36 /// unintentional) BIOS settings, restrictions coming from a service
37 /// processor or another BIOS/HW-based mechanisms.
38 ///
39 /// This does not cover ACPI thermal limitations which can be discovered
40 /// through a generic thermal driver.
41 ///
42 /// This attribute is not present if the scaling driver in use does not
43 /// support it.
44 #[sysfs]
45 pub fn bios_limit(cpu: usize) -> usize {
46 let read = |text: &str| text.parse().unwrap();
47 ..
48 }
49
50 /// Current frequency of the CPUs belonging to this policy as obtained
51 /// from the hardware (in KHz).
52 ///
53 /// This is expected to be the frequency the hardware actually runs at.
54 /// If that frequency cannot be determined, this attribute should not be
55 /// present.
56 #[sysfs]
57 pub fn cpuinfo_cur_freq(cpu: usize) -> usize {
58 let read = |text: &str| text.parse().unwrap();
59 ..
60 }
61
62 /// Maximum possible operating frequency the CPUs belonging to this
63 /// policy can run at (in kHz).
64 #[sysfs]
65 pub fn cpuinfo_max_freq(cpu: usize) -> usize {
66 let read = |text: &str| text.parse().unwrap();
67 ..
68 }
69
70 /// Minimum possible operating frequency the CPUs belonging to this
71 /// policy can run at (in kHz).
72 #[sysfs]
73 pub fn cpuinfo_min_freq(cpu: usize) -> usize {
74 let read = |text: &str| text.parse().unwrap();
75 ..
76 }
77
78 /// The time it takes to switch the CPUs belonging to this policy from
79 /// one P-state to another, in nanoseconds.
80 ///
81 /// If unknown or if known to be so high that the scaling driver does
82 /// not work with the ondemand governor, -1 (CPUFREQ_ETERNAL) will be
83 /// returned by reads from this attribute.
84 #[sysfs]
85 pub fn cpuinfo_transition_latency(cpu: usize) -> isize {
86 let read = |text: &str| text.parse().unwrap();
87 ..
88 }
89
90 /// List of all (online and offline) CPUs belonging to this policy.
91 #[sysfs]
92 pub fn related_cpus(cpu: usize) -> Vec<usize> {
93 let read = |text: &str| text.split(' ').map(|int| int.parse().unwrap()).collect();
94 ..
95 }
96
97 /// List of CPUFreq scaling governors present in the kernel that can be
98 /// attached to this policy or (if the intel_pstate scaling driver is in
99 /// use) list of scaling algorithms provided by the driver that can be
100 /// applied to this policy.
101 ///
102 /// [Note that some governors are modular and it may be necessary to
103 /// load a kernel module for the governor held by it to become available
104 /// and be listed by this attribute.]
105 #[sysfs]
106 pub fn scaling_available_governors(cpu: usize) -> Vec<String> {
107 let read = |text: &str| text.split(' ').map(str::to_owned).collect();
108 ..
109 }
110
111 /// Current frequency of all of the CPUs belonging to this policy
112 /// (in kHz).
113 ///
114 /// In the majority of cases, this is the frequency of the last P-state
115 /// requested by the scaling driver from the hardware using the scaling
116 /// interface provided by it, which may or may not reflect the frequency
117 /// the CPU is actually running at (due to hardware design and other
118 /// limitations).
119 ///
120 /// Some architectures (e.g. x86) may attempt to provide information
121 /// more precisely reflecting the current CPU frequency through this
122 /// attribute, but that still may not be the exact current CPU frequency
123 /// as seen by the hardware at the moment.
124 #[sysfs]
125 pub fn scaling_cur_freq(cpu: usize) -> usize {
126 let read = |text: &str| text.parse().unwrap();
127 ..
128 }
129
130 /// The scaling driver currently in use.
131 #[sysfs]
132 pub fn scaling_driver(cpu: usize) -> String {
133 let read = str::to_owned;
134 ..
135 }
136
137 /// The scaling governor currently attached to this policy or (if the
138 /// intel_pstate scaling driver is in use) the scaling algorithm
139 /// provided by the driver that is currently applied to this policy.
140 ///
141 /// This attribute is read-write and writing to it will cause a new
142 /// scaling governor to be attached to this policy or a new scaling
143 /// algorithm provided by the scaling driver to be applied to it (in the
144 /// intel_pstate case), as indicated by the string written to this
145 /// attribute (which must be one of the names listed by the
146 /// scaling_available_governors attribute described above).
147 #[sysfs]
148 pub fn scaling_governor(cpu: usize) -> String {
149 let read = str::to_owned;
150 let write = |gov: &str| gov.to_owned();
151 ..
152 }
153
154 /// Maximum frequency the CPUs belonging to this policy are allowed to
155 /// be running at (in kHz).
156 ///
157 /// This attribute is read-write and writing a string representing an
158 /// integer to it will cause a new limit to be set (it must not be lower
159 /// than the value of the scaling_min_freq attribute).
160 #[sysfs]
161 pub fn scaling_max_freq(cpu: usize) -> usize {
162 let read = |text: &str| text.parse().unwrap();
163 let write = |khz: usize| khz.to_string();
164 ..
165 }
166
167 /// Minimum frequency the CPUs belonging to this policy are allowed to
168 /// be running at (in kHz).
169 ///
170 /// This attribute is read-write and writing a string representing a
171 /// non-negative integer to it will cause a new limit to be set (it must
172 /// not be higher than the value of the scaling_max_freq attribute).
173 #[sysfs]
174 pub fn scaling_min_freq(cpu: usize) -> usize {
175 let read = |text: &str| text.parse().unwrap();
176 let write = |khz: usize| khz.to_string();
177 ..
178 }
179
180 /// This attribute is functional only if the userspace scaling governor
181 /// is attached to the given policy.
182 ///
183 /// It returns the last frequency requested by the governor (in kHz) or
184 /// can be written to in order to set a new frequency for the policy.
185 #[sysfs]
186 pub fn scaling_setspeed(cpu: usize) -> usize {
187 let read = |text: &str| text.parse().unwrap();
188 let write = |khz: usize| khz.to_string();
189 ..
190 }
191}
192
193// Currently the functions in here are all prefixed with `amd_pstate`.
194// The attribute files themselves are all in the `cpufreq` subdirectory.
195//
196// I thought it was best to put them in a separate module,
197// because it is a separate feature that has to be enabled by the kernel
198// parameter `amd_pstate=` as either `active`, `passive`, or `guided`.
199//
200// Because they are now in a separate module, I think it is best to remove the
201// prefix.
202#[sysfs_attrs(in "/sys/devices/system/cpu/cpufreq/policy{cpu}")]
203pub mod amd_pstate {
204 use crate::lib::sysfs;
205
206 /// Maximum CPPC performance and CPU frequency that the driver is allowed to
207 /// set, in percent of the maximum supported CPPC performance level (the
208 /// highest performance supported in AMD CPPC Performance Capability).
209 /// In some ASICs, the highest CPPC performance is not the one in the _CPC
210 /// table, so we need to expose it to sysfs. If boost is not active, but
211 /// still supported, this maximum frequency will be larger than the one in
212 /// cpuinfo. This attribute is read-only.
213 #[sysfs]
214 pub fn amd_pstate_highest_perf(cpu: usize) -> usize {
215 let read = |text: &str| text.parse().unwrap();
216 ..
217 }
218
219 /// See documentation for [`amd_pstate_highest_perf`].
220 #[sysfs]
221 pub fn amd_pstate_max_freq(cpu: usize) -> usize {
222 let read = |text: &str| text.parse().unwrap();
223 ..
224 }
225
226 /// The lowest non-linear CPPC CPU frequency that the driver is allowed to
227 /// set, in percent of the maximum supported CPPC performance level.
228 /// (Please see the lowest non-linear performance in AMD CPPC Performance
229 /// Capability.) This attribute is read-only.
230 #[sysfs]
231 pub fn amd_pstate_lowest_nonlinear_freq(cpu: usize) -> usize {
232 let read = |text: &str| text.parse().unwrap();
233 ..
234 }
235
236 /// A list of all the supported EPP preferences that could be used for
237 /// energy_performance_preference on this system. These profiles represent
238 /// different hints that are provided to the low-level firmware about the
239 /// user's desired energy vs efficiency tradeoff. default represents the epp
240 /// value is set by platform firmware. This attribute is read-only.
241 #[sysfs]
242 pub fn energy_performance_available_preferences(cpu: usize) -> Vec<String> {
243 let read = |text: &str| text.split(' ').map(str::to_owned).collect();
244 ..
245 }
246
247 /// The current energy performance preference can be read from this
248 /// attribute. and user can change current preference according to energy or
249 /// performance needs Please get all support profiles list from
250 /// energy_performance_available_preferences attribute, all the profiles are
251 /// integer values defined between 0 to 255 when EPP feature is enabled by
252 /// platform firmware, if EPP feature is disabled, driver will ignore the
253 /// written value This attribute is read-write.
254 #[sysfs]
255 pub fn energy_performance_preference(cpu: usize) -> String {
256 let read = str::to_owned;
257 let write = |epp: &str| epp.to_owned();
258 ..
259 }
260}
261
262/// <https://www.kernel.org/doc/html/latest/admin-guide/acpi/cppc_sysfs.html>
263#[sysfs_attrs(in "/sys/devices/system/cpu/cpu{cpu}/acpi_cppc")]
264pub mod acpi_cppc {
265 use crate::lib::sysfs;
266
267 /// Highest performance of this processor (abstract scale).
268 #[sysfs]
269 pub fn highest_perf(cpu: usize) -> usize {
270 let read = |text: &str| text.parse().unwrap();
271 ..
272 }
273
274 /// Highest sustained performance of this processor (abstract scale).
275 #[sysfs]
276 pub fn nominal_perf(cpu: usize) -> usize {
277 let read = |text: &str| text.parse().unwrap();
278 ..
279 }
280
281 /// Lowest performance of this processor with nonlinear power savings (abstract scale).
282 #[sysfs]
283 pub fn lowest_nonlinear_perf(cpu: usize) -> usize {
284 let read = |text: &str| text.parse().unwrap();
285 ..
286 }
287
288 /// Lowest performance of this processor (abstract scale).
289 #[sysfs]
290 pub fn lowest_perf(cpu: usize) -> usize {
291 let read = |text: &str| text.parse().unwrap();
292 ..
293 }
294
295 /// CPU frequency corresponding to lowest_perf (in MHz).
296 #[sysfs]
297 pub fn lowest_freq(cpu: usize) -> usize {
298 let read = |text: &str| text.parse().unwrap();
299 ..
300 }
301
302 /// CPU frequency corresponding to nominal_perf (in MHz). The above
303 /// frequencies should only be used to report processor performance in
304 /// frequency instead of abstract scale. These values should not be used
305 /// for any functional decisions.
306 #[sysfs]
307 pub fn nominal_freq(cpu: usize) -> usize {
308 let read = |text: &str| text.parse().unwrap();
309 ..
310 }
311
312 /// Includes both Reference and delivered performance counter. Reference
313 /// counter ticks up proportional to processor's reference performance.
314 /// Delivered counter ticks up proportional to processor's delivered
315 /// performance.
316 #[sysfs]
317 pub fn feedback_ctrs(cpu: usize) -> FeedbackCounters {
318 let read = |text: &str| text.parse().unwrap();
319 ..
320 }
321
322 #[derive(Copy, Clone, Debug)]
323 pub struct FeedbackCounters {
324 pub reference: usize,
325 pub delivered: usize,
326 }
327
328 impl std::str::FromStr for FeedbackCounters {
329 type Err = crate::Error;
330
331 fn from_str(text: &str) -> crate::Result<Self> {
332 let mut reference = None;
333 let mut delivered = None;
334
335 for text in text.split(' ') {
336 if let Some(text) = text.strip_prefix("ref:") {
337 reference = Some(text.parse().unwrap());
338 } else if let Some(text) = text.strip_prefix("del:") {
339 delivered = Some(text.parse().unwrap());
340 } else {
341 todo!("parsing error")
342 }
343 }
344
345 Ok(Self {
346 reference: reference.unwrap(),
347 delivered: delivered.unwrap(),
348 })
349 }
350 }
351
352 /// Minimum time for the feedback counters to wraparound (seconds).
353 #[sysfs]
354 pub fn wraparound_time(cpu: usize) -> usize {
355 let read = |text: &str| text.parse().unwrap();
356 ..
357 }
358
359 /// Performance level at which reference performance counter accumulates
360 /// (abstract scale).
361 #[sysfs]
362 pub fn reference_perf(cpu: usize) -> usize {
363 let read = |text: &str| text.parse().unwrap();
364 ..
365 }
366}