| From c19d56fb938b1c461653f3801f301df2befecdb9 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 14 Apr 2022 17:02:20 +0800 |
| Subject: sched/pelt: Fix attach_entity_load_avg() corner case |
| |
| From: kuyo chang <kuyo.chang@mediatek.com> |
| |
| [ Upstream commit 40f5aa4c5eaebfeaca4566217cb9c468e28ed682 ] |
| |
| The warning in cfs_rq_is_decayed() triggered: |
| |
| SCHED_WARN_ON(cfs_rq->avg.load_avg || |
| cfs_rq->avg.util_avg || |
| cfs_rq->avg.runnable_avg) |
| |
| There exists a corner case in attach_entity_load_avg() which will |
| cause load_sum to be zero while load_avg will not be. |
| |
| Consider se_weight is 88761 as per the sched_prio_to_weight[] table. |
| Further assume the get_pelt_divider() is 47742, this gives: |
| se->avg.load_avg is 1. |
| |
| However, calculating load_sum: |
| |
| se->avg.load_sum = div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se)); |
| se->avg.load_sum = 1*47742/88761 = 0. |
| |
| Then enqueue_load_avg() adds this to the cfs_rq totals: |
| |
| cfs_rq->avg.load_avg += se->avg.load_avg; |
| cfs_rq->avg.load_sum += se_weight(se) * se->avg.load_sum; |
| |
| Resulting in load_avg being 1 with load_sum is 0, which will trigger |
| the WARN. |
| |
| Fixes: f207934fb79d ("sched/fair: Align PELT windows between cfs_rq and its se") |
| Signed-off-by: kuyo chang <kuyo.chang@mediatek.com> |
| [peterz: massage changelog] |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Reviewed-by: Vincent Guittot <vincent.guittot@linaro.org> |
| Tested-by: Dietmar Eggemann <dietmar.eggemann@arm.com> |
| Link: https://lkml.kernel.org/r/20220414090229.342-1-kuyo.chang@mediatek.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| kernel/sched/fair.c | 10 +++++----- |
| 1 file changed, 5 insertions(+), 5 deletions(-) |
| |
| diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c |
| index acd9833b8ec2..1a306ef51bbe 100644 |
| --- a/kernel/sched/fair.c |
| +++ b/kernel/sched/fair.c |
| @@ -3748,11 +3748,11 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s |
| |
| se->avg.runnable_sum = se->avg.runnable_avg * divider; |
| |
| - se->avg.load_sum = divider; |
| - if (se_weight(se)) { |
| - se->avg.load_sum = |
| - div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se)); |
| - } |
| + se->avg.load_sum = se->avg.load_avg * divider; |
| + if (se_weight(se) < se->avg.load_sum) |
| + se->avg.load_sum = div_u64(se->avg.load_sum, se_weight(se)); |
| + else |
| + se->avg.load_sum = 1; |
| |
| enqueue_load_avg(cfs_rq, se); |
| cfs_rq->avg.util_avg += se->avg.util_avg; |
| -- |
| 2.35.1 |
| |