[PATCH 10/18 v2] sched/fair: Add force push task mechanism for fair
From: Vincent Guittot
Date: Fri Oct 02 2026 - 11:46:40 EST
When the task is alone on the CPU, it's never put back in the enqueued
list; In this special case, we use the tick to run the check used to push
runnable task on a btter CPU.
Signed-off-by: Vincent Guittot <vincent.guittot@xxxxxxxxxx>
---
kernel/sched/fair.c | 71 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 483ed5807dfc..6ed3e5bb7fd6 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -9955,6 +9955,71 @@ static void fair_add_pushable_prev(struct rq *rq, struct task_struct *prev, stru
__fair_add_pushable_task(rq, prev);
}
+static int active_load_balance_cpu_stop(void *data);
+
+/*
+ * See if the alone task running on the CPU should migrate on a better than
+ * the local one.
+ */
+static inline bool tick_pushable_task(struct task_struct *p, struct rq *rq, struct rq_flags *rf)
+{
+ int new_cpu, cpu = cpu_of(rq);
+
+ if (!sched_push_task_enabled())
+ return false;
+
+ if (!rf)
+ return false;
+
+ if (WARN_ON(!p))
+ return false;
+
+ if (WARN_ON(!task_current(rq, p)))
+ return false;
+
+ if (is_migration_disabled(p))
+ return false;
+
+ /* If there are several task, wait for being put back */
+ if (rq->nr_running > 1)
+ return false;
+
+ if (!fair_check_pushable_task(rq, p, NULL))
+ return false;
+
+ if (!raw_spin_trylock(&p->pi_lock))
+ return false;
+
+ new_cpu = select_task_rq_fair(p, cpu, 0);
+
+ raw_spin_unlock(&p->pi_lock);
+
+ if (new_cpu == cpu)
+ return false;
+
+ /*
+ * ->active_balance synchronizes accesses to
+ * ->active_balance_work. Once set, it's cleared
+ * only after active load balance is finished.
+ */
+ if (!rq->active_balance) {
+ rq->active_balance = 1;
+ rq->push_cpu = new_cpu;
+ } else {
+ return false;
+ }
+
+ preempt_disable();
+ rq_unlock(rq, rf);
+ stop_one_cpu_nowait(cpu,
+ active_load_balance_cpu_stop, rq,
+ &rq->active_balance_work);
+ preempt_enable();
+ rq_lock(rq, rf);
+
+ return true;
+}
+
/*
* select_task_rq_fair: Select a target runqueue for the task.
* There are 2 ways to select the target runqueue:
@@ -15373,8 +15438,10 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, struct rq_fl
task_tick_cache(rq, curr);
- update_misfit_status(curr, rq);
- check_update_overutilized_status(task_rq(curr));
+ if (!tick_pushable_task(curr, rq, rf)) {
+ update_misfit_status(curr, rq);
+ check_update_overutilized_status(task_rq(curr));
+ }
task_tick_core(rq, curr);
}
--
2.53.0