sched: Fix nohz load accounting -- again!
tip-bot for Peter Zijlstra
maintainerCommit-ID: c308b56b5398779cd3da0f62ab26b0453494c3d4 Gitweb: http://git.kernel.org/tip/c308b56b5398779cd3da0f62ab26b0453494c3d4 Author: Peter Zijlstra <[email protected]> AuthorDate: Thu, 1 Mar 2012 15:04:46 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 12 Mar 2012 20:43:17 +0100
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 Doug Smythies <[email protected]>
Reported-by LesÅ=82aw Kope=C4=87 <[email protected]>
Reported-by Aman Gupta <[email protected]>
Signed-off-by Peter Zijlstra <[email protected]>
Signed-off-by Ingo Molnar <[email protected]>
--- kernel/sched/core.c | 53 +++++++++++++++++++++++++-------------------------- 1 files changed, 26 insertions(+), 27 deletions(-)
kernel/sched/core.c +26 -27
@@ -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 * 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; -if (time_before (jiffies, calc_load_update)) -return ; -/* * If we crossed a calc_load_update boundary, make sure to fold * any pending idle changes, the respective CPUs might have
@@ -2284,31 +2281,25 @@ static void calc_global_nohz(unsigned long ticks)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 ) { - n = ticks /LOAD_FREQ ; +if (time_before (jiffies, calc_load_update +10 )) +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); - avenrun[1 ] =calc_load_n (avenrun[1 ],EXP_5 , active, n); - avenrun[2 ] =calc_load_n (avenrun[2 ],EXP_15 , active, n); + active =atomic_long_read (&calc_load_tasks); + active = active >0 ? active *FIXED_1 :0 ; - 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); -/* -* 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. - */ + calc_load_update += n * LOAD_FREQ; }#else void calc_load_account_idle (struct rq *this_rq)
@@ -2320,7 +2311,7 @@ static inline long calc_load_fold_idle(void) return 0; } -static void calc_global_nohz (unsigned long ticks) +static void calc_global_nohz (void ) { }#endif
@@ -2348,8 +2339,6 @@ void calc_global_load(unsigned long ticks) {long active; -calc_global_nohz (ticks); -if (time_before (jiffies, calc_load_update +10 ))return ;
@@ -2361,6 +2350,16 @@ void calc_global_load(unsigned long ticks) avenrun[2 ] =calc_load (avenrun[2 ],EXP_15 , active); 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 (); }/*