The __select_idle_cpu() function uses sched_cpu_cookie_match() to determine
if a task can be placed on an idle CPU. This function incorrectly returns
false when the whole core is idle but the task has a cookie, preventing
proper task placement.
Replace sched_cpu_cookie_match() with sched_core_cookie_match() which
correctly handles the idle core case. Refactor select_idle_smt() to avoid
duplicate work by checking core cookie compatibility only once in the SMT
mask.
Fixes: 97886d9dcd868 ("sched: Migration changes for core scheduling")
Signed-off-by: Fernand Sieber <sieberf@amazon.com>
---
kernel/sched/fair.c | 5 ++++-
kernel/sched/sched.h | 14 --------------
2 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b173a059315c..43ddfc25af99 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7447,7 +7447,7 @@ static inline int sched_balance_find_dst_cpu(struct sched_domain *sd, struct tas
static inline int __select_idle_cpu(int cpu, struct task_struct *p)
{
if ((available_idle_cpu(cpu) || sched_idle_cpu(cpu)) &&
- sched_cpu_cookie_match(cpu_rq(cpu), p))
+ sched_core_cookie_match(cpu_rq(cpu), p))
return cpu;
return -1;
@@ -7546,6 +7546,9 @@ static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int t
{
int cpu;
+ if (!sched_core_cookie_match(cpu_rq(target), p))
+ return -1;
+
for_each_cpu_and(cpu, cpu_smt_mask(target), p->cpus_ptr) {
if (cpu == target)
continue;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index be9745d104f7..4e7080123a4c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1386,15 +1386,6 @@ extern void task_vruntime_update(struct rq *rq, struct task_struct *p, bool in_f
* A special case is that the task's cookie always matches with CPU's core
* cookie if the CPU is in an idle core.
*/
-static inline bool sched_cpu_cookie_match(struct rq *rq, struct task_struct *p)
-{
- /* Ignore cookie match if core scheduler is not enabled on the CPU. */
- if (!sched_core_enabled(rq))
- return true;
-
- return rq->core->core_cookie == p->core_cookie;
-}
-
static inline bool sched_core_cookie_match(struct rq *rq, struct task_struct *p)
{
bool idle_core = true;
@@ -1468,11 +1459,6 @@ static inline raw_spinlock_t *__rq_lockp(struct rq *rq)
return &rq->__lock;
}
-static inline bool sched_cpu_cookie_match(struct rq *rq, struct task_struct *p)
-{
- return true;
-}
-
static inline bool sched_core_cookie_match(struct rq *rq, struct task_struct *p)
{
return true;
--
2.43.0
Amazon Development Centre (South Africa) (Proprietary) Limited
29 Gogosoa Street, Observatory, Cape Town, Western Cape, 7925, South Africa
Registration Number: 2004 / 034463 / 07
Hello Fernand, On 9/22/2025 6:09 PM, Fernand Sieber wrote: > @@ -7447,7 +7447,7 @@ static inline int sched_balance_find_dst_cpu(struct sched_domain *sd, struct tas > static inline int __select_idle_cpu(int cpu, struct task_struct *p) > { > if ((available_idle_cpu(cpu) || sched_idle_cpu(cpu)) && > - sched_cpu_cookie_match(cpu_rq(cpu), p)) > + sched_core_cookie_match(cpu_rq(cpu), p)) __select_idle_cpu() is only called when "has_idle_core" is false which means it is highly unlikely we'll find an idle core. In such cases, just matching the cookie should be sufficient right? Do you have any benchmark numbers which shows a large difference with these changes? > return cpu; > > return -1; > @@ -7546,6 +7546,9 @@ static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int t > { > int cpu; > > + if (!sched_core_cookie_match(cpu_rq(target), p)) > + return -1; > + select_idle_smt() is again called when "has_idle_core" is false and sched_cpu_cookie_match() should be sufficient for most part here too. > for_each_cpu_and(cpu, cpu_smt_mask(target), p->cpus_ptr) { > if (cpu == target) > continue; -- Thanks and Regards, Prateek
© 2016 - 2025 Red Hat, Inc.