sched: Fix poor interactivity on UP systems due to group scheduler nice tune bug
Michael Witten and Christian Kujau reported that the autogroup scheduling feature hurts interactivity on their UP systems. It turns out that this is an older bug in the group scheduling code, and the wider appeal provided by the autogroup feature exposed it more prominently. When on UP with FAIR_GROUP_SCHED enabled, tune shares only affect tg->shares, but is not reflected in tg->se->load. The reason is that update_cfs_shares() does nothing on UP. So introduce update_cfs_shares() for UP && FAIR_GROUP_SCHED. This issue was found when enable autogroup scheduling was enabled, but it is an older bug that also exists on cgroup.cpu on UP. Reported-and-Tested-by: Michael Witten <mfwitten@gmail.com> Reported-and-Tested-by: Christian Kujau <christian@nerdbynature.de> Signed-off-by: Yong Zhang <yong.zhang0@gmail.com> Acked-by: Pekka Enberg <penberg@kernel.org> Acked-by: Mike Galbraith <efault@gmx.de> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> LKML-Reference: <20110124073352.GA24186@windriver.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
1bae4ce27c
commit
3ff6dcac73
|
@ -699,7 +699,8 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
||||||
cfs_rq->nr_running--;
|
cfs_rq->nr_running--;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||||||
|
# ifdef CONFIG_SMP
|
||||||
static void update_cfs_rq_load_contribution(struct cfs_rq *cfs_rq,
|
static void update_cfs_rq_load_contribution(struct cfs_rq *cfs_rq,
|
||||||
int global_update)
|
int global_update)
|
||||||
{
|
{
|
||||||
|
@ -762,6 +763,51 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
|
||||||
list_del_leaf_cfs_rq(cfs_rq);
|
list_del_leaf_cfs_rq(cfs_rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
|
||||||
|
long weight_delta)
|
||||||
|
{
|
||||||
|
long load_weight, load, shares;
|
||||||
|
|
||||||
|
load = cfs_rq->load.weight + weight_delta;
|
||||||
|
|
||||||
|
load_weight = atomic_read(&tg->load_weight);
|
||||||
|
load_weight -= cfs_rq->load_contribution;
|
||||||
|
load_weight += load;
|
||||||
|
|
||||||
|
shares = (tg->shares * load);
|
||||||
|
if (load_weight)
|
||||||
|
shares /= load_weight;
|
||||||
|
|
||||||
|
if (shares < MIN_SHARES)
|
||||||
|
shares = MIN_SHARES;
|
||||||
|
if (shares > tg->shares)
|
||||||
|
shares = tg->shares;
|
||||||
|
|
||||||
|
return shares;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
|
||||||
|
{
|
||||||
|
if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
|
||||||
|
update_cfs_load(cfs_rq, 0);
|
||||||
|
update_cfs_shares(cfs_rq, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# else /* CONFIG_SMP */
|
||||||
|
static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
|
||||||
|
long weight_delta)
|
||||||
|
{
|
||||||
|
return tg->shares;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
# endif /* CONFIG_SMP */
|
||||||
static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
|
static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
|
||||||
unsigned long weight)
|
unsigned long weight)
|
||||||
{
|
{
|
||||||
|
@ -782,7 +828,7 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
|
||||||
{
|
{
|
||||||
struct task_group *tg;
|
struct task_group *tg;
|
||||||
struct sched_entity *se;
|
struct sched_entity *se;
|
||||||
long load_weight, load, shares;
|
long shares;
|
||||||
|
|
||||||
if (!cfs_rq)
|
if (!cfs_rq)
|
||||||
return;
|
return;
|
||||||
|
@ -791,32 +837,14 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
|
||||||
se = tg->se[cpu_of(rq_of(cfs_rq))];
|
se = tg->se[cpu_of(rq_of(cfs_rq))];
|
||||||
if (!se)
|
if (!se)
|
||||||
return;
|
return;
|
||||||
|
#ifndef CONFIG_SMP
|
||||||
load = cfs_rq->load.weight + weight_delta;
|
if (likely(se->load.weight == tg->shares))
|
||||||
|
return;
|
||||||
load_weight = atomic_read(&tg->load_weight);
|
#endif
|
||||||
load_weight -= cfs_rq->load_contribution;
|
shares = calc_cfs_shares(cfs_rq, tg, weight_delta);
|
||||||
load_weight += load;
|
|
||||||
|
|
||||||
shares = (tg->shares * load);
|
|
||||||
if (load_weight)
|
|
||||||
shares /= load_weight;
|
|
||||||
|
|
||||||
if (shares < MIN_SHARES)
|
|
||||||
shares = MIN_SHARES;
|
|
||||||
if (shares > tg->shares)
|
|
||||||
shares = tg->shares;
|
|
||||||
|
|
||||||
reweight_entity(cfs_rq_of(se), se, shares);
|
reweight_entity(cfs_rq_of(se), se, shares);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
|
|
||||||
{
|
|
||||||
if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
|
|
||||||
update_cfs_load(cfs_rq, 0);
|
|
||||||
update_cfs_shares(cfs_rq, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else /* CONFIG_FAIR_GROUP_SCHED */
|
#else /* CONFIG_FAIR_GROUP_SCHED */
|
||||||
static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
|
static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue