Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set governor to "performance" if available #2438

Merged
merged 4 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ rpassword = "7.0.0"
rpc-toolkit = "0.2.2"
rust-argon2 = "1.0.0"
scopeguard = "1.1" # because avahi-sys fucks your shit up
sscanf = "0.4.1"
serde = { version = "1.0.139", features = ["derive", "rc"] }
serde_cbor = { package = "ciborium", version = "0.2.0" }
serde_json = "1.0.82"
Expand Down
20 changes: 20 additions & 0 deletions backend/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ use crate::middleware::auth::LOCAL_AUTH_COOKIE_PATH;
use crate::prelude::*;
use crate::sound::BEP;
use crate::system::time;
use crate::util::cpupower::{
current_governor, get_available_governors, set_governor, GOVERNOR_PERFORMANCE,
};
use crate::util::docker::{create_bridge_network, CONTAINER_DATADIR, CONTAINER_TOOL};
use crate::util::Invoke;
use crate::{Error, ARCH};
Expand Down Expand Up @@ -341,6 +344,23 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
.await?;
tracing::info!("Enabled Docker QEMU Emulation");

if current_governor()
.await?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't a is_performance method be better for what is returned on current_govenrnor()

.map(|g| &g != &GOVERNOR_PERFORMANCE)
.unwrap_or(false)
{
tracing::info!("Setting CPU Governor to \"{}\"", GOVERNOR_PERFORMANCE);
if get_available_governors()
.await?
.contains(&GOVERNOR_PERFORMANCE)
{
set_governor(&GOVERNOR_PERFORMANCE).await?;
tracing::info!("Set CPU Governor");
} else {
tracing::warn!("CPU Governor \"{}\" Not Available", GOVERNOR_PERFORMANCE)
}
}

let mut warn_time_not_synced = true;
for _ in 0..60 {
if check_time_is_synchronized().await? {
Expand Down
125 changes: 125 additions & 0 deletions backend/src/util/cpupower.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use std::borrow::Cow;
use std::collections::BTreeSet;

use imbl::OrdMap;
use tokio::process::Command;

use crate::prelude::*;
use crate::util::Invoke;

pub const GOVERNOR_PERFORMANCE: Governor = Governor(Cow::Borrowed("performance"));

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Governor(Cow<'static, str>);
impl std::fmt::Display for Governor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::ops::Deref for Governor {
type Target = str;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl std::borrow::Borrow<str> for Governor {
fn borrow(&self) -> &str {
&**self
}
}

pub async fn get_available_governors() -> Result<BTreeSet<Governor>, Error> {
let raw = String::from_utf8(
Command::new("cpupower")
.arg("frequency-info")
.arg("-g")
.invoke(ErrorKind::CpuSettings)
.await?,
)?;
let mut for_cpu: OrdMap<u32, BTreeSet<Governor>> = OrdMap::new();
let mut current_cpu = None;
for line in raw.lines() {
if line.starts_with("analyzing") {
current_cpu = Some(
sscanf::sscanf!(line, "analyzing CPU {u32}:")
.map_err(|e| eyre!("{e}"))
.with_kind(ErrorKind::ParseSysInfo)?,
);
} else if let Some(rest) = line
.trim()
.strip_prefix("available cpufreq governors:")
.map(|s| s.trim())
{
if rest != "Not Available" {
for_cpu
.entry(current_cpu.ok_or_else(|| {
Error::new(
eyre!("governors listed before cpu"),
ErrorKind::ParseSysInfo,
)
})?)
.or_default()
.extend(
rest.split_ascii_whitespace()
.map(|g| Governor(Cow::Owned(g.to_owned()))),
);
}
}
}
Ok(for_cpu
.into_iter()
.fold(None, |acc: Option<BTreeSet<Governor>>, (_, x)| {
if let Some(acc) = acc {
Some(acc.intersection(&x).cloned().collect())
} else {
Some(x)
}
})
.unwrap_or_default()) // include only governors available for ALL cpus
}

pub async fn current_governor() -> Result<Option<Governor>, Error> {
let Some(raw) = Command::new("cpupower")
.arg("frequency-info")
.arg("-p")
.invoke(ErrorKind::CpuSettings)
.await
.and_then(|s| Ok(Some(String::from_utf8(s)?)))
.or_else(|e| {
if e.source
.to_string()
.contains("Unable to determine current policy")
{
Ok(None)
} else {
Err(e)
}
})?
else {
return Ok(None);
};

for line in raw.lines() {
if let Some(governor) = line
.trim()
.strip_prefix("The governor \"")
.and_then(|s| s.strip_suffix("\" may decide which speed to use"))
{
return Ok(Some(Governor(Cow::Owned(governor.to_owned()))));
}
}
Err(Error::new(
eyre!("Failed to parse cpupower output:\n{raw}"),
ErrorKind::ParseSysInfo,
))
}

pub async fn set_governor(governor: &Governor) -> Result<(), Error> {
Command::new("cpupower")
.arg("frequency-set")
.arg("-g")
.arg(&*governor.0)
.invoke(ErrorKind::CpuSettings)
.await?;
Ok(())
}
1 change: 1 addition & 0 deletions backend/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use tracing::instrument;
use crate::shutdown::Shutdown;
use crate::{Error, ErrorKind, ResultExt as _};
pub mod config;
pub mod cpupower;
pub mod docker;
pub mod http_reader;
pub mod io;
Expand Down
1 change: 1 addition & 0 deletions build/lib/depends
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ iw
jq
libavahi-client3
libyajl2
linux-cpupower
lm-sensors
lshw
lvm2
Expand Down
2 changes: 2 additions & 0 deletions libs/models/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub enum ErrorKind {
OpenSsh = 66,
Zram = 67,
Lshw = 68,
CpuSettings = 69,
}
impl ErrorKind {
pub fn as_str(&self) -> &'static str {
Expand Down Expand Up @@ -151,6 +152,7 @@ impl ErrorKind {
OpenSsh => "OpenSSH Error",
Zram => "Zram Error",
Lshw => "LSHW Error",
CpuSettings => "CPU Settings Error",
}
}
}
Expand Down