sched/fair: Reject misfit pulls onto busy SMT siblings on asym-capacity

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.

Reported-by: Felix Abecassis <fabecassis@nvidia.com>
Signed-off-by: Andrea Righi <arighi@nvidia.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Vincent Guittot <vincent.guittot@linaro.org>
Link: https://patch.msgid.link/20260509180955.1840064-5-arighi@nvidia.com
This commit is contained in:
Andrea Righi 2026-05-09 20:07:28 +02:00 committed by Peter Zijlstra
parent 25a32e400a
commit bf6aa72219

View File

@ -9625,6 +9625,7 @@ struct lb_env {
int dst_cpu;
struct rq *dst_rq;
bool dst_core_idle;
struct cpumask *dst_grpmask;
int new_dst_cpu;
@ -10850,10 +10851,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;
@ -11417,6 +11424,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;