mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <dsmythies@telus.net> Reported-by: LesÅ=82aw Kope=C4=87 <leslaw.kopec@nasza-klasa.pl> Reported-by: Aman Gupta <aman@tmm1.net> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/n/tip-4v31etnhgg9kwd6ocgx3rxl8@git.kernel.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
		
							parent
							
								
									8e3fabfde4
								
							
						
					
					
						commit
						c308b56b53
					
				
					 1 changed files with 27 additions and 28 deletions
				
			
		| 
						 | 
					@ -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,10 +2281,16 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Catch-up, fold however many we are behind still
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						delta = jiffies - calc_load_update - 10;
 | 
				
			||||||
 | 
						n = 1 + (delta / LOAD_FREQ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	active = atomic_long_read(&calc_load_tasks);
 | 
						active = atomic_long_read(&calc_load_tasks);
 | 
				
			||||||
	active = active > 0 ? active * FIXED_1 : 0;
 | 
						active = active > 0 ? active * FIXED_1 : 0;
 | 
				
			||||||
| 
						 | 
					@ -2297,18 +2300,6 @@ static void calc_global_nohz(unsigned long ticks)
 | 
				
			||||||
	avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
 | 
						avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	calc_load_update += n * LOAD_FREQ;
 | 
						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)
 | 
				
			||||||
	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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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)
 | 
				
			||||||
	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();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue