Skip to content

Commit e33078b

Browse files
paulturnerIngo Molnar
authored andcommitted
sched: Fix update_cfs_load() synchronization
Using cfs_rq->nr_running is not sufficient to synchronize update_cfs_load with the put path since nr_running accounting occurs at deactivation. It's also not safe to make the removal decision based on load_avg as this fails with both high periods and low shares. Resolve this by clipping history after 4 periods without activity. Note: the above will always occur from update_shares() since in the last-task-sleep-case that task will still be cfs_rq->curr when update_cfs_load is called. Signed-off-by: Paul Turner <[email protected]> Signed-off-by: Peter Zijlstra <[email protected]> LKML-Reference: <[email protected]> Signed-off-by: Ingo Molnar <[email protected]>
1 parent f0d7442 commit e33078b

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

kernel/sched.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ struct cfs_rq {
355355

356356
u64 load_avg;
357357
u64 load_period;
358-
u64 load_stamp;
358+
u64 load_stamp, load_last;
359359

360360
unsigned long load_contribution;
361361
#endif

kernel/sched_fair.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -674,20 +674,31 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
674674
}
675675

676676
#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
677-
static void update_cfs_load(struct cfs_rq *cfs_rq, int lb)
677+
static void update_cfs_load(struct cfs_rq *cfs_rq)
678678
{
679679
u64 period = sched_avg_period();
680680
u64 now, delta;
681+
unsigned long load = cfs_rq->load.weight;
681682

682683
if (!cfs_rq)
683684
return;
684685

685686
now = rq_of(cfs_rq)->clock;
686687
delta = now - cfs_rq->load_stamp;
687688

689+
/* truncate load history at 4 idle periods */
690+
if (cfs_rq->load_stamp > cfs_rq->load_last &&
691+
now - cfs_rq->load_last > 4 * period) {
692+
cfs_rq->load_period = 0;
693+
cfs_rq->load_avg = 0;
694+
}
695+
688696
cfs_rq->load_stamp = now;
689697
cfs_rq->load_period += delta;
690-
cfs_rq->load_avg += delta * cfs_rq->load.weight;
698+
if (load) {
699+
cfs_rq->load_last = now;
700+
cfs_rq->load_avg += delta * load;
701+
}
691702

692703
while (cfs_rq->load_period > period) {
693704
/*
@@ -700,10 +711,8 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int lb)
700711
cfs_rq->load_avg /= 2;
701712
}
702713

703-
if (lb && !cfs_rq->nr_running) {
704-
if (cfs_rq->load_avg < (period / 8))
705-
list_del_leaf_cfs_rq(cfs_rq);
706-
}
714+
if (!cfs_rq->curr && !cfs_rq->nr_running && !cfs_rq->load_avg)
715+
list_del_leaf_cfs_rq(cfs_rq);
707716
}
708717

709718
static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
@@ -750,7 +759,7 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
750759
reweight_entity(cfs_rq_of(se), se, shares);
751760
}
752761
#else /* CONFIG_FAIR_GROUP_SCHED */
753-
static inline void update_cfs_load(struct cfs_rq *cfs_rq, int lb)
762+
static inline void update_cfs_load(struct cfs_rq *cfs_rq)
754763
{
755764
}
756765

@@ -880,7 +889,7 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
880889
* Update run-time statistics of the 'current'.
881890
*/
882891
update_curr(cfs_rq);
883-
update_cfs_load(cfs_rq, 0);
892+
update_cfs_load(cfs_rq);
884893
update_cfs_shares(cfs_rq, se->load.weight);
885894
account_entity_enqueue(cfs_rq, se);
886895

@@ -941,7 +950,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
941950
if (se != cfs_rq->curr)
942951
__dequeue_entity(cfs_rq, se);
943952
se->on_rq = 0;
944-
update_cfs_load(cfs_rq, 0);
953+
update_cfs_load(cfs_rq);
945954
account_entity_dequeue(cfs_rq, se);
946955
update_min_vruntime(cfs_rq);
947956
update_cfs_shares(cfs_rq, 0);
@@ -1176,7 +1185,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
11761185
for_each_sched_entity(se) {
11771186
struct cfs_rq *cfs_rq = cfs_rq_of(se);
11781187

1179-
update_cfs_load(cfs_rq, 0);
1188+
update_cfs_load(cfs_rq);
11801189
update_cfs_shares(cfs_rq, 0);
11811190
}
11821191

@@ -1206,7 +1215,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
12061215
for_each_sched_entity(se) {
12071216
struct cfs_rq *cfs_rq = cfs_rq_of(se);
12081217

1209-
update_cfs_load(cfs_rq, 0);
1218+
update_cfs_load(cfs_rq);
12101219
update_cfs_shares(cfs_rq, 0);
12111220
}
12121221

@@ -2023,7 +2032,7 @@ static int tg_shares_up(struct task_group *tg, int cpu)
20232032
raw_spin_lock_irqsave(&rq->lock, flags);
20242033

20252034
update_rq_clock(rq);
2026-
update_cfs_load(cfs_rq, 1);
2035+
update_cfs_load(cfs_rq);
20272036

20282037
load_avg = div64_u64(cfs_rq->load_avg, cfs_rq->load_period+1);
20292038
load_avg -= cfs_rq->load_contribution;

0 commit comments

Comments
 (0)