On Fri, Jul 24, 2026 at 07:37:26PM +0530, Shrikanth Hegde wrote:
> When cpu is marked as non preferred, any load pulled towards it is
> pointless since in the next tick task will be pushed out again.
> So, Consider only preferred CPUs for load balance.
> 
> This makes it not fight against the push task mechanism which happens
> at tick. Also, this stops active balance to happen on non-preferred CPU
> pulling the load.
> 
> This means there is no load balancing if the task is pinned only to
> non-preferred CPUs. They will continue to run where they were previously
> running before the CPUs was marked as non-preferred.
> 
> Bailout early for NEWIDLE and IDLE balance as load balancing is done
> only on preferred CPUs.
> 
> Signed-off-by: Shrikanth Hegde <[email protected]>
> ---
>  kernel/sched/fair.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index df8c9c2c7918..12f5b7de28d2 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -13399,7 +13399,7 @@ static int sched_balance_rq(int this_cpu, struct rq 
> *this_rq,
>       };
>       bool need_unlock = false;
>  
> -     cpumask_and(cpus, sched_domain_span(sd), cpu_active_mask);
> +     cpumask_and(cpus, sched_domain_span(sd), cpu_preferred_mask);
>  
>       schedstat_inc(sd->lb_count[idle]);
>  
> @@ -14337,7 +14337,8 @@ static void _nohz_idle_balance(struct rq *this_rq, 
> unsigned int flags)
>                       update_rq_clock(rq);
>                       rq_unlock_irqrestore(rq, &rf);
>  
> -                     if (flags & NOHZ_BALANCE_KICK)
> +                     if (flags & NOHZ_BALANCE_KICK &&
> +                         cpu_preferred(balance_cpu))
>                               sched_balance_domains(rq, CPU_IDLE);

Here you skip the sched_balance_domains() for idle non-preferred CPUs,
which means you don't re-calculate the rq->next_balance.

In the following code, we update the global nohz.next_balance
depending on the new rq->next_balance, which doesn't happen if
the sched_balance_domains() is not invoked.

So, you propagate an already-expired per-CPU deadline back into the
global NOHZ deadline. It may lead to unneeded asynchronous IPI in the
nohz_balancer_kick() -> kick_ilb() path.

I think, you need another helper, something like:

        void sched_balance_domains(rq, idle)
        {
                __sched_balance_domains(rq, idle);
                advance_rq_next_balance(rq, idle);
        }

And then in the code above:

        if (flags & NOHZ_BALANCE_KICK) {
                if (cpu_preferred(balance_cpu))
                        __sched_balance_domains(rq, CPU_IDLE);

                advance_rq_next_balance(rq, idle);
        }

> @@ -14481,10 +14482,8 @@ static int sched_balance_newidle(struct rq *this_rq, 
> struct rq_flags *rf)
>        */
>       this_rq->idle_stamp = rq_clock(this_rq);
>  
> -     /*
> -      * Do not pull tasks towards !active CPUs...
> -      */
> -     if (!cpu_active(this_cpu))
> +     /* Do not pull tasks towards !preferred CPUs */
> +     if (!cpu_preferred(this_cpu))
>               return 0;
>  
>       /*
> -- 
> 2.47.3

Reply via email to