Skip to content

Commit

Permalink
sched/cpufreq: Move the cfs_rq_util_change() call to cpufreq_update_u…
Browse files Browse the repository at this point in the history
…til()

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 <[email protected]>
Tested-by: Doug Smythies <[email protected]>
Signed-off-by: Vincent Guittot <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Dietmar Eggemann <[email protected]>
Acked-by: Rafael J. Wysocki <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Fixes: 039ae8b ("sched/fair: Fix O(nr_cgroups) in the load balancing path")
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
vingu-linaro authored and Ingo Molnar committed Nov 18, 2019
1 parent b21feab commit bef69dd
Showing 1 changed file with 62 additions and 49 deletions.
111 changes: 62 additions & 49 deletions kernel/sched/fair.c
Original file line number Diff line number Diff line change
Expand Up @@ -3508,9 +3508,6 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
cfs_rq->load_last_update_time_copy = sa->last_update_time;
#endif

if (decayed)
cfs_rq_util_change(cfs_rq, 0);

return decayed;
}

Expand Down Expand Up @@ -3620,8 +3617,12 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
attach_entity_load_avg(cfs_rq, se, SCHED_CPUFREQ_MIGRATION);
update_tg_load_avg(cfs_rq, 0);

} else if (decayed && (flags & UPDATE_TG))
update_tg_load_avg(cfs_rq, 0);
} else if (decayed) {
cfs_rq_util_change(cfs_rq, 0);

if (flags & UPDATE_TG)
update_tg_load_avg(cfs_rq, 0);
}
}

#ifndef CONFIG_64BIT
Expand Down Expand Up @@ -7482,6 +7483,28 @@ static inline bool others_have_blocked(struct rq *rq) { return false; }
static inline void update_blocked_load_status(struct rq *rq, bool has_blocked) {}
#endif

static bool __update_blocked_others(struct rq *rq, bool *done)
{
const struct sched_class *curr_class;
u64 now = rq_clock_pelt(rq);
bool decayed;

/*
* update_load_avg() can call cpufreq_update_util(). Make sure that RT,
* DL and IRQ signals have been updated before updating CFS.
*/
curr_class = rq->curr->sched_class;

decayed = update_rt_rq_load_avg(now, rq, curr_class == &rt_sched_class) |
update_dl_rq_load_avg(now, rq, curr_class == &dl_sched_class) |
update_irq_load_avg(rq, 0);

if (others_have_blocked(rq))
*done = false;

return decayed;
}

#ifdef CONFIG_FAIR_GROUP_SCHED

static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
Expand All @@ -7501,29 +7524,11 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
return true;
}

static void update_blocked_averages(int cpu)
static bool __update_blocked_fair(struct rq *rq, bool *done)
{
struct rq *rq = cpu_rq(cpu);
struct cfs_rq *cfs_rq, *pos;
const struct sched_class *curr_class;
struct rq_flags rf;
bool done = true;

rq_lock_irqsave(rq, &rf);
update_rq_clock(rq);

/*
* update_cfs_rq_load_avg() can call cpufreq_update_util(). Make sure
* that RT, DL and IRQ signals have been updated before updating CFS.
*/
curr_class = rq->curr->sched_class;
update_rt_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &rt_sched_class);
update_dl_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &dl_sched_class);
update_irq_load_avg(rq, 0);

/* Don't need periodic decay once load/util_avg are null */
if (others_have_blocked(rq))
done = false;
bool decayed = false;
int cpu = cpu_of(rq);

/*
* Iterates the task_group tree in a bottom up fashion, see
Expand All @@ -7532,9 +7537,13 @@ static void update_blocked_averages(int cpu)
for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
struct sched_entity *se;

if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq))
if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
update_tg_load_avg(cfs_rq, 0);

if (cfs_rq == &rq->cfs)
decayed = true;
}

/* Propagate pending load changes to the parent, if any: */
se = cfs_rq->tg->se[cpu];
if (se && !skip_blocked_update(se))
Expand All @@ -7549,11 +7558,10 @@ static void update_blocked_averages(int cpu)

/* Don't need periodic decay once load/util_avg are null */
if (cfs_rq_has_blocked(cfs_rq))
done = false;
*done = false;
}

update_blocked_load_status(rq, !done);
rq_unlock_irqrestore(rq, &rf);
return decayed;
}

/*
Expand Down Expand Up @@ -7603,29 +7611,16 @@ static unsigned long task_h_load(struct task_struct *p)
cfs_rq_load_avg(cfs_rq) + 1);
}
#else
static inline void update_blocked_averages(int cpu)
static bool __update_blocked_fair(struct rq *rq, bool *done)
{
struct rq *rq = cpu_rq(cpu);
struct cfs_rq *cfs_rq = &rq->cfs;
const struct sched_class *curr_class;
struct rq_flags rf;

rq_lock_irqsave(rq, &rf);
update_rq_clock(rq);

/*
* update_cfs_rq_load_avg() can call cpufreq_update_util(). Make sure
* that RT, DL and IRQ signals have been updated before updating CFS.
*/
curr_class = rq->curr->sched_class;
update_rt_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &rt_sched_class);
update_dl_rq_load_avg(rq_clock_pelt(rq), rq, curr_class == &dl_sched_class);
update_irq_load_avg(rq, 0);
bool decayed;

update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq);
decayed = update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq);
if (cfs_rq_has_blocked(cfs_rq))
*done = false;

update_blocked_load_status(rq, cfs_rq_has_blocked(cfs_rq) || others_have_blocked(rq));
rq_unlock_irqrestore(rq, &rf);
return decayed;
}

static unsigned long task_h_load(struct task_struct *p)
Expand All @@ -7634,6 +7629,24 @@ static unsigned long task_h_load(struct task_struct *p)
}
#endif

static void update_blocked_averages(int cpu)
{
bool decayed = false, done = true;
struct rq *rq = cpu_rq(cpu);
struct rq_flags rf;

rq_lock_irqsave(rq, &rf);
update_rq_clock(rq);

decayed |= __update_blocked_others(rq, &done);
decayed |= __update_blocked_fair(rq, &done);

update_blocked_load_status(rq, !done);
if (decayed)
cpufreq_update_util(rq, 0);
rq_unlock_irqrestore(rq, &rf);
}

/********** Helpers for find_busiest_group ************************/

/*
Expand Down

0 comments on commit bef69dd

Please sign in to comment.