diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-17 12:35:54 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-17 12:35:54 -0800 | 
| commit | dd0508093b79141e0044ca02f0acb6319f69f546 (patch) | |
| tree | 5e0116949fd98cfaee9b118b6637203d17fa5dd0 /kernel/sched/fair.c | |
| parent | 1070d5ac193af55fd335ef2aacaf03c5fc4ee461 (diff) | |
| parent | 9dbdb155532395ba000c5d5d187658b0e17e529f (diff) | |
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fixes from Ingo Molnar:
 "Three fixes for scheduler crashes, each triggers in relatively rare,
  hardware environment dependent situations"
* 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  sched/fair: Rework sched_fair time accounting
  math64: Add mul_u64_u32_shr()
  sched: Remove PREEMPT_NEED_RESCHED from generic code
  sched: Initialize power_orig for overlapping groups
Diffstat (limited to 'kernel/sched/fair.c')
| -rw-r--r-- | kernel/sched/fair.c | 144 | 
1 files changed, 64 insertions, 80 deletions
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index fd773ade1a31..9030da7bcb15 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -178,59 +178,61 @@ void sched_init_granularity(void)  	update_sysctl();  } -#if BITS_PER_LONG == 32 -# define WMULT_CONST	(~0UL) -#else -# define WMULT_CONST	(1UL << 32) -#endif - +#define WMULT_CONST	(~0U)  #define WMULT_SHIFT	32 -/* - * Shift right and round: - */ -#define SRR(x, y) (((x) + (1UL << ((y) - 1))) >> (y)) +static void __update_inv_weight(struct load_weight *lw) +{ +	unsigned long w; + +	if (likely(lw->inv_weight)) +		return; + +	w = scale_load_down(lw->weight); + +	if (BITS_PER_LONG > 32 && unlikely(w >= WMULT_CONST)) +		lw->inv_weight = 1; +	else if (unlikely(!w)) +		lw->inv_weight = WMULT_CONST; +	else +		lw->inv_weight = WMULT_CONST / w; +}  /* - * delta *= weight / lw + * delta_exec * weight / lw.weight + *   OR + * (delta_exec * (weight * lw->inv_weight)) >> WMULT_SHIFT + * + * Either weight := NICE_0_LOAD and lw \e prio_to_wmult[], in which case + * we're guaranteed shift stays positive because inv_weight is guaranteed to + * fit 32 bits, and NICE_0_LOAD gives another 10 bits; therefore shift >= 22. + * + * Or, weight =< lw.weight (because lw.weight is the runqueue weight), thus + * weight/lw.weight <= 1, and therefore our shift will also be positive.   */ -static unsigned long -calc_delta_mine(unsigned long delta_exec, unsigned long weight, -		struct load_weight *lw) +static u64 __calc_delta(u64 delta_exec, unsigned long weight, struct load_weight *lw)  { -	u64 tmp; +	u64 fact = scale_load_down(weight); +	int shift = WMULT_SHIFT; -	/* -	 * weight can be less than 2^SCHED_LOAD_RESOLUTION for task group sched -	 * entities since MIN_SHARES = 2. Treat weight as 1 if less than -	 * 2^SCHED_LOAD_RESOLUTION. -	 */ -	if (likely(weight > (1UL << SCHED_LOAD_RESOLUTION))) -		tmp = (u64)delta_exec * scale_load_down(weight); -	else -		tmp = (u64)delta_exec; +	__update_inv_weight(lw); -	if (!lw->inv_weight) { -		unsigned long w = scale_load_down(lw->weight); - -		if (BITS_PER_LONG > 32 && unlikely(w >= WMULT_CONST)) -			lw->inv_weight = 1; -		else if (unlikely(!w)) -			lw->inv_weight = WMULT_CONST; -		else -			lw->inv_weight = WMULT_CONST / w; +	if (unlikely(fact >> 32)) { +		while (fact >> 32) { +			fact >>= 1; +			shift--; +		}  	} -	/* -	 * Check whether we'd overflow the 64-bit multiplication: -	 */ -	if (unlikely(tmp > WMULT_CONST)) -		tmp = SRR(SRR(tmp, WMULT_SHIFT/2) * lw->inv_weight, -			WMULT_SHIFT/2); -	else -		tmp = SRR(tmp * lw->inv_weight, WMULT_SHIFT); +	/* hint to use a 32x32->64 mul */ +	fact = (u64)(u32)fact * lw->inv_weight; + +	while (fact >> 32) { +		fact >>= 1; +		shift--; +	} -	return (unsigned long)min(tmp, (u64)(unsigned long)LONG_MAX); +	return mul_u64_u32_shr(delta_exec, fact, shift);  } @@ -443,7 +445,7 @@ find_matching_se(struct sched_entity **se, struct sched_entity **pse)  #endif	/* CONFIG_FAIR_GROUP_SCHED */  static __always_inline -void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, unsigned long delta_exec); +void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec);  /**************************************************************   * Scheduling class tree data structure manipulation methods: @@ -612,11 +614,10 @@ int sched_proc_update_handler(struct ctl_table *table, int write,  /*   * delta /= w   */ -static inline unsigned long -calc_delta_fair(unsigned long delta, struct sched_entity *se) +static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se)  {  	if (unlikely(se->load.weight != NICE_0_LOAD)) -		delta = calc_delta_mine(delta, NICE_0_LOAD, &se->load); +		delta = __calc_delta(delta, NICE_0_LOAD, &se->load);  	return delta;  } @@ -665,7 +666,7 @@ static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)  			update_load_add(&lw, se->load.weight);  			load = &lw;  		} -		slice = calc_delta_mine(slice, se->load.weight, load); +		slice = __calc_delta(slice, se->load.weight, load);  	}  	return slice;  } @@ -703,47 +704,32 @@ void init_task_runnable_average(struct task_struct *p)  #endif  /* - * Update the current task's runtime statistics. Skip current tasks that - * are not in our scheduling class. + * Update the current task's runtime statistics.   */ -static inline void -__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr, -	      unsigned long delta_exec) -{ -	unsigned long delta_exec_weighted; - -	schedstat_set(curr->statistics.exec_max, -		      max((u64)delta_exec, curr->statistics.exec_max)); - -	curr->sum_exec_runtime += delta_exec; -	schedstat_add(cfs_rq, exec_clock, delta_exec); -	delta_exec_weighted = calc_delta_fair(delta_exec, curr); - -	curr->vruntime += delta_exec_weighted; -	update_min_vruntime(cfs_rq); -} -  static void update_curr(struct cfs_rq *cfs_rq)  {  	struct sched_entity *curr = cfs_rq->curr;  	u64 now = rq_clock_task(rq_of(cfs_rq)); -	unsigned long delta_exec; +	u64 delta_exec;  	if (unlikely(!curr))  		return; -	/* -	 * Get the amount of time the current task was running -	 * since the last time we changed load (this cannot -	 * overflow on 32 bits): -	 */ -	delta_exec = (unsigned long)(now - curr->exec_start); -	if (!delta_exec) +	delta_exec = now - curr->exec_start; +	if (unlikely((s64)delta_exec <= 0))  		return; -	__update_curr(cfs_rq, curr, delta_exec);  	curr->exec_start = now; +	schedstat_set(curr->statistics.exec_max, +		      max(delta_exec, curr->statistics.exec_max)); + +	curr->sum_exec_runtime += delta_exec; +	schedstat_add(cfs_rq, exec_clock, delta_exec); + +	curr->vruntime += calc_delta_fair(delta_exec, curr); +	update_min_vruntime(cfs_rq); +  	if (entity_is_task(curr)) {  		struct task_struct *curtask = task_of(curr); @@ -3015,8 +3001,7 @@ static void expire_cfs_rq_runtime(struct cfs_rq *cfs_rq)  	}  } -static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, -				     unsigned long delta_exec) +static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)  {  	/* dock delta_exec before expiring quota (as it could span periods) */  	cfs_rq->runtime_remaining -= delta_exec; @@ -3034,7 +3019,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq,  }  static __always_inline -void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, unsigned long delta_exec) +void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)  {  	if (!cfs_bandwidth_used() || !cfs_rq->runtime_enabled)  		return; @@ -3574,8 +3559,7 @@ static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)  	return rq_clock_task(rq_of(cfs_rq));  } -static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, -				     unsigned long delta_exec) {} +static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {}  static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}  static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {}  static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}  | 
