Skip to content

Commit 0e9619f

Browse files
vingu-linarogregkh
authored andcommitted
sched/cpufreq: Move the cfs_rq_util_change() call to cpufreq_update_util()
[ Upstream commit bef69dd ] update_cfs_rq_load_avg() calls cfs_rq_util_change() every time PELT decays, which might be inefficient when the cpufreq driver has rate limitation. When a task is attached on a CPU, we have this call path: update_load_avg() update_cfs_rq_load_avg() cfs_rq_util_change -- > trig frequency update attach_entity_load_avg() cfs_rq_util_change -- > trig frequency update The 1st frequency update will not take into account the utilization of the newly attached task and the 2nd one might be discarded because of rate limitation of the cpufreq driver. update_cfs_rq_load_avg() is only called by update_blocked_averages() and update_load_avg() so we can move the call to cfs_rq_util_change/cpufreq_update_util() into these two functions. It's also interesting to note that update_load_avg() already calls cfs_rq_util_change() directly for the !SMP case. This change will also ensure that cpufreq_update_util() is called even when there is no more CFS rq in the leaf_cfs_rq_list to update, but only IRQ, RT or DL PELT signals. [ mingo: Minor updates. ] Reported-by: Doug Smythies <dsmythies@telus.net> Tested-by: Doug Smythies <dsmythies@telus.net> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: juri.lelli@redhat.com Cc: linux-pm@vger.kernel.org Cc: mgorman@suse.de Cc: rostedt@goodmis.org Cc: sargun@sargun.me Cc: srinivas.pandruvada@linux.intel.com Cc: tj@kernel.org Cc: xiexiuqi@huawei.com Cc: xiezhipeng1@huawei.com Fixes: 039ae8b ("sched/fair: Fix O(nr_cgroups) in the load balancing path") Link: https://lkml.kernel.org/r/1574083279-799-1-git-send-email-vincent.guittot@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e0e2379 commit 0e9619f

1 file changed

Lines changed: 62 additions & 49 deletions

File tree

kernel/sched/fair.c

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3504,9 +3504,6 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
35043504
cfs_rq->load_last_update_time_copy = sa->last_update_time;
35053505
#endif
35063506

3507-
if (decayed)
3508-
cfs_rq_util_change(cfs_rq, 0);
3509-
35103507
return decayed;
35113508
}
35123509

@@ -3616,8 +3613,12 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
36163613
attach_entity_load_avg(cfs_rq, se, SCHED_CPUFREQ_MIGRATION);
36173614
update_tg_load_avg(cfs_rq, 0);
36183615

3619-
} else if (decayed && (flags & UPDATE_TG))
3620-
update_tg_load_avg(cfs_rq, 0);
3616+
} else if (decayed) {
3617+
cfs_rq_util_change(cfs_rq, 0);
3618+
3619+
if (flags & UPDATE_TG)
3620+
update_tg_load_avg(cfs_rq, 0);
3621+
}
36213622
}
36223623

36233624
#ifndef CONFIG_64BIT
@@ -7517,6 +7518,28 @@ static inline bool others_have_blocked(struct rq *rq) { return false; }
75177518
static inline void update_blocked_load_status(struct rq *rq, bool has_blocked) {}
75187519
#endif
75197520

7521+
static bool __update_blocked_others(struct rq *rq, bool *done)
7522+
{
7523+
const struct sched_class *curr_class;
7524+
u64 now = rq_clock_pelt(rq);
7525+
bool decayed;
7526+
7527+
/*
7528+
* update_load_avg() can call cpufreq_update_util(). Make sure that RT,
7529+
* DL and IRQ signals have been updated before updating CFS.
7530+
*/
7531+
curr_class = rq->curr->sched_class;
7532+
7533+
decayed = update_rt_rq_load_avg(now, rq, curr_class == &rt_sched_class) |
7534+
update_dl_rq_load_avg(now, rq, curr_class == &dl_sched_class) |
7535+
update_irq_load_avg(rq, 0);
7536+
7537+
if (others_have_blocked(rq))
7538+
*done = false;
7539+
7540+
return decayed;
7541+
}
7542+
75207543
#ifdef CONFIG_FAIR_GROUP_SCHED
75217544

75227545
static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
@@ -7536,29 +7559,11 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
75367559
return true;
75377560
}
75387561

7539-
static void update_blocked_averages(int cpu)
7562+
static bool __update_blocked_fair(struct rq *rq, bool *done)
75407563
{
7541-
struct rq *rq = cpu_rq(cpu);
75427564
struct cfs_rq *cfs_rq, *pos;
7543-
const struct sched_class *curr_class;
7544-
struct rq_flags rf;
7545-
bool done = true;
7546-
7547-
rq_lock_irqsave(rq, &rf);
7548-
update_rq_clock(rq);
7549-
7550-
/*
7551-
* update_cfs_rq_load_avg() can call cpufreq_update_util(). Make sure
7552-
* that RT, DL and IRQ signals have been updated before updating CFS.
7553-
*/
7554-
curr_class = rq->curr->sched_class;
7555-
update_rt_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &rt_sched_class);
7556-
update_dl_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &dl_sched_class);
7557-
update_irq_load_avg(rq, 0);
7558-
7559-
/* Don't need periodic decay once load/util_avg are null */
7560-
if (others_have_blocked(rq))
7561-
done = false;
7565+
bool decayed = false;
7566+
int cpu = cpu_of(rq);
75627567

75637568
/*
75647569
* Iterates the task_group tree in a bottom up fashion, see
@@ -7567,9 +7572,13 @@ static void update_blocked_averages(int cpu)
75677572
for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
75687573
struct sched_entity *se;
75697574

7570-
if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq))
7575+
if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
75717576
update_tg_load_avg(cfs_rq, 0);
75727577

7578+
if (cfs_rq == &rq->cfs)
7579+
decayed = true;
7580+
}
7581+
75737582
/* Propagate pending load changes to the parent, if any: */
75747583
se = cfs_rq->tg->se[cpu];
75757584
if (se && !skip_blocked_update(se))
@@ -7584,11 +7593,10 @@ static void update_blocked_averages(int cpu)
75847593

75857594
/* Don't need periodic decay once load/util_avg are null */
75867595
if (cfs_rq_has_blocked(cfs_rq))
7587-
done = false;
7596+
*done = false;
75887597
}
75897598

7590-
update_blocked_load_status(rq, !done);
7591-
rq_unlock_irqrestore(rq, &rf);
7599+
return decayed;
75927600
}
75937601

75947602
/*
@@ -7638,29 +7646,16 @@ static unsigned long task_h_load(struct task_struct *p)
76387646
cfs_rq_load_avg(cfs_rq) + 1);
76397647
}
76407648
#else
7641-
static inline void update_blocked_averages(int cpu)
7649+
static bool __update_blocked_fair(struct rq *rq, bool *done)
76427650
{
7643-
struct rq *rq = cpu_rq(cpu);
76447651
struct cfs_rq *cfs_rq = &rq->cfs;
7645-
const struct sched_class *curr_class;
7646-
struct rq_flags rf;
7647-
7648-
rq_lock_irqsave(rq, &rf);
7649-
update_rq_clock(rq);
7650-
7651-
/*
7652-
* update_cfs_rq_load_avg() can call cpufreq_update_util(). Make sure
7653-
* that RT, DL and IRQ signals have been updated before updating CFS.
7654-
*/
7655-
curr_class = rq->curr->sched_class;
7656-
update_rt_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &rt_sched_class);
7657-
update_dl_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &dl_sched_class);
7658-
update_irq_load_avg(rq, 0);
7652+
bool decayed;
76597653

7660-
update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq);
7654+
decayed = update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq);
7655+
if (cfs_rq_has_blocked(cfs_rq))
7656+
*done = false;
76617657

7662-
update_blocked_load_status(rq, cfs_rq_has_blocked(cfs_rq) || others_have_blocked(rq));
7663-
rq_unlock_irqrestore(rq, &rf);
7658+
return decayed;
76647659
}
76657660

76667661
static unsigned long task_h_load(struct task_struct *p)
@@ -7669,6 +7664,24 @@ static unsigned long task_h_load(struct task_struct *p)
76697664
}
76707665
#endif
76717666

7667+
static void update_blocked_averages(int cpu)
7668+
{
7669+
bool decayed = false, done = true;
7670+
struct rq *rq = cpu_rq(cpu);
7671+
struct rq_flags rf;
7672+
7673+
rq_lock_irqsave(rq, &rf);
7674+
update_rq_clock(rq);
7675+
7676+
decayed |= __update_blocked_others(rq, &done);
7677+
decayed |= __update_blocked_fair(rq, &done);
7678+
7679+
update_blocked_load_status(rq, !done);
7680+
if (decayed)
7681+
cpufreq_update_util(rq, 0);
7682+
rq_unlock_irqrestore(rq, &rf);
7683+
}
7684+
76727685
/********** Helpers for find_busiest_group ************************/
76737686

76747687
/*

0 commit comments

Comments
 (0)