From fb353f75388a121be87b7a0357a4d6e20f518b7f Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Wed, 28 May 2025 16:40:22 +0200 Subject: [PATCH 1/2] scx_utils: autopower: Introduce balanced_power and balanced_performance Some CPU frequency scaling drivers, such as intel_pstate or amd_pstate, expose intermediate performance scaling preferences: balance_power and balance_performance. These represent a spectrum between maximum power efficiency and peak performance, offering more granular control than the traditional performance or powersave modes. Expose this information in the scx_utils crate, so that schedulers can also apply more fine-grained performance or power-saving optimizations. Signed-off-by: Andrea Righi --- rust/scx_utils/src/autopower.rs | 12 +++++++----- scheds/rust/scx_bpfland/src/main.rs | 5 ++--- scheds/rust/scx_lavd/src/main.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/rust/scx_utils/src/autopower.rs b/rust/scx_utils/src/autopower.rs index 4035b77233..27a6876974 100644 --- a/rust/scx_utils/src/autopower.rs +++ b/rust/scx_utils/src/autopower.rs @@ -24,7 +24,7 @@ const MAX_RETRIES: usize = 10; #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PowerProfile { Powersave, - Balanced, + Balanced { power: bool }, Performance, Unknown, } @@ -33,7 +33,8 @@ impl fmt::Display for PowerProfile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PowerProfile::Powersave => "powersave", - PowerProfile::Balanced => "balanced", + PowerProfile::Balanced { power: true } => "balanced_power", + PowerProfile::Balanced { power: false } => "balanced_performance", PowerProfile::Performance => "performance", PowerProfile::Unknown => "unknown", } @@ -49,8 +50,9 @@ fn read_energy_profile() -> PowerProfile { .ok() .or_else(|| fs::read_to_string(scaling_governor_path).ok()) .map(|s| match s.trim_end() { - "power" | "balance_power" | "powersave" => PowerProfile::Powersave, - "balance_performance" => PowerProfile::Balanced, + "power" | "powersave" => PowerProfile::Powersave, + "balance_power" => PowerProfile::Balanced { power: true }, + "balance_performance" => PowerProfile::Balanced { power: false }, "performance" => PowerProfile::Performance, _ => PowerProfile::Unknown, }) @@ -61,7 +63,7 @@ pub fn fetch_power_profile(no_ppd: bool) -> PowerProfile { fn parse_profile(profile: &str) -> PowerProfile { match profile { "power-saver" => PowerProfile::Powersave, - "balanced" => PowerProfile::Balanced, + "balanced" => PowerProfile::Balanced { power: false }, "performance" => PowerProfile::Performance, _ => PowerProfile::Unknown, } diff --git a/scheds/rust/scx_bpfland/src/main.rs b/scheds/rust/scx_bpfland/src/main.rs index 7b106b993d..d0ed009ea9 100644 --- a/scheds/rust/scx_bpfland/src/main.rs +++ b/scheds/rust/scx_bpfland/src/main.rs @@ -419,9 +419,8 @@ impl<'a> Scheduler<'a> { "performance" => Self::epp_to_cpumask(Powermode::Performance)?, "auto" => match power_profile { PowerProfile::Powersave => Self::epp_to_cpumask(Powermode::Powersave)?, - PowerProfile::Performance | PowerProfile::Balanced => { - Self::epp_to_cpumask(Powermode::Performance)? - } + PowerProfile::Balanced { .. } => Self::epp_to_cpumask(Powermode::Any)?, + PowerProfile::Performance => Self::epp_to_cpumask(Powermode::Performance)?, PowerProfile::Unknown => Self::epp_to_cpumask(Powermode::Any)?, }, "all" => Self::epp_to_cpumask(Powermode::Any)?, diff --git a/scheds/rust/scx_lavd/src/main.rs b/scheds/rust/scx_lavd/src/main.rs index 569b30be63..190561c56c 100644 --- a/scheds/rust/scx_lavd/src/main.rs +++ b/scheds/rust/scx_lavd/src/main.rs @@ -950,7 +950,7 @@ impl<'a> Scheduler<'a> { let _ = match profile { PowerProfile::Performance => self.set_power_profile(LAVD_PM_PERFORMANCE), - PowerProfile::Balanced => self.set_power_profile(LAVD_PM_BALANCED), + PowerProfile::Balanced { .. } => self.set_power_profile(LAVD_PM_BALANCED), PowerProfile::Powersave => self.set_power_profile(LAVD_PM_POWERSAVE), PowerProfile::Unknown => { // We don't know how to handle an unknown energy profile, From f18d94e39a537c548876750b9d708493e98d6524 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Wed, 28 May 2025 16:43:07 +0200 Subject: [PATCH 2/2] scx_bpfland: Support balance_power and balance_performance modes Use the following logic when running in auto mode (`-m auto`): +------------------------+----------------+ | Current Power Profile | Active Cores | +------------------------+----------------+ | powersave | slow cores | | balance_power | slow cores | | balance_performance | all cores | | performance | all cores | +------------------------+----------------+ With this logic, on battery-powered systems, the scheduler prioritizes the slow cores when running on battery. When plugged into AC power, it uses all cores more evenly. If the CPU frequency scaling driver supports only a single "balanced" mode, the scheduler operates as balance_performance, using all cores equally. Signed-off-by: Andrea Righi --- scheds/rust/scx_bpfland/src/main.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scheds/rust/scx_bpfland/src/main.rs b/scheds/rust/scx_bpfland/src/main.rs index d0ed009ea9..098b46a550 100644 --- a/scheds/rust/scx_bpfland/src/main.rs +++ b/scheds/rust/scx_bpfland/src/main.rs @@ -339,7 +339,7 @@ impl<'a> Scheduler<'a> { let mut skel = scx_ops_load!(skel, bpfland_ops, uei)?; // Initialize the primary scheduling domain and the preferred domain. - let power_profile = fetch_power_profile(false); + let power_profile = Self::power_profile(); if let Err(err) = Self::init_energy_domain(&mut skel, &opts.primary_domain, power_profile) { warn!("failed to initialize primary domain: error {}", err); } @@ -419,8 +419,11 @@ impl<'a> Scheduler<'a> { "performance" => Self::epp_to_cpumask(Powermode::Performance)?, "auto" => match power_profile { PowerProfile::Powersave => Self::epp_to_cpumask(Powermode::Powersave)?, - PowerProfile::Balanced { .. } => Self::epp_to_cpumask(Powermode::Any)?, - PowerProfile::Performance => Self::epp_to_cpumask(Powermode::Performance)?, + PowerProfile::Balanced { power: true } => { + Self::epp_to_cpumask(Powermode::Powersave)? + } + PowerProfile::Balanced { power: false } => Self::epp_to_cpumask(Powermode::Any)?, + PowerProfile::Performance => Self::epp_to_cpumask(Powermode::Any)?, PowerProfile::Unknown => Self::epp_to_cpumask(Powermode::Any)?, }, "all" => Self::epp_to_cpumask(Powermode::Any)?, @@ -472,9 +475,18 @@ impl<'a> Scheduler<'a> { Ok(()) } + fn power_profile() -> PowerProfile { + let profile = fetch_power_profile(true); + if profile == PowerProfile::Unknown { + fetch_power_profile(false) + } else { + profile + } + } + fn refresh_sched_domain(&mut self) -> bool { if self.power_profile != PowerProfile::Unknown { - let power_profile = fetch_power_profile(false); + let power_profile = Self::power_profile(); if power_profile != self.power_profile { self.power_profile = power_profile;