Skip to content

Commit

Permalink
Merge pull request #1070 from CachyOS/feature/scx-loader-lib-crate
Browse files Browse the repository at this point in the history
scx_loader: provide library crate to be used by other crates
  • Loading branch information
hodgesds authored Dec 8, 2024
2 parents 8ecbea6 + ee0d293 commit b9a505c
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 87 deletions.
7 changes: 7 additions & 0 deletions rust/scx_loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ tokio = { version = "1.39", features = ["macros", "sync", "rt-multi-thread", "pr
toml = "0.8.19"
zbus = { version = "5", features = ["tokio"], default-features = false }
zvariant = "5.1"

[lib]
path = "src/lib.rs"

[[bin]]
name = "scx_loader"
path = "src/main.rs"
9 changes: 5 additions & 4 deletions rust/scx_loader/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ use std::path::Path;

use anyhow::Result;
use serde::Deserialize;
use serde::Serialize;

use crate::get_name_from_scx;
use crate::SchedMode;
use crate::SupportedSched;

#[derive(Debug, PartialEq, Default, Deserialize)]
#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
pub default_sched: Option<SupportedSched>,
pub default_mode: Option<SchedMode>,
pub scheds: HashMap<String, Sched>,
}

#[derive(Debug, PartialEq, Default, Deserialize)]
#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
pub struct Sched {
pub auto_mode: Option<Vec<String>>,
pub gaming_mode: Option<Vec<String>>,
Expand Down Expand Up @@ -102,7 +102,8 @@ pub fn get_scx_flags_for_mode(
scx_sched: &SupportedSched,
sched_mode: SchedMode,
) -> Vec<String> {
if let Some(sched_config) = config.scheds.get(get_name_from_scx(scx_sched)) {
let scx_name: &str = scx_sched.into();
if let Some(sched_config) = config.scheds.get(scx_name) {
let scx_flags = extract_scx_flags_from_config(sched_config, &sched_mode);

// try to exact flags from config, otherwise fallback to hardcoded default
Expand Down
62 changes: 62 additions & 0 deletions rust/scx_loader/src/dbus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2024 Vladislav Nepogodin <vnepogodin@cachyos.org>

// This software may be used and distributed according to the terms of the
// GNU General Public License version 2.

use crate::SchedMode;
use crate::SupportedSched;

#[zbus::proxy(
interface = "org.scx.Loader",
default_service = "org.scx.Loader",
default_path = "/org/scx/Loader"
)]
pub trait LoaderClient {
/// Starts the specified scheduler with the given mode.
fn start_scheduler(&self, scx_name: SupportedSched, sched_mode: SchedMode) -> zbus::Result<()>;

/// Starts the specified scheduler with the provided arguments.
fn start_scheduler_with_args(
&self,
scx_name: SupportedSched,
scx_args: &[String],
) -> zbus::Result<()>;

/// Stops the currently running scheduler.
fn stop_scheduler(&self) -> zbus::Result<()>;

/// Method for switching to the specified scheduler with the given mode.
/// This method will stop the currently running scheduler (if any) and
/// then start the new scheduler.
fn switch_scheduler(&self, scx_name: SupportedSched, sched_mode: SchedMode)
-> zbus::Result<()>;

/// Switches to the specified scheduler with the provided arguments. This
/// method will stop the currently running scheduler (if any) and then
/// start the new scheduler with the given arguments.
fn switch_scheduler_with_args(
&self,
scx_name: SupportedSched,
scx_args: &[String],
) -> zbus::Result<()>;

/// The name of the currently running scheduler. If no scheduler is active,
/// this property will be set to "unknown".
#[zbus(property)]
fn current_scheduler(&self) -> zbus::Result<String>;

/// The currently active scheduler mode. Scheduler modes allow you to
/// apply pre-defined configurations to a scheduler that are
/// optimized for different use cases. If no scheduler is active,
/// this property will be set to 0 (Auto).
#[zbus(property)]
fn scheduler_mode(&self) -> zbus::Result<SchedMode>;

/// A list of the schedulers currently supported by the Scheduler Loader.
/// The names of the supported schedulers will be listed as strings in
/// this array.
#[zbus(property)]
fn supported_schedulers(&self) -> zbus::Result<Vec<String>>;
}
74 changes: 74 additions & 0 deletions rust/scx_loader/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2024 Vladislav Nepogodin <vnepogodin@cachyos.org>

// This software may be used and distributed according to the terms of the
// GNU General Public License version 2.

pub mod config;
pub mod dbus;

use std::str::FromStr;

use serde::Deserialize;
use serde::Serialize;
use zvariant::OwnedValue;
use zvariant::Type;
use zvariant::Value;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
#[zvariant(signature = "s")]
#[serde(rename_all = "lowercase")]
pub enum SupportedSched {
#[serde(rename = "scx_bpfland")]
Bpfland,
#[serde(rename = "scx_rusty")]
Rusty,
#[serde(rename = "scx_lavd")]
Lavd,
#[serde(rename = "scx_flash")]
Flash,
}

#[derive(Debug, Clone, Deserialize, Serialize, Type, Value, OwnedValue, PartialEq)]
pub enum SchedMode {
/// Default values for the scheduler
Auto = 0,
/// Applies flags for better gaming experience
Gaming = 1,
/// Applies flags for lower power usage
PowerSave = 2,
/// Starts scheduler in low latency mode
LowLatency = 3,
}

impl From<&SupportedSched> for &str {
fn from(scx_name: &SupportedSched) -> &'static str {
match scx_name {
SupportedSched::Bpfland => "scx_bpfland",
SupportedSched::Rusty => "scx_rusty",
SupportedSched::Lavd => "scx_lavd",
SupportedSched::Flash => "scx_flash",
}
}
}

impl From<SupportedSched> for &str {
fn from(scx_name: SupportedSched) -> &'static str {
scx_name.into()
}
}

impl FromStr for SupportedSched {
type Err = anyhow::Error;

fn from_str(scx_name: &str) -> anyhow::Result<SupportedSched> {
match scx_name {
"scx_bpfland" => Ok(SupportedSched::Bpfland),
"scx_rusty" => Ok(SupportedSched::Rusty),
"scx_lavd" => Ok(SupportedSched::Lavd),
"scx_flash" => Ok(SupportedSched::Flash),
_ => Err(anyhow::anyhow!("{scx_name} is not supported")),
}
}
}
98 changes: 15 additions & 83 deletions rust/scx_loader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2.

mod config;
mod logger;

use scx_loader::dbus::LoaderClientProxy;
use scx_loader::*;

use std::process::Stdio;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
Expand All @@ -16,8 +18,6 @@ use std::sync::Arc;
use anyhow::Context;
use anyhow::Result;
use clap::Parser;
use serde::Deserialize;
use serde::Serialize;
use sysinfo::System;
use tokio::process::Child;
use tokio::process::Command;
Expand All @@ -27,21 +27,6 @@ use tokio::time::Duration;
use tokio::time::Instant;
use zbus::interface;
use zbus::Connection;
use zvariant::Type;
use zvariant::Value;

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum SupportedSched {
#[serde(rename = "scx_bpfland")]
Bpfland,
#[serde(rename = "scx_rusty")]
Rusty,
#[serde(rename = "scx_lavd")]
Lavd,
#[serde(rename = "scx_flash")]
Flash,
}

#[derive(Debug, PartialEq)]
enum ScxMessage {
Expand Down Expand Up @@ -69,18 +54,6 @@ enum RunnerMessage {
Stop,
}

#[derive(Debug, Clone, Deserialize, Serialize, Type, Value, PartialEq)]
enum SchedMode {
/// Default values for the scheduler
Auto = 0,
/// Applies flags for better gaming experience
Gaming = 1,
/// Applies flags for lower power usage
PowerSave = 2,
/// Starts scheduler in low latency mode
LowLatency = 3,
}

struct ScxLoader {
current_scx: Option<SupportedSched>,
current_mode: SchedMode,
Expand All @@ -100,9 +73,9 @@ impl ScxLoader {
#[zbus(property)]
async fn current_scheduler(&self) -> String {
if let Some(current_scx) = &self.current_scx {
let current_scx = get_name_from_scx(current_scx).into();
let current_scx: &str = current_scx.into();
log::info!("called {current_scx:?}");
return current_scx;
return current_scx.to_owned();
}
"unknown".to_owned()
}
Expand All @@ -121,11 +94,9 @@ impl ScxLoader {

async fn start_scheduler(
&mut self,
scx_name: &str,
scx_name: SupportedSched,
sched_mode: SchedMode,
) -> zbus::fdo::Result<()> {
let scx_name = get_scx_from_str(scx_name)?;

log::info!("starting {scx_name:?} with mode {sched_mode:?}..");

let _ = self.channel.send(ScxMessage::StartSched((
Expand All @@ -140,11 +111,9 @@ impl ScxLoader {

async fn start_scheduler_with_args(
&mut self,
scx_name: &str,
scx_name: SupportedSched,
scx_args: Vec<String>,
) -> zbus::fdo::Result<()> {
let scx_name = get_scx_from_str(scx_name)?;

log::info!("starting {scx_name:?} with args {scx_args:?}..");

let _ = self
Expand All @@ -159,11 +128,9 @@ impl ScxLoader {

async fn switch_scheduler(
&mut self,
scx_name: &str,
scx_name: SupportedSched,
sched_mode: SchedMode,
) -> zbus::fdo::Result<()> {
let scx_name = get_scx_from_str(scx_name)?;

log::info!("switching {scx_name:?} with mode {sched_mode:?}..");

let _ = self.channel.send(ScxMessage::SwitchSched((
Expand All @@ -178,11 +145,9 @@ impl ScxLoader {

async fn switch_scheduler_with_args(
&mut self,
scx_name: &str,
scx_name: SupportedSched,
scx_args: Vec<String>,
) -> zbus::fdo::Result<()> {
let scx_name = get_scx_from_str(scx_name)?;

log::info!("switching {scx_name:?} with args {scx_args:?}..");

let _ = self
Expand All @@ -197,7 +162,7 @@ impl ScxLoader {

async fn stop_scheduler(&mut self) -> zbus::fdo::Result<()> {
if let Some(current_scx) = &self.current_scx {
let scx_name = get_name_from_scx(current_scx);
let scx_name: &str = current_scx.into();

log::info!("stopping {scx_name:?}..");
let _ = self.channel.send(ScxMessage::StopSched);
Expand All @@ -208,18 +173,6 @@ impl ScxLoader {
}
}

#[zbus::proxy(
interface = "org.scx.Loader",
default_service = "org.scx.Loader",
default_path = "/org/scx/Loader"
)]
pub trait LoaderClient {
/// Method for switching to the specified scheduler with the given mode.
/// This method will stop the currently running scheduler (if any) and
/// then start the new scheduler.
fn switch_scheduler(&self, scx_name: &str, sched_mode: SchedMode) -> zbus::Result<()>;
}

// Monitors CPU utilization and enables scx_lavd when utilization of any CPUs is > 90%
async fn monitor_cpu_util() -> Result<()> {
let mut system = System::new_all();
Expand Down Expand Up @@ -247,8 +200,10 @@ async fn monitor_cpu_util() -> Result<()> {
if cpu_above_threshold_since.unwrap().elapsed() > high_utilization_trigger_duration {
if running_sched.is_none() {
log::info!("CPU Utilization exceeded 90% for 5 seconds, starting scx_lavd");

let scx_name: &str = SupportedSched::Lavd.into();
running_sched = Some(
Command::new(get_name_from_scx(&SupportedSched::Lavd))
Command::new(scx_name)
.spawn()
.expect("Failed to start scx_lavd"),
);
Expand Down Expand Up @@ -339,7 +294,7 @@ async fn main() -> Result<()> {

let loader_client = LoaderClientProxy::new(&connection).await?;
loader_client
.switch_scheduler(get_name_from_scx(default_sched), default_mode)
.switch_scheduler(default_sched.clone(), default_mode)
.await?;
}

Expand Down Expand Up @@ -530,7 +485,7 @@ async fn spawn_scheduler(
args: Vec<String>,
child_id: Arc<AtomicU32>,
) -> Result<Child> {
let sched_bin_name = get_name_from_scx(&scx_crate);
let sched_bin_name: &str = scx_crate.into();
log::info!("starting {sched_bin_name} command");

let mut cmd = Command::new(sched_bin_name);
Expand Down Expand Up @@ -580,26 +535,3 @@ async fn stop_scheduler(child_id: Arc<AtomicU32>) -> Result<()> {

Ok(())
}

/// Get the scx trait from the given scx name or return error if the given scx name is not supported
fn get_scx_from_str(scx_name: &str) -> zbus::fdo::Result<SupportedSched> {
match scx_name {
"scx_bpfland" => Ok(SupportedSched::Bpfland),
"scx_rusty" => Ok(SupportedSched::Rusty),
"scx_lavd" => Ok(SupportedSched::Lavd),
"scx_flash" => Ok(SupportedSched::Flash),
_ => Err(zbus::fdo::Error::Failed(format!(
"{scx_name} is not supported"
))),
}
}

/// Get the scx name from the given scx trait
fn get_name_from_scx(supported_sched: &SupportedSched) -> &'static str {
match supported_sched {
SupportedSched::Bpfland => "scx_bpfland",
SupportedSched::Rusty => "scx_rusty",
SupportedSched::Lavd => "scx_lavd",
SupportedSched::Flash => "scx_flash",
}
}

0 comments on commit b9a505c

Please sign in to comment.