Commit c308b56b authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

sched: Fix nohz load accounting -- again!

Various people reported nohz load tracking still being wrecked, but Doug
spotted the actual problem. We fold the nohz remainder in too soon,
causing us to loose samples and under-account.

So instead of playing catch-up up-front, always do a single load-fold
with whatever state we encounter and only then fold the nohz remainder
and play catch-up.
Reported-by: default avatarDoug Smythies <dsmythies@telus.net>
Reported-by: default avatarLesÅ=82aw Kope=C4=87 <leslaw.kopec@nasza-klasa.pl>
Reported-by: default avatarAman Gupta <aman@tmm1.net>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/n/tip-4v31etnhgg9kwd6ocgx3rxl8@git.kernel.orgSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 8e3fabfd
...@@ -2266,13 +2266,10 @@ calc_load_n(unsigned long load, unsigned long exp, ...@@ -2266,13 +2266,10 @@ calc_load_n(unsigned long load, unsigned long exp,
* Once we've updated the global active value, we need to apply the exponential * Once we've updated the global active value, we need to apply the exponential
* weights adjusted to the number of cycles missed. * weights adjusted to the number of cycles missed.
*/ */
static void calc_global_nohz(unsigned long ticks) static void calc_global_nohz(void)
{ {
long delta, active, n; long delta, active, n;
if (time_before(jiffies, calc_load_update))
return;
/* /*
* If we crossed a calc_load_update boundary, make sure to fold * If we crossed a calc_load_update boundary, make sure to fold
* any pending idle changes, the respective CPUs might have * any pending idle changes, the respective CPUs might have
...@@ -2284,31 +2281,25 @@ static void calc_global_nohz(unsigned long ticks) ...@@ -2284,31 +2281,25 @@ static void calc_global_nohz(unsigned long ticks)
atomic_long_add(delta, &calc_load_tasks); atomic_long_add(delta, &calc_load_tasks);
/* /*
* If we were idle for multiple load cycles, apply them. * It could be the one fold was all it took, we done!
*/ */
if (ticks >= LOAD_FREQ) { if (time_before(jiffies, calc_load_update + 10))
n = ticks / LOAD_FREQ; return;
active = atomic_long_read(&calc_load_tasks); /*
active = active > 0 ? active * FIXED_1 : 0; * Catch-up, fold however many we are behind still
*/
delta = jiffies - calc_load_update - 10;
n = 1 + (delta / LOAD_FREQ);
avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n); active = atomic_long_read(&calc_load_tasks);
avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n); active = active > 0 ? active * FIXED_1 : 0;
avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
calc_load_update += n * LOAD_FREQ; avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
} avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
/* calc_load_update += n * LOAD_FREQ;
* Its possible the remainder of the above division also crosses
* a LOAD_FREQ period, the regular check in calc_global_load()
* which comes after this will take care of that.
*
* Consider us being 11 ticks before a cycle completion, and us
* sleeping for 4*LOAD_FREQ + 22 ticks, then the above code will
* age us 4 cycles, and the test in calc_global_load() will
* pick up the final one.
*/
} }
#else #else
void calc_load_account_idle(struct rq *this_rq) void calc_load_account_idle(struct rq *this_rq)
...@@ -2320,7 +2311,7 @@ static inline long calc_load_fold_idle(void) ...@@ -2320,7 +2311,7 @@ static inline long calc_load_fold_idle(void)
return 0; return 0;
} }
static void calc_global_nohz(unsigned long ticks) static void calc_global_nohz(void)
{ {
} }
#endif #endif
...@@ -2348,8 +2339,6 @@ void calc_global_load(unsigned long ticks) ...@@ -2348,8 +2339,6 @@ void calc_global_load(unsigned long ticks)
{ {
long active; long active;
calc_global_nohz(ticks);
if (time_before(jiffies, calc_load_update + 10)) if (time_before(jiffies, calc_load_update + 10))
return; return;
...@@ -2361,6 +2350,16 @@ void calc_global_load(unsigned long ticks) ...@@ -2361,6 +2350,16 @@ void calc_global_load(unsigned long ticks)
avenrun[2] = calc_load(avenrun[2], EXP_15, active); avenrun[2] = calc_load(avenrun[2], EXP_15, active);
calc_load_update += LOAD_FREQ; calc_load_update += LOAD_FREQ;
/*
* Account one period with whatever state we found before
* folding in the nohz state and ageing the entire idle period.
*
* This avoids loosing a sample when we go idle between
* calc_load_account_active() (10 ticks ago) and now and thus
* under-accounting.
*/
calc_global_nohz();
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment