Re: [PATCH v9 06/11] sched/core: Push current task from non preferred CPU
Shrikanth Hegde <[email protected]> Mon, 27 Jul 2026 14:25:35 +0530
| Newsgroups | dev.linux.lists.virtualization,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Hi Yury, On 7/25/26 3:34 AM, Yury Norov wrote: > On Fri, Jul 24, 2026 at 07:37:27PM +0530, Shrikanth Hegde wrote: >> Actively push out task running on a non-preferred CPU. Since the task is >> running on the CPU, need to stop the cpu and push the task out. >> However, if the task is pinned only to non-preferred CPUs, it will continue >> running there. This will help in maintaining the userspace affinities >> unlike CPU hotplug or isolated cpusets. >> >> Though code is similar to __balance_push_cpu_stop and quite close to >> push_cpu_stop, it is being kept separate as it provides a cleaner >> implementation with CONFIG_PREFERRED_CPU. >> >> Add push_task_work_done flag to protect work buffer. >> Works only with FAIR class. >> >> For now, only current running task is pushed out. This keeps the code >> simpler. In future optimization maybe done to move all the queued >> task on the rq. >> >> Signed-off-by: Shrikanth Hegde <[email protected]> >> --- >> kernel/sched/core.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ >> kernel/sched/sched.h | 8 +++++ >> 2 files changed, 86 insertions(+) >> >> diff --git a/kernel/sched/core.c b/kernel/sched/core.c >> index 9e8eec4451b6..704043531b24 100644 >> --- a/kernel/sched/core.c >> +++ b/kernel/sched/core.c >> @@ -5774,6 +5774,9 @@ void sched_tick(void) >> unsigned long hw_pressure; >> u64 resched_latency; >> >> + if (!cpu_preferred(cpu)) >> + sched_push_current_non_preferred_cpu(rq); >> + >> if (housekeeping_cpu(cpu, HK_TYPE_KERNEL_NOISE)) >> arch_scale_freq_tick(); >> >> @@ -11292,3 +11295,78 @@ void sched_change_end(struct sched_change_ctx *ctx) >> p->sched_class->prio_changed(rq, p, ctx->prio); >> } >> } >> + >> +#ifdef CONFIG_PREFERRED_CPU >> +static DEFINE_PER_CPU(struct cpu_stop_work, npc_push_task_work); >> + >> +static int sched_non_preferred_cpu_push_stop(void *arg) >> +{ >> + struct task_struct *p = arg; >> + struct rq *rq = this_rq(); >> + struct rq_flags rf; >> + int cpu; >> + >> + if (cpu_preferred(rq->cpu)) { >> + scoped_guard(rq_lock, rq) >> + rq->push_task_work_done = false; >> + put_task_struct(p); >> + return 0; >> + } >> + >> + raw_spin_lock_irq(&p->pi_lock); >> + >> + /* This could take rq lock. So call it before rq lock is taken */ >> + cpu = select_fallback_rq(rq->cpu, p); >> + rq_lock(rq, &rf); >> + rq->push_task_work_done = false; >> + update_rq_clock(rq); >> + >> + context_unsafe_alias(rq); >> + >> + if (task_rq(p) == rq && task_on_rq_queued(p) && >> + !is_migration_disabled(p)) >> + rq = __migrate_task(rq, &rf, p, cpu); >> + >> + rq_unlock(rq, &rf); >> + raw_spin_unlock_irq(&p->pi_lock); >> + put_task_struct(p); >> + >> + return 0; > > You always return 0, and don't test the return value. Just make it > void, or return (and handle) some error, please. > Currently all the function callbacks of stop_one_cpu_nowait return 0. This can't be changed to void today since signature mandates int. typedef int (*cpu_stop_fn_t)(void *arg); Also even if return value is of some error, it doesn't make any difference. This is because in cpu_stopper_thread, return value is propagated only if it wait for work to complete semantic. stop_one_cpu_nowait sets done=NULL. bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, struct cpu_stop_work *work_buf) { *work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, .caller = _RET_IP_, }; return cpu_stop_queue_work(cpu, work_buf); } cpu_stopper_thread: ret = fn(arg); if (done) { if (ret) done->ret = ret; cpu_stop_signal_done(done); } If we really need to return void then we need a new function signature for nowait variant. Adding separate function signature just for nowait isn't probably worth. What do you think?