mirror of
https://github.com/RGBCube/watt
synced 2025-08-02 19:07:47 +00:00
Compare commits
3 commits
dfa788009c
...
24fa53914d
Author | SHA1 | Date | |
---|---|---|---|
24fa53914d | |||
3212bc0ad5 | |||
c1a509328b |
5 changed files with 194 additions and 151 deletions
|
@ -50,7 +50,7 @@ pub struct CpuDelta {
|
||||||
|
|
||||||
impl CpuDelta {
|
impl CpuDelta {
|
||||||
pub fn apply(&self) -> anyhow::Result<()> {
|
pub fn apply(&self) -> anyhow::Result<()> {
|
||||||
let cpus = match &self.for_ {
|
let mut cpus = match &self.for_ {
|
||||||
Some(numbers) => {
|
Some(numbers) => {
|
||||||
let mut cpus = Vec::with_capacity(numbers.len());
|
let mut cpus = Vec::with_capacity(numbers.len());
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ impl CpuDelta {
|
||||||
None => cpu::Cpu::all().context("failed to get all CPUs and their information")?,
|
None => cpu::Cpu::all().context("failed to get all CPUs and their information")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
for cpu in cpus {
|
for cpu in &mut cpus {
|
||||||
if let Some(governor) = self.governor.as_ref() {
|
if let Some(governor) = self.governor.as_ref() {
|
||||||
cpu.set_governor(governor)?;
|
cpu.set_governor(governor)?;
|
||||||
}
|
}
|
||||||
|
@ -77,11 +77,11 @@ impl CpuDelta {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mhz_minimum) = self.frequency_mhz_minimum {
|
if let Some(mhz_minimum) = self.frequency_mhz_minimum {
|
||||||
cpu.set_frequency_minimum(mhz_minimum)?;
|
cpu.set_frequency_mhz_minimum(mhz_minimum)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mhz_maximum) = self.frequency_mhz_maximum {
|
if let Some(mhz_maximum) = self.frequency_mhz_maximum {
|
||||||
cpu.set_frequency_maximum(mhz_maximum)?;
|
cpu.set_frequency_mhz_maximum(mhz_maximum)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,12 @@ pub struct SystemInfo {
|
||||||
pub struct CpuCoreInfo {
|
pub struct CpuCoreInfo {
|
||||||
// Per-core data
|
// Per-core data
|
||||||
pub core_id: u32,
|
pub core_id: u32,
|
||||||
pub current_frequency_mhz: Option<u32>,
|
|
||||||
pub min_frequency_mhz: Option<u32>,
|
|
||||||
pub max_frequency_mhz: Option<u32>,
|
|
||||||
pub usage_percent: Option<f32>,
|
pub usage_percent: Option<f32>,
|
||||||
pub temperature_celsius: Option<f32>,
|
pub temperature_celsius: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CpuGlobalInfo {
|
pub struct CpuGlobalInfo {
|
||||||
// System-wide CPU settings
|
// System-wide CPU settings
|
||||||
pub current_governor: Option<String>,
|
|
||||||
pub available_governors: Vec<String>,
|
|
||||||
pub turbo_status: Option<bool>, // true for enabled, false for disabled
|
pub turbo_status: Option<bool>, // true for enabled, false for disabled
|
||||||
pub epp: Option<String>, // Energy Performance Preference
|
pub epp: Option<String>, // Energy Performance Preference
|
||||||
pub epb: Option<String>, // Energy Performance Bias
|
pub epb: Option<String>, // Energy Performance Bias
|
||||||
|
|
251
src/cpu.rs
251
src/cpu.rs
|
@ -11,6 +11,19 @@ pub struct Cpu {
|
||||||
|
|
||||||
pub has_cpufreq: bool,
|
pub has_cpufreq: bool,
|
||||||
|
|
||||||
|
pub available_governors: Vec<String>,
|
||||||
|
pub governor: Option<String>,
|
||||||
|
|
||||||
|
pub frequency_mhz: Option<u64>,
|
||||||
|
pub frequency_mhz_minimum: Option<u64>,
|
||||||
|
pub frequency_mhz_maximum: Option<u64>,
|
||||||
|
|
||||||
|
pub available_epps: Vec<String>,
|
||||||
|
pub epp: Option<String>,
|
||||||
|
|
||||||
|
pub available_epbs: Vec<String>,
|
||||||
|
pub epb: Option<String>,
|
||||||
|
|
||||||
pub time_user: u64,
|
pub time_user: u64,
|
||||||
pub time_nice: u64,
|
pub time_nice: u64,
|
||||||
pub time_system: u64,
|
pub time_system: u64,
|
||||||
|
@ -52,6 +65,19 @@ impl Cpu {
|
||||||
number,
|
number,
|
||||||
has_cpufreq: false,
|
has_cpufreq: false,
|
||||||
|
|
||||||
|
available_governors: Vec::new(),
|
||||||
|
governor: None,
|
||||||
|
|
||||||
|
frequency_mhz: None,
|
||||||
|
frequency_mhz_minimum: None,
|
||||||
|
frequency_mhz_maximum: None,
|
||||||
|
|
||||||
|
available_epps: Vec::new(),
|
||||||
|
epp: None,
|
||||||
|
|
||||||
|
available_epbs: Vec::new(),
|
||||||
|
epb: None,
|
||||||
|
|
||||||
time_user: 0,
|
time_user: 0,
|
||||||
time_nice: 0,
|
time_nice: 0,
|
||||||
time_system: 0,
|
time_system: 0,
|
||||||
|
@ -116,6 +142,13 @@ impl Cpu {
|
||||||
|
|
||||||
self.rescan_times()?;
|
self.rescan_times()?;
|
||||||
|
|
||||||
|
if self.has_cpufreq {
|
||||||
|
self.rescan_governor()?;
|
||||||
|
self.rescan_frequency()?;
|
||||||
|
self.rescan_epp()?;
|
||||||
|
self.rescan_epb()?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,25 +213,134 @@ impl Cpu {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_available_governors(&self) -> Vec<String> {
|
fn rescan_governor(&mut self) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self { number, .. } = *self;
|
||||||
|
|
||||||
|
self.available_governors = 'available_governors: {
|
||||||
let Some(Ok(content)) = fs::read(format!(
|
let Some(Ok(content)) = fs::read(format!(
|
||||||
"/sys/devices/system/cpu/cpu{number}/cpufreq/scaling_available_governors"
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/scaling_available_governors"
|
||||||
)) else {
|
)) else {
|
||||||
return Vec::new();
|
break 'available_governors Vec::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
content
|
content
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.map(ToString::to_string)
|
.map(ToString::to_string)
|
||||||
.collect()
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.governor = Some(
|
||||||
|
fs::read(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/scaling_governor"
|
||||||
|
))
|
||||||
|
.with_context(|| format!("failed to find {self} scaling governor"))?
|
||||||
|
.with_context(|| format!("failed to read {self} scaling governor"))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_governor(&self, governor: &str) -> anyhow::Result<()> {
|
fn rescan_frequency(&mut self) -> anyhow::Result<()> {
|
||||||
|
let Self { number, .. } = *self;
|
||||||
|
|
||||||
|
let frequency_khz = fs::read_u64(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/scaling_cur_freq"
|
||||||
|
))
|
||||||
|
.with_context(|| format!("failed to find {self} frequency"))?
|
||||||
|
.with_context(|| format!("failed to parse {self} frequency"))?;
|
||||||
|
let frequency_khz_minimum = fs::read_u64(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/scaling_min_freq"
|
||||||
|
))
|
||||||
|
.with_context(|| format!("failed to find {self} frequency minimum"))?
|
||||||
|
.with_context(|| format!("failed to parse {self} frequency"))?;
|
||||||
|
let frequency_khz_maximum = fs::read_u64(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/scaling_max_freq"
|
||||||
|
))
|
||||||
|
.with_context(|| format!("failed to find {self} frequency maximum"))?
|
||||||
|
.with_context(|| format!("failed to parse {self} frequency"))?;
|
||||||
|
|
||||||
|
self.frequency_mhz = Some(frequency_khz / 1000);
|
||||||
|
self.frequency_mhz_minimum = Some(frequency_khz_minimum / 1000);
|
||||||
|
self.frequency_mhz_maximum = Some(frequency_khz_maximum / 1000);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rescan_epp(&mut self) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self { number, .. } = self;
|
||||||
|
|
||||||
let governors = self.get_available_governors();
|
self.available_epps = 'available_epps: {
|
||||||
|
let Some(Ok(content)) = fs::read(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/energy_performance_available_preferences"
|
||||||
|
)) else {
|
||||||
|
break 'available_epps Vec::new();
|
||||||
|
};
|
||||||
|
|
||||||
|
content
|
||||||
|
.split_whitespace()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.epp = Some(
|
||||||
|
fs::read(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/energy_performance_preference"
|
||||||
|
))
|
||||||
|
.with_context(|| format!("failed to find {self} EPP"))?
|
||||||
|
.with_context(|| format!("failed to read {self} EPP"))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rescan_epb(&mut self) -> anyhow::Result<()> {
|
||||||
|
let Self { number, .. } = self;
|
||||||
|
|
||||||
|
self.available_epbs = if self.has_cpufreq {
|
||||||
|
vec![
|
||||||
|
"1".to_owned(),
|
||||||
|
"2".to_owned(),
|
||||||
|
"3".to_owned(),
|
||||||
|
"4".to_owned(),
|
||||||
|
"5".to_owned(),
|
||||||
|
"6".to_owned(),
|
||||||
|
"7".to_owned(),
|
||||||
|
"8".to_owned(),
|
||||||
|
"9".to_owned(),
|
||||||
|
"10".to_owned(),
|
||||||
|
"11".to_owned(),
|
||||||
|
"12".to_owned(),
|
||||||
|
"13".to_owned(),
|
||||||
|
"14".to_owned(),
|
||||||
|
"15".to_owned(),
|
||||||
|
"performance".to_owned(),
|
||||||
|
"balance-performance".to_owned(),
|
||||||
|
"balance_performance".to_owned(), // Alternative form with underscore.
|
||||||
|
"balance-power".to_owned(),
|
||||||
|
"balance_power".to_owned(), // Alternative form with underscore.
|
||||||
|
"power".to_owned(),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.epb = Some(
|
||||||
|
fs::read(format!(
|
||||||
|
"/sys/devices/system/cpu/cpu{number}/cpufreq/energy_performance_bias"
|
||||||
|
))
|
||||||
|
.with_context(|| format!("failed to find {self} EPB"))?
|
||||||
|
.with_context(|| format!("failed to read {self} EPB"))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_governor(&mut self, governor: &str) -> anyhow::Result<()> {
|
||||||
|
let Self {
|
||||||
|
number,
|
||||||
|
available_governors: ref governors,
|
||||||
|
..
|
||||||
|
} = *self;
|
||||||
|
|
||||||
if !governors
|
if !governors
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -218,28 +360,19 @@ impl Cpu {
|
||||||
format!(
|
format!(
|
||||||
"this probably means that {self} doesn't exist or doesn't support changing governors"
|
"this probably means that {self} doesn't exist or doesn't support changing governors"
|
||||||
)
|
)
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
self.governor = Some(governor.to_owned());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_available_epps(&self) -> Vec<String> {
|
pub fn set_epp(&mut self, epp: &str) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self {
|
||||||
|
number,
|
||||||
let Some(Ok(content)) = fs::read(format!(
|
available_epps: ref epps,
|
||||||
"/sys/devices/system/cpu/cpu{number}/cpufreq/energy_performance_available_preferences"
|
..
|
||||||
)) else {
|
} = *self;
|
||||||
return Vec::new();
|
|
||||||
};
|
|
||||||
|
|
||||||
content
|
|
||||||
.split_whitespace()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_epp(&self, epp: &str) -> anyhow::Result<()> {
|
|
||||||
let Self { number, .. } = self;
|
|
||||||
|
|
||||||
let epps = self.get_available_epps();
|
|
||||||
|
|
||||||
if !epps.iter().any(|avail_epp| avail_epp == epp) {
|
if !epps.iter().any(|avail_epp| avail_epp == epp) {
|
||||||
bail!(
|
bail!(
|
||||||
|
@ -257,42 +390,14 @@ impl Cpu {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_available_epbs(&self) -> &'static [&'static str] {
|
|
||||||
if !self.has_cpufreq {
|
|
||||||
return &[];
|
|
||||||
}
|
|
||||||
|
|
||||||
&[
|
|
||||||
"1",
|
|
||||||
"2",
|
|
||||||
"3",
|
|
||||||
"4",
|
|
||||||
"5",
|
|
||||||
"6",
|
|
||||||
"7",
|
|
||||||
"8",
|
|
||||||
"9",
|
|
||||||
"10",
|
|
||||||
"11",
|
|
||||||
"12",
|
|
||||||
"13",
|
|
||||||
"14",
|
|
||||||
"15",
|
|
||||||
"performance",
|
|
||||||
"balance-performance",
|
|
||||||
"balance_performance", // Alternative form with underscore.
|
|
||||||
"balance-power",
|
|
||||||
"balance_power", // Alternative form with underscore.
|
|
||||||
"power",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_epb(&self, epb: &str) -> anyhow::Result<()> {
|
pub fn set_epb(&self, epb: &str) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self {
|
||||||
|
number,
|
||||||
|
available_epbs: ref epbs,
|
||||||
|
..
|
||||||
|
} = *self;
|
||||||
|
|
||||||
let epbs = self.get_available_epbs();
|
if !epbs.iter().any(|avail_epb| avail_epb == epb) {
|
||||||
|
|
||||||
if !epbs.contains(&epb) {
|
|
||||||
bail!(
|
bail!(
|
||||||
"EPB value '{epb}' is not available for {self}. available EPB values: {valid}",
|
"EPB value '{epb}' is not available for {self}. available EPB values: {valid}",
|
||||||
valid = epbs.join(", "),
|
valid = epbs.join(", "),
|
||||||
|
@ -308,10 +413,10 @@ impl Cpu {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_frequency_minimum(&self, frequency_mhz: u64) -> anyhow::Result<()> {
|
pub fn set_frequency_mhz_minimum(&mut self, frequency_mhz: u64) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self { number, .. } = *self;
|
||||||
|
|
||||||
self.validate_frequency_minimum(frequency_mhz)?;
|
self.validate_frequency_mhz_minimum(frequency_mhz)?;
|
||||||
|
|
||||||
// We use u64 for the intermediate calculation to prevent overflow
|
// We use u64 for the intermediate calculation to prevent overflow
|
||||||
let frequency_khz = frequency_mhz * 1000;
|
let frequency_khz = frequency_mhz * 1000;
|
||||||
|
@ -323,10 +428,14 @@ impl Cpu {
|
||||||
)
|
)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("this probably means that {self} doesn't exist or doesn't support changing minimum frequency")
|
format!("this probably means that {self} doesn't exist or doesn't support changing minimum frequency")
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
self.frequency_mhz_minimum = Some(frequency_mhz);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_frequency_minimum(&self, new_frequency_mhz: u64) -> anyhow::Result<()> {
|
fn validate_frequency_mhz_minimum(&self, new_frequency_mhz: u64) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self { number, .. } = self;
|
||||||
|
|
||||||
let Some(Ok(minimum_frequency_khz)) = fs::read_u64(format!(
|
let Some(Ok(minimum_frequency_khz)) = fs::read_u64(format!(
|
||||||
|
@ -346,10 +455,10 @@ impl Cpu {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_frequency_maximum(&self, frequency_mhz: u64) -> anyhow::Result<()> {
|
pub fn set_frequency_mhz_maximum(&mut self, frequency_mhz: u64) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self { number, .. } = *self;
|
||||||
|
|
||||||
self.validate_frequency_maximum(frequency_mhz)?;
|
self.validate_frequency_mhz_maximum(frequency_mhz)?;
|
||||||
|
|
||||||
// We use u64 for the intermediate calculation to prevent overflow
|
// We use u64 for the intermediate calculation to prevent overflow
|
||||||
let frequency_khz = frequency_mhz * 1000;
|
let frequency_khz = frequency_mhz * 1000;
|
||||||
|
@ -361,10 +470,14 @@ impl Cpu {
|
||||||
)
|
)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("this probably means that {self} doesn't exist or doesn't support changing maximum frequency")
|
format!("this probably means that {self} doesn't exist or doesn't support changing maximum frequency")
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
self.frequency_mhz_maximum = Some(frequency_mhz);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_frequency_maximum(&self, new_frequency_mhz: u64) -> anyhow::Result<()> {
|
fn validate_frequency_mhz_maximum(&self, new_frequency_mhz: u64) -> anyhow::Result<()> {
|
||||||
let Self { number, .. } = self;
|
let Self { number, .. } = self;
|
||||||
|
|
||||||
let Some(Ok(maximum_frequency_khz)) = fs::read_u64(format!(
|
let Some(Ok(maximum_frequency_khz)) = fs::read_u64(format!(
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn read(path: impl AsRef<Path>) -> Option<anyhow::Result<String>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
match fs::read_to_string(path) {
|
match fs::read_to_string(path) {
|
||||||
Ok(string) => Some(Ok(string)),
|
Ok(string) => Some(Ok(string.trim().to_owned())),
|
||||||
|
|
||||||
Err(error) if error.kind() == io::ErrorKind::NotFound => None,
|
Err(error) if error.kind() == io::ErrorKind::NotFound => None,
|
||||||
|
|
||||||
|
|
|
@ -21,18 +21,6 @@ pub fn get_cpu_core_info(
|
||||||
prev_times: &CpuTimes,
|
prev_times: &CpuTimes,
|
||||||
current_times: &CpuTimes,
|
current_times: &CpuTimes,
|
||||||
) -> anyhow::Result<CpuCoreInfo> {
|
) -> anyhow::Result<CpuCoreInfo> {
|
||||||
let cpufreq_path = PathBuf::from(format!("/sys/devices/system/cpu/cpu{core_id}/cpufreq/"));
|
|
||||||
|
|
||||||
let current_frequency_mhz = read_sysfs_value::<u32>(cpufreq_path.join("scaling_cur_freq"))
|
|
||||||
.map(|khz| khz / 1000)
|
|
||||||
.ok();
|
|
||||||
let min_frequency_mhz = read_sysfs_value::<u32>(cpufreq_path.join("scaling_min_freq"))
|
|
||||||
.map(|khz| khz / 1000)
|
|
||||||
.ok();
|
|
||||||
let max_frequency_mhz = read_sysfs_value::<u32>(cpufreq_path.join("scaling_max_freq"))
|
|
||||||
.map(|khz| khz / 1000)
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
// Temperature detection.
|
// Temperature detection.
|
||||||
// Should be generic enough to be able to support for multiple hardware sensors
|
// Should be generic enough to be able to support for multiple hardware sensors
|
||||||
// with the possibility of extending later down the road.
|
// with the possibility of extending later down the road.
|
||||||
|
@ -144,9 +132,6 @@ pub fn get_cpu_core_info(
|
||||||
|
|
||||||
Ok(CpuCoreInfo {
|
Ok(CpuCoreInfo {
|
||||||
core_id,
|
core_id,
|
||||||
current_frequency_mhz,
|
|
||||||
min_frequency_mhz,
|
|
||||||
max_frequency_mhz,
|
|
||||||
usage_percent,
|
usage_percent,
|
||||||
temperature_celsius,
|
temperature_celsius,
|
||||||
})
|
})
|
||||||
|
@ -253,47 +238,9 @@ pub fn get_all_cpu_core_info() -> anyhow::Result<Vec<CpuCoreInfo>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cpu_global_info(cpu_cores: &[CpuCoreInfo]) -> CpuGlobalInfo {
|
pub fn get_cpu_global_info(cpu_cores: &[CpuCoreInfo]) -> CpuGlobalInfo {
|
||||||
// Find a valid CPU to read global settings from
|
|
||||||
// Try cpu0 first, then fall back to any available CPU with cpufreq
|
|
||||||
let mut cpufreq_base_path_buf = PathBuf::from("/sys/devices/system/cpu/cpu0/cpufreq/");
|
|
||||||
|
|
||||||
if !cpufreq_base_path_buf.exists() {
|
|
||||||
let core_count = get_real_cpus().unwrap_or_else(|e| {
|
|
||||||
eprintln!("Warning: {e}");
|
|
||||||
0
|
|
||||||
});
|
|
||||||
|
|
||||||
for i in 0..core_count {
|
|
||||||
let test_path = PathBuf::from(format!("/sys/devices/system/cpu/cpu{i}/cpufreq/"));
|
|
||||||
if test_path.exists() {
|
|
||||||
cpufreq_base_path_buf = test_path;
|
|
||||||
break; // Exit the loop as soon as we find a valid path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let turbo_status_path = Path::new("/sys/devices/system/cpu/intel_pstate/no_turbo");
|
let turbo_status_path = Path::new("/sys/devices/system/cpu/intel_pstate/no_turbo");
|
||||||
let boost_path = Path::new("/sys/devices/system/cpu/cpufreq/boost");
|
let boost_path = Path::new("/sys/devices/system/cpu/cpufreq/boost");
|
||||||
|
|
||||||
let current_governor = if cpufreq_base_path_buf.join("scaling_governor").exists() {
|
|
||||||
read_sysfs_file_trimmed(cpufreq_base_path_buf.join("scaling_governor")).ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let available_governors = if cpufreq_base_path_buf
|
|
||||||
.join("scaling_available_governors")
|
|
||||||
.exists()
|
|
||||||
{
|
|
||||||
read_sysfs_file_trimmed(cpufreq_base_path_buf.join("scaling_available_governors"))
|
|
||||||
.map_or_else(
|
|
||||||
|_| vec![],
|
|
||||||
|s| s.split_whitespace().map(String::from).collect(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
let turbo_status = if turbo_status_path.exists() {
|
let turbo_status = if turbo_status_path.exists() {
|
||||||
// 0 means turbo enabled, 1 means disabled for intel_pstate
|
// 0 means turbo enabled, 1 means disabled for intel_pstate
|
||||||
read_sysfs_value::<u8>(turbo_status_path)
|
read_sysfs_value::<u8>(turbo_status_path)
|
||||||
|
@ -306,14 +253,6 @@ pub fn get_cpu_global_info(cpu_cores: &[CpuCoreInfo]) -> CpuGlobalInfo {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// EPP (Energy Performance Preference)
|
|
||||||
let energy_perf_pref =
|
|
||||||
read_sysfs_file_trimmed(cpufreq_base_path_buf.join("energy_performance_preference")).ok();
|
|
||||||
|
|
||||||
// EPB (Energy Performance Bias)
|
|
||||||
let energy_perf_bias =
|
|
||||||
read_sysfs_file_trimmed(cpufreq_base_path_buf.join("energy_performance_bias")).ok();
|
|
||||||
|
|
||||||
let platform_profile = read_sysfs_file_trimmed("/sys/firmware/acpi/platform_profile").ok();
|
let platform_profile = read_sysfs_file_trimmed("/sys/firmware/acpi/platform_profile").ok();
|
||||||
|
|
||||||
// Calculate average CPU temperature from the core temperatures
|
// Calculate average CPU temperature from the core temperatures
|
||||||
|
@ -340,11 +279,7 @@ pub fn get_cpu_global_info(cpu_cores: &[CpuCoreInfo]) -> CpuGlobalInfo {
|
||||||
|
|
||||||
// Return the constructed CpuGlobalInfo
|
// Return the constructed CpuGlobalInfo
|
||||||
CpuGlobalInfo {
|
CpuGlobalInfo {
|
||||||
current_governor,
|
|
||||||
available_governors,
|
|
||||||
turbo_status,
|
turbo_status,
|
||||||
epp: energy_perf_pref,
|
|
||||||
epb: energy_perf_bias,
|
|
||||||
platform_profile,
|
platform_profile,
|
||||||
average_temperature_celsius,
|
average_temperature_celsius,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue