From e0f49a338a376f4e3f02afbe602b15ff31cb7413 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Tue, 27 Aug 2024 13:36:50 +0200 Subject: [PATCH] scx_bpfland: fix turbo boost domain nullifying primary domain limits When creating the turbo boost scheduling domain, we might use a full CPU mask (selecting all possible CPUs) to indicate "do not prioritize turbo boost CPUs" or when all CPUs have the same maximum frequency. This approach works when the primary domain also contains all the CPUs, as the complete overlap allows the CPU selection logic to ignore the turbo boost domain and start picking CPUs directly from the primary domain. However, if the primary domain doesn't include all CPUs, the two domains won't fully overlap, which can lead to the turbo boost domain incorrectly including all CPUs, thereby negating the restrictions set by the primary scheduling domain. To resolve this, an empty CPU mask should be used for the turbo boost domain when turbo boost CPUs aren't prioritized. If the turbo boost domain is empty, it should be entirely bypassed, and the selection should proceed directly to the primary domain. Reported-by: Changwoo Min Signed-off-by: Andrea Righi --- scheds/rust/scx_bpfland/src/bpf/main.bpf.c | 4 +++- scheds/rust/scx_bpfland/src/main.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scheds/rust/scx_bpfland/src/bpf/main.bpf.c b/scheds/rust/scx_bpfland/src/bpf/main.bpf.c index 445ede73f..a1e30763f 100644 --- a/scheds/rust/scx_bpfland/src/bpf/main.bpf.c +++ b/scheds/rust/scx_bpfland/src/bpf/main.bpf.c @@ -592,7 +592,9 @@ static s32 pick_idle_cpu(struct task_struct *p, s32 prev_cpu, u64 wake_flags) * Try to dispatch on the turbo boosted CPUs first. If we can't find * any idle CPU, re-try again with the primary scheduling domain. */ - if (do_turbo && !bpf_cpumask_equal(cast_mask(turbo), cast_mask(primary))) { + if (do_turbo && + !bpf_cpumask_empty(cast_mask(turbo)) && + !bpf_cpumask_equal(cast_mask(turbo), cast_mask(primary))) { bpf_cpumask_and(p_mask, p->cpus_ptr, cast_mask(turbo)); } else { bpf_cpumask_and(p_mask, p->cpus_ptr, cast_mask(primary)); diff --git a/scheds/rust/scx_bpfland/src/main.rs b/scheds/rust/scx_bpfland/src/main.rs index 5b1f14c97..7990e37a6 100644 --- a/scheds/rust/scx_bpfland/src/main.rs +++ b/scheds/rust/scx_bpfland/src/main.rs @@ -434,9 +434,10 @@ impl<'a> Scheduler<'a> { "balance_power" => get_primary_cpus(Powermode::Turbo).unwrap_or(Vec::new()), &_ => Vec::new(), }; + // If no turbo-boosted CPUs are selected, use an empty CPU mask, so that tasks are + // scheduled directly to the primary domain, bypassing the turbo boost domain. if cpus.is_empty() { let mut cpumask = Cpumask::new()?; - cpumask.setall(); cpumask } else { Cpumask::from_str(&cpus_to_cpumask(&cpus))?