Re: [PATCH 4/5] sched/fair: Reject misfit pulls onto busy SMT siblings on asym-capacity

From: Vincent Guittot

Date: Mon May 11 2026 - 09:17:15 EST


On Sat, 9 May 2026 at 20:10, Andrea Righi <arighi@xxxxxxxxxx> wrote:
>
> When SD_ASYM_CPUCAPACITY load balancing considers pulling a misfit task,
> capacity_of(dst_cpu) can overstate available compute if the SMT sibling is
> busy: the core does not deliver its full nominal capacity.
>
> If SMT is active and dst_cpu is not on a fully idle core, skip this
> destination so we do not migrate a misfit expecting a capacity upgrade we
> cannot actually provide.
>
> Cc: Vincent Guittot <vincent.guittot@xxxxxxxxxx>
> Cc: Dietmar Eggemann <dietmar.eggemann@xxxxxxx>
> Cc: Christian Loehle <christian.loehle@xxxxxxx>
> Cc: Koba Ko <kobak@xxxxxxxxxx>
> Cc: K Prateek Nayak <kprateek.nayak@xxxxxxx>
> Reported-by: Felix Abecassis <fabecassis@xxxxxxxxxx>
> Signed-off-by: Andrea Righi <arighi@xxxxxxxxxx>

Reviewed-by: Vincent Guittot <vincent.guittot@xxxxxxxxxx>


> ---
> kernel/sched/fair.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 6f0835c15ee11..2ddba8bd27e59 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -9693,6 +9693,7 @@ struct lb_env {
>
> int dst_cpu;
> struct rq *dst_rq;
> + bool dst_core_idle;
>
> struct cpumask *dst_grpmask;
> int new_dst_cpu;
> @@ -10918,10 +10919,16 @@ static bool update_sd_pick_busiest(struct lb_env *env,
> * We can use max_capacity here as reduction in capacity on some
> * CPUs in the group should either be possible to resolve
> * internally or be covered by avg_load imbalance (eventually).
> + *
> + * When SMT is active, only pull a misfit to dst_cpu if it is on a
> + * fully idle core; otherwise the effective capacity of the core is
> + * reduced and we may not actually provide more capacity than the
> + * source.
> */
> if ((env->sd->flags & SD_ASYM_CPUCAPACITY) &&
> (sgs->group_type == group_misfit_task) &&
> - (!capacity_greater(capacity_of(env->dst_cpu), sg->sgc->max_capacity) ||
> + (!env->dst_core_idle ||
> + !capacity_greater(capacity_of(env->dst_cpu), sg->sgc->max_capacity) ||
> sds->local_stat.group_type != group_has_spare))
> return false;
>
> @@ -11485,6 +11492,8 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd
> unsigned long sum_util = 0;
> bool sg_overloaded = 0, sg_overutilized = 0;
>
> + env->dst_core_idle = !sched_smt_active() || is_core_idle(env->dst_cpu);
> +
> do {
> struct sg_lb_stats *sgs = &tmp_sgs;
> int local_group;
> --
> 2.54.0
>