1use crate::{Error, Result};
2
3#[cfg(target_os = "linux")]
5pub fn num_cpus() -> Result<usize> {
6 use std::io::BufRead;
7
8 let f = std::fs::File::open("/proc/cpuinfo")?;
9 let reader = std::io::BufReader::new(f);
10 let lines = reader.lines();
11 let mut count = 0;
12 for line in lines {
13 let line = line?;
14 if line
15 .split(':')
16 .next()
17 .ok_or_else(|| Error::Failed("invalid line".into()))?
18 .trim_end()
19 == "processor"
20 {
21 count += 1;
22 }
23 }
24 Ok(count)
25}
26
27#[cfg(not(target_os = "linux"))]
29pub fn num_cpus() -> Result<usize> {
30 Err(Error::Unimplemented)
31}
32
33pub mod linux {
35 use crate::Result;
36
37 use core::fmt;
38 use std::{collections::BTreeMap, fs};
39 use tracing::warn;
40
41 #[derive(Default)]
56 pub struct SystemConfig {
57 values: BTreeMap<&'static str, String>,
58 prev_values: BTreeMap<&'static str, String>,
59 }
60
61 impl SystemConfig {
62 #[must_use]
64 pub fn new() -> Self {
65 Self::default()
66 }
67 pub fn set<V: fmt::Display>(mut self, key: &'static str, value: V) -> Self {
69 self.values.insert(key, value.to_string());
70 self
71 }
72 pub fn apply(mut self) -> Result<SystemConfigGuard> {
74 for (key, value) in &self.values {
75 let fname = format!("/proc/sys/{}", key);
76 let prev_value = fs::read_to_string(&fname)?;
77 self.prev_values.insert(key, prev_value);
78 fs::write(fname, value)?;
79 }
80 Ok(SystemConfigGuard { config: self })
81 }
82 }
83
84 #[derive(Default)]
86 pub struct SystemConfigGuard {
87 config: SystemConfig,
88 }
89
90 impl Drop for SystemConfigGuard {
91 fn drop(&mut self) {
92 for (key, value) in &self.config.prev_values {
93 if let Err(error) = fs::write(format!("/proc/sys/{}", key), value) {
94 warn!(key, value, %error, "Failed to restore system config");
95 }
96 }
97 }
98 }
99
100 #[derive(Default)]
102 pub struct CpuGovernor {
103 prev_governor: BTreeMap<usize, String>,
104 }
105
106 impl CpuGovernor {
107 pub fn performance<I>(performance_cpus: I) -> Result<CpuGovernor>
112 where
113 I: IntoIterator<Item = usize>,
114 {
115 let mut prev_governor = BTreeMap::new();
116 for cpu in performance_cpus {
117 let fname = format!(
118 "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_governor",
119 cpu
120 );
121 let prev_value = fs::read_to_string(fname)?;
122 prev_governor.insert(cpu, prev_value.trim().to_string());
123 }
124 for cpu in prev_governor.keys() {
125 let fname = format!(
126 "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_governor",
127 cpu
128 );
129 fs::write(fname, "performance")?;
130 }
131 Ok(CpuGovernor { prev_governor })
132 }
133 }
134
135 impl Drop for CpuGovernor {
136 fn drop(&mut self) {
137 for (cpu, governor) in &self.prev_governor {
138 if let Err(error) = fs::write(
139 format!(
140 "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_governor",
141 cpu
142 ),
143 governor,
144 ) {
145 warn!(cpu, %error, "Failed to restore governor");
146 }
147 }
148 }
149 }
150}