Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sched/fair: fix case with reduced capacity CPU

The capacity of the CPU available for CFS tasks can be reduced because of
other activities running on the latter. In such case, it's worth trying to
move CFS tasks on a CPU with more available capacity.

The rework of the load balance has filtered the case when the CPU is
classified to be fully busy but its capacity is reduced.

Check if CPU's capacity is reduced while gathering load balance statistic
and classify it group_misfit_task instead of group_fully_busy so we can
try to move the load on another CPU.

Reported-by: David Chen <david.chen@nutanix.com>
Reported-by: Zhang Qiao <zhangqiao22@huawei.com>
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: David Chen <david.chen@nutanix.com>
Tested-by: Zhang Qiao <zhangqiao22@huawei.com>
Link: https://lkml.kernel.org/r/20220708154401.21411-1-vincent.guittot@linaro.org

authored by

Vincent Guittot and committed by
Peter Zijlstra
c82a6962 c02d5546

+42 -12
+42 -12
kernel/sched/fair.c
··· 7711 7711 */ 7712 7712 group_fully_busy, 7713 7713 /* 7714 - * SD_ASYM_CPUCAPACITY only: One task doesn't fit with CPU's capacity 7715 - * and must be migrated to a more powerful CPU. 7714 + * One task doesn't fit with CPU's capacity and must be migrated to a 7715 + * more powerful CPU. 7716 7716 */ 7717 7717 group_misfit_task, 7718 7718 /* ··· 8798 8798 return sched_asym_prefer(env->dst_cpu, group->asym_prefer_cpu); 8799 8799 } 8800 8800 8801 + static inline bool 8802 + sched_reduced_capacity(struct rq *rq, struct sched_domain *sd) 8803 + { 8804 + /* 8805 + * When there is more than 1 task, the group_overloaded case already 8806 + * takes care of cpu with reduced capacity 8807 + */ 8808 + if (rq->cfs.h_nr_running != 1) 8809 + return false; 8810 + 8811 + return check_cpu_capacity(rq, sd); 8812 + } 8813 + 8801 8814 /** 8802 8815 * update_sg_lb_stats - Update sched_group's statistics for load balancing. 8803 8816 * @env: The load balancing environment. ··· 8833 8820 8834 8821 for_each_cpu_and(i, sched_group_span(group), env->cpus) { 8835 8822 struct rq *rq = cpu_rq(i); 8823 + unsigned long load = cpu_load(rq); 8836 8824 8837 - sgs->group_load += cpu_load(rq); 8825 + sgs->group_load += load; 8838 8826 sgs->group_util += cpu_util_cfs(i); 8839 8827 sgs->group_runnable += cpu_runnable(rq); 8840 8828 sgs->sum_h_nr_running += rq->cfs.h_nr_running; ··· 8865 8851 if (local_group) 8866 8852 continue; 8867 8853 8868 - /* Check for a misfit task on the cpu */ 8869 - if (env->sd->flags & SD_ASYM_CPUCAPACITY && 8870 - sgs->group_misfit_task_load < rq->misfit_task_load) { 8871 - sgs->group_misfit_task_load = rq->misfit_task_load; 8872 - *sg_status |= SG_OVERLOAD; 8854 + if (env->sd->flags & SD_ASYM_CPUCAPACITY) { 8855 + /* Check for a misfit task on the cpu */ 8856 + if (sgs->group_misfit_task_load < rq->misfit_task_load) { 8857 + sgs->group_misfit_task_load = rq->misfit_task_load; 8858 + *sg_status |= SG_OVERLOAD; 8859 + } 8860 + } else if ((env->idle != CPU_NOT_IDLE) && 8861 + sched_reduced_capacity(rq, env->sd)) { 8862 + /* Check for a task running on a CPU with reduced capacity */ 8863 + if (sgs->group_misfit_task_load < load) 8864 + sgs->group_misfit_task_load = load; 8873 8865 } 8874 8866 } 8875 8867 ··· 8928 8908 * CPUs in the group should either be possible to resolve 8929 8909 * internally or be covered by avg_load imbalance (eventually). 8930 8910 */ 8931 - if (sgs->group_type == group_misfit_task && 8911 + if ((env->sd->flags & SD_ASYM_CPUCAPACITY) && 8912 + (sgs->group_type == group_misfit_task) && 8932 8913 (!capacity_greater(capacity_of(env->dst_cpu), sg->sgc->max_capacity) || 8933 8914 sds->local_stat.group_type != group_has_spare)) 8934 8915 return false; ··· 9538 9517 busiest = &sds->busiest_stat; 9539 9518 9540 9519 if (busiest->group_type == group_misfit_task) { 9541 - /* Set imbalance to allow misfit tasks to be balanced. */ 9542 - env->migration_type = migrate_misfit; 9543 - env->imbalance = 1; 9520 + if (env->sd->flags & SD_ASYM_CPUCAPACITY) { 9521 + /* Set imbalance to allow misfit tasks to be balanced. */ 9522 + env->migration_type = migrate_misfit; 9523 + env->imbalance = 1; 9524 + } else { 9525 + /* 9526 + * Set load imbalance to allow moving task from cpu 9527 + * with reduced capacity. 9528 + */ 9529 + env->migration_type = migrate_load; 9530 + env->imbalance = busiest->group_misfit_task_load; 9531 + } 9544 9532 return; 9545 9533 } 9546 9534