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}