mirror of
https://github.com/RGBCube/superfreq
synced 2025-07-28 01:17:45 +00:00
commit
c88b3c00af
1 changed files with 53 additions and 71 deletions
122
src/cpu.rs
122
src/cpu.rs
|
@ -1,11 +1,6 @@
|
||||||
use crate::core::TurboSetting;
|
use crate::core::TurboSetting;
|
||||||
use crate::monitor::Result as MonitorResult;
|
|
||||||
use core::str;
|
use core::str;
|
||||||
use std::{
|
use std::{fs, io, path::Path, string::ToString};
|
||||||
fs, io,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
string::ToString,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ControlError {
|
pub enum ControlError {
|
||||||
|
@ -18,10 +13,10 @@ pub enum ControlError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for ControlError {
|
impl From<io::Error> for ControlError {
|
||||||
fn from(err: io::Error) -> ControlError {
|
fn from(err: io::Error) -> Self {
|
||||||
match err.kind() {
|
match err.kind() {
|
||||||
io::ErrorKind::PermissionDenied => ControlError::PermissionDenied(err.to_string()),
|
io::ErrorKind::PermissionDenied => Self::PermissionDenied(err.to_string()),
|
||||||
_ => ControlError::Io(err),
|
_ => Self::Io(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,18 +24,17 @@ impl From<io::Error> for ControlError {
|
||||||
impl std::fmt::Display for ControlError {
|
impl std::fmt::Display for ControlError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ControlError::Io(e) => write!(f, "I/O error: {}", e),
|
Self::Io(e) => write!(f, "I/O error: {e}"),
|
||||||
ControlError::WriteError(s) => write!(f, "Failed to write to sysfs path: {}", s),
|
Self::WriteError(s) => write!(f, "Failed to write to sysfs path: {s}"),
|
||||||
ControlError::InvalidValueError(s) => write!(f, "Invalid value for setting: {}", s),
|
Self::InvalidValueError(s) => write!(f, "Invalid value for setting: {s}"),
|
||||||
ControlError::NotSupported(s) => write!(f, "Control action not supported: {}", s),
|
Self::NotSupported(s) => write!(f, "Control action not supported: {s}"),
|
||||||
ControlError::PermissionDenied(s) => {
|
Self::PermissionDenied(s) => {
|
||||||
write!(f, "Permission denied: {}. Try running with sudo.", s)
|
write!(f, "Permission denied: {s}. Try running with sudo.")
|
||||||
}
|
}
|
||||||
ControlError::InvalidProfile(s) => {
|
Self::InvalidProfile(s) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Invalid platform control profile {} supplied, please provide a valid one.",
|
"Invalid platform control profile {s} supplied, please provide a valid one."
|
||||||
s
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,27 +69,41 @@ where
|
||||||
// Let's use a similar discovery to monitor's get_logical_core_count
|
// Let's use a similar discovery to monitor's get_logical_core_count
|
||||||
let mut cores_to_act_on = Vec::new();
|
let mut cores_to_act_on = Vec::new();
|
||||||
let path = Path::new("/sys/devices/system/cpu");
|
let path = Path::new("/sys/devices/system/cpu");
|
||||||
if path.exists() {
|
if !path.exists() {
|
||||||
if let Ok(entries) = fs::read_dir(path) {
|
return Err(ControlError::NotSupported(format!(
|
||||||
for entry in entries.flatten() {
|
"No logical cores found at {}.",
|
||||||
let name = entry.file_name();
|
path.display()
|
||||||
if let Some(name_str) = name.to_str() {
|
)));
|
||||||
if name_str.starts_with("cpu")
|
}
|
||||||
&& name_str.len() > 3
|
|
||||||
&& name_str[3..].chars().all(char::is_numeric)
|
let entries = fs::read_dir(path)
|
||||||
{
|
.map_err(|_| {
|
||||||
if entry.path().join("cpufreq").exists() {
|
ControlError::PermissionDenied(format!("Cannot read contents of {}.", path.display()))
|
||||||
if let Ok(core_id) = name_str[3..].parse::<u32>() {
|
})?
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
let entry_file_name = entry.file_name();
|
||||||
|
let Some(name) = entry_file_name.to_str() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Skip non-CPU directories (e.g., cpuidle, cpufreq)
|
||||||
|
if !name.starts_with("cpu") || name.len() <= 3 || !name[3..].chars().all(char::is_numeric) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !entry.path().join("cpufreq").exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(core_id) = name[3..].parse::<u32>() {
|
||||||
cores_to_act_on.push(core_id);
|
cores_to_act_on.push(core_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cores_to_act_on.is_empty() {
|
if cores_to_act_on.is_empty() {
|
||||||
// Fallback if sysfs iteration above fails to find any cpufreq cores
|
// Fallback if sysfs iteration above fails to find any cpufreq cores
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let num_cores = num_cpus::get() as u32;
|
let num_cores = num_cpus::get() as u32;
|
||||||
for core_id in 0..num_cores {
|
for core_id in 0..num_cores {
|
||||||
cores_to_act_on.push(core_id);
|
cores_to_act_on.push(core_id);
|
||||||
|
@ -110,7 +118,7 @@ where
|
||||||
|
|
||||||
pub fn set_governor(governor: &str, core_id: Option<u32>) -> Result<()> {
|
pub fn set_governor(governor: &str, core_id: Option<u32>) -> Result<()> {
|
||||||
let action = |id: u32| {
|
let action = |id: u32| {
|
||||||
let path = format!("/sys/devices/system/cpu/cpu{}/cpufreq/scaling_governor", id);
|
let path = format!("/sys/devices/system/cpu/cpu{id}/cpufreq/scaling_governor");
|
||||||
if Path::new(&path).exists() {
|
if Path::new(&path).exists() {
|
||||||
write_sysfs_value(&path, governor)
|
write_sysfs_value(&path, governor)
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,11 +128,7 @@ pub fn set_governor(governor: &str, core_id: Option<u32>) -> Result<()> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(id) = core_id {
|
core_id.map_or_else(|| for_each_cpu_core(action), action)
|
||||||
action(id)
|
|
||||||
} else {
|
|
||||||
for_each_cpu_core(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_turbo(setting: TurboSetting) -> Result<()> {
|
pub fn set_turbo(setting: TurboSetting) -> Result<()> {
|
||||||
|
@ -155,76 +159,54 @@ pub fn set_turbo(setting: TurboSetting) -> Result<()> {
|
||||||
|
|
||||||
pub fn set_epp(epp: &str, core_id: Option<u32>) -> Result<()> {
|
pub fn set_epp(epp: &str, core_id: Option<u32>) -> Result<()> {
|
||||||
let action = |id: u32| {
|
let action = |id: u32| {
|
||||||
let path = format!(
|
let path = format!("/sys/devices/system/cpu/cpu{id}/cpufreq/energy_performance_preference");
|
||||||
"/sys/devices/system/cpu/cpu{}/cpufreq/energy_performance_preference",
|
|
||||||
id
|
|
||||||
);
|
|
||||||
if Path::new(&path).exists() {
|
if Path::new(&path).exists() {
|
||||||
write_sysfs_value(&path, epp)
|
write_sysfs_value(&path, epp)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(id) = core_id {
|
core_id.map_or_else(|| for_each_cpu_core(action), action)
|
||||||
action(id)
|
|
||||||
} else {
|
|
||||||
for_each_cpu_core(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_epb(epb: &str, core_id: Option<u32>) -> Result<()> {
|
pub fn set_epb(epb: &str, core_id: Option<u32>) -> Result<()> {
|
||||||
// EPB is often an integer 0-15. Ensure `epb` string is valid if parsing.
|
// EPB is often an integer 0-15. Ensure `epb` string is valid if parsing.
|
||||||
// For now, writing it directly as a string.
|
// For now, writing it directly as a string.
|
||||||
let action = |id: u32| {
|
let action = |id: u32| {
|
||||||
let path = format!(
|
let path = format!("/sys/devices/system/cpu/cpu{id}/cpufreq/energy_performance_bias");
|
||||||
"/sys/devices/system/cpu/cpu{}/cpufreq/energy_performance_bias",
|
|
||||||
id
|
|
||||||
);
|
|
||||||
if Path::new(&path).exists() {
|
if Path::new(&path).exists() {
|
||||||
write_sysfs_value(&path, epb)
|
write_sysfs_value(&path, epb)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(id) = core_id {
|
core_id.map_or_else(|| for_each_cpu_core(action), action)
|
||||||
action(id)
|
|
||||||
} else {
|
|
||||||
for_each_cpu_core(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_min_frequency(freq_mhz: u32, core_id: Option<u32>) -> Result<()> {
|
pub fn set_min_frequency(freq_mhz: u32, core_id: Option<u32>) -> Result<()> {
|
||||||
let freq_khz_str = (freq_mhz * 1000).to_string();
|
let freq_khz_str = (freq_mhz * 1000).to_string();
|
||||||
let action = |id: u32| {
|
let action = |id: u32| {
|
||||||
let path = format!("/sys/devices/system/cpu/cpu{}/cpufreq/scaling_min_freq", id);
|
let path = format!("/sys/devices/system/cpu/cpu{id}/cpufreq/scaling_min_freq");
|
||||||
if Path::new(&path).exists() {
|
if Path::new(&path).exists() {
|
||||||
write_sysfs_value(&path, &freq_khz_str)
|
write_sysfs_value(&path, &freq_khz_str)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(id) = core_id {
|
core_id.map_or_else(|| for_each_cpu_core(action), action)
|
||||||
action(id)
|
|
||||||
} else {
|
|
||||||
for_each_cpu_core(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_max_frequency(freq_mhz: u32, core_id: Option<u32>) -> Result<()> {
|
pub fn set_max_frequency(freq_mhz: u32, core_id: Option<u32>) -> Result<()> {
|
||||||
let freq_khz_str = (freq_mhz * 1000).to_string();
|
let freq_khz_str = (freq_mhz * 1000).to_string();
|
||||||
let action = |id: u32| {
|
let action = |id: u32| {
|
||||||
let path = format!("/sys/devices/system/cpu/cpu{}/cpufreq/scaling_max_freq", id);
|
let path = format!("/sys/devices/system/cpu/cpu{id}/cpufreq/scaling_max_freq");
|
||||||
if Path::new(&path).exists() {
|
if Path::new(&path).exists() {
|
||||||
write_sysfs_value(&path, &freq_khz_str)
|
write_sysfs_value(&path, &freq_khz_str)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(id) = core_id {
|
core_id.map_or_else(|| for_each_cpu_core(action), action)
|
||||||
action(id)
|
|
||||||
} else {
|
|
||||||
for_each_cpu_core(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the platform profile.
|
/// Sets the platform profile.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue