提交 be12014d 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched

* git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched: (61 commits)
  sched: refine negative nice level granularity
  sched: fix update_stats_enqueue() reniced codepath
  sched: round a bit better
  sched: make the multiplication table more accurate
  sched: optimize update_rq_clock() calls in the load-balancer
  sched: optimize activate_task()
  sched: clean up set_curr_task_fair()
  sched: remove __update_rq_clock() call from entity_tick()
  sched: move the __update_rq_clock() call to scheduler_tick()
  sched debug: remove the 'u64 now' parameter from print_task()/_rq()
  sched: remove the 'u64 now' local variables
  sched: remove the 'u64 now' parameter from deactivate_task()
  sched: remove the 'u64 now' parameter from dequeue_task()
  sched: remove the 'u64 now' parameter from enqueue_task()
  sched: remove the 'u64 now' parameter from dec_nr_running()
  sched: remove the 'u64 now' parameter from inc_nr_running()
  sched: remove the 'u64 now' parameter from dec_load()
  sched: remove the 'u64 now' parameter from inc_load()
  sched: remove the 'u64 now' parameter from update_curr_load()
  sched: remove the 'u64 now' parameter from ->task_new()
  ...
...@@ -83,7 +83,7 @@ Some implementation details: ...@@ -83,7 +83,7 @@ Some implementation details:
CFS uses nanosecond granularity accounting and does not rely on any CFS uses nanosecond granularity accounting and does not rely on any
jiffies or other HZ detail. Thus the CFS scheduler has no notion of jiffies or other HZ detail. Thus the CFS scheduler has no notion of
'timeslices' and has no heuristics whatsoever. There is only one 'timeslices' and has no heuristics whatsoever. There is only one
central tunable: central tunable (you have to switch on CONFIG_SCHED_DEBUG):
/proc/sys/kernel/sched_granularity_ns /proc/sys/kernel/sched_granularity_ns
......
This document explains the thinking about the revamped and streamlined
nice-levels implementation in the new Linux scheduler.
Nice levels were always pretty weak under Linux and people continuously
pestered us to make nice +19 tasks use up much less CPU time.
Unfortunately that was not that easy to implement under the old
scheduler, (otherwise we'd have done it long ago) because nice level
support was historically coupled to timeslice length, and timeslice
units were driven by the HZ tick, so the smallest timeslice was 1/HZ.
In the O(1) scheduler (in 2003) we changed negative nice levels to be
much stronger than they were before in 2.4 (and people were happy about
that change), and we also intentionally calibrated the linear timeslice
rule so that nice +19 level would be _exactly_ 1 jiffy. To better
understand it, the timeslice graph went like this (cheesy ASCII art
alert!):
A
\ | [timeslice length]
\ |
\ |
\ |
\ |
\|___100msecs
|^ . _
| ^ . _
| ^ . _
-*----------------------------------*-----> [nice level]
-20 | +19
|
|
So that if someone wanted to really renice tasks, +19 would give a much
bigger hit than the normal linear rule would do. (The solution of
changing the ABI to extend priorities was discarded early on.)
This approach worked to some degree for some time, but later on with
HZ=1000 it caused 1 jiffy to be 1 msec, which meant 0.1% CPU usage which
we felt to be a bit excessive. Excessive _not_ because it's too small of
a CPU utilization, but because it causes too frequent (once per
millisec) rescheduling. (and would thus trash the cache, etc. Remember,
this was long ago when hardware was weaker and caches were smaller, and
people were running number crunching apps at nice +19.)
So for HZ=1000 we changed nice +19 to 5msecs, because that felt like the
right minimal granularity - and this translates to 5% CPU utilization.
But the fundamental HZ-sensitive property for nice+19 still remained,
and we never got a single complaint about nice +19 being too _weak_ in
terms of CPU utilization, we only got complaints about it (still) being
too _strong_ :-)
To sum it up: we always wanted to make nice levels more consistent, but
within the constraints of HZ and jiffies and their nasty design level
coupling to timeslices and granularity it was not really viable.
The second (less frequent but still periodically occuring) complaint
about Linux's nice level support was its assymetry around the origo
(which you can see demonstrated in the picture above), or more
accurately: the fact that nice level behavior depended on the _absolute_
nice level as well, while the nice API itself is fundamentally
"relative":
int nice(int inc);
asmlinkage long sys_nice(int increment)
(the first one is the glibc API, the second one is the syscall API.)
Note that the 'inc' is relative to the current nice level. Tools like
bash's "nice" command mirror this relative API.
With the old scheduler, if you for example started a niced task with +1
and another task with +2, the CPU split between the two tasks would
depend on the nice level of the parent shell - if it was at nice -10 the
CPU split was different than if it was at +5 or +10.
A third complaint against Linux's nice level support was that negative
nice levels were not 'punchy enough', so lots of people had to resort to
run audio (and other multimedia) apps under RT priorities such as
SCHED_FIFO. But this caused other problems: SCHED_FIFO is not starvation
proof, and a buggy SCHED_FIFO app can also lock up the system for good.
The new scheduler in v2.6.23 addresses all three types of complaints:
To address the first complaint (of nice levels being not "punchy"
enough), the scheduler was decoupled from 'time slice' and HZ concepts
(and granularity was made a separate concept from nice levels) and thus
it was possible to implement better and more consistent nice +19
support: with the new scheduler nice +19 tasks get a HZ-independent
1.5%, instead of the variable 3%-5%-9% range they got in the old
scheduler.
To address the second complaint (of nice levels not being consistent),
the new scheduler makes nice(1) have the same CPU utilization effect on
tasks, regardless of their absolute nice levels. So on the new
scheduler, running a nice +10 and a nice 11 task has the same CPU
utilization "split" between them as running a nice -5 and a nice -4
task. (one will get 55% of the CPU, the other 45%.) That is why nice
levels were changed to be "multiplicative" (or exponential) - that way
it does not matter which nice level you start out from, the 'relative
result' will always be the same.
The third complaint (of negative nice levels not being "punchy" enough
and forcing audio apps to run under the more dangerous SCHED_FIFO
scheduling policy) is addressed by the new scheduler almost
automatically: stronger negative nice levels are an automatic
side-effect of the recalibrated dynamic range of nice levels.
...@@ -139,7 +139,7 @@ struct cfs_rq; ...@@ -139,7 +139,7 @@ struct cfs_rq;
extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m); extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m);
extern void proc_sched_set_task(struct task_struct *p); extern void proc_sched_set_task(struct task_struct *p);
extern void extern void
print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now); print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
#else #else
static inline void static inline void
proc_sched_show_task(struct task_struct *p, struct seq_file *m) proc_sched_show_task(struct task_struct *p, struct seq_file *m)
...@@ -149,7 +149,7 @@ static inline void proc_sched_set_task(struct task_struct *p) ...@@ -149,7 +149,7 @@ static inline void proc_sched_set_task(struct task_struct *p)
{ {
} }
static inline void static inline void
print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now) print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
{ {
} }
#endif #endif
...@@ -855,26 +855,24 @@ struct sched_domain; ...@@ -855,26 +855,24 @@ struct sched_domain;
struct sched_class { struct sched_class {
struct sched_class *next; struct sched_class *next;
void (*enqueue_task) (struct rq *rq, struct task_struct *p, void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
int wakeup, u64 now); void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
void (*dequeue_task) (struct rq *rq, struct task_struct *p,
int sleep, u64 now);
void (*yield_task) (struct rq *rq, struct task_struct *p); void (*yield_task) (struct rq *rq, struct task_struct *p);
void (*check_preempt_curr) (struct rq *rq, struct task_struct *p); void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
struct task_struct * (*pick_next_task) (struct rq *rq, u64 now); struct task_struct * (*pick_next_task) (struct rq *rq);
void (*put_prev_task) (struct rq *rq, struct task_struct *p, u64 now); void (*put_prev_task) (struct rq *rq, struct task_struct *p);
int (*load_balance) (struct rq *this_rq, int this_cpu, unsigned long (*load_balance) (struct rq *this_rq, int this_cpu,
struct rq *busiest, struct rq *busiest,
unsigned long max_nr_move, unsigned long max_load_move, unsigned long max_nr_move, unsigned long max_load_move,
struct sched_domain *sd, enum cpu_idle_type idle, struct sched_domain *sd, enum cpu_idle_type idle,
int *all_pinned, unsigned long *total_load_moved); int *all_pinned, int *this_best_prio);
void (*set_curr_task) (struct rq *rq); void (*set_curr_task) (struct rq *rq);
void (*task_tick) (struct rq *rq, struct task_struct *p); void (*task_tick) (struct rq *rq, struct task_struct *p);
void (*task_new) (struct rq *rq, struct task_struct *p, u64 now); void (*task_new) (struct rq *rq, struct task_struct *p);
}; };
struct load_weight { struct load_weight {
......
此差异已折叠。
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
} while (0) } while (0)
static void static void
print_task(struct seq_file *m, struct rq *rq, struct task_struct *p, u64 now) print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
{ {
if (rq->curr == p) if (rq->curr == p)
SEQ_printf(m, "R"); SEQ_printf(m, "R");
...@@ -56,7 +56,7 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p, u64 now) ...@@ -56,7 +56,7 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p, u64 now)
#endif #endif
} }
static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu, u64 now) static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
{ {
struct task_struct *g, *p; struct task_struct *g, *p;
...@@ -77,7 +77,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu, u64 now) ...@@ -77,7 +77,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu, u64 now)
if (!p->se.on_rq || task_cpu(p) != rq_cpu) if (!p->se.on_rq || task_cpu(p) != rq_cpu)
continue; continue;
print_task(m, rq, p, now); print_task(m, rq, p);
} while_each_thread(g, p); } while_each_thread(g, p);
read_unlock_irq(&tasklist_lock); read_unlock_irq(&tasklist_lock);
...@@ -106,7 +106,7 @@ print_cfs_rq_runtime_sum(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) ...@@ -106,7 +106,7 @@ print_cfs_rq_runtime_sum(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
(long long)wait_runtime_rq_sum); (long long)wait_runtime_rq_sum);
} }
void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now) void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
{ {
SEQ_printf(m, "\ncfs_rq %p\n", cfs_rq); SEQ_printf(m, "\ncfs_rq %p\n", cfs_rq);
...@@ -124,7 +124,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now) ...@@ -124,7 +124,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now)
print_cfs_rq_runtime_sum(m, cpu, cfs_rq); print_cfs_rq_runtime_sum(m, cpu, cfs_rq);
} }
static void print_cpu(struct seq_file *m, int cpu, u64 now) static void print_cpu(struct seq_file *m, int cpu)
{ {
struct rq *rq = &per_cpu(runqueues, cpu); struct rq *rq = &per_cpu(runqueues, cpu);
...@@ -166,9 +166,9 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now) ...@@ -166,9 +166,9 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
P(cpu_load[4]); P(cpu_load[4]);
#undef P #undef P
print_cfs_stats(m, cpu, now); print_cfs_stats(m, cpu);
print_rq(m, rq, cpu, now); print_rq(m, rq, cpu);
} }
static int sched_debug_show(struct seq_file *m, void *v) static int sched_debug_show(struct seq_file *m, void *v)
...@@ -184,7 +184,7 @@ static int sched_debug_show(struct seq_file *m, void *v) ...@@ -184,7 +184,7 @@ static int sched_debug_show(struct seq_file *m, void *v)
SEQ_printf(m, "now at %Lu nsecs\n", (unsigned long long)now); SEQ_printf(m, "now at %Lu nsecs\n", (unsigned long long)now);
for_each_online_cpu(cpu) for_each_online_cpu(cpu)
print_cpu(m, cpu, now); print_cpu(m, cpu);
SEQ_printf(m, "\n"); SEQ_printf(m, "\n");
......
...@@ -222,21 +222,25 @@ niced_granularity(struct sched_entity *curr, unsigned long granularity) ...@@ -222,21 +222,25 @@ niced_granularity(struct sched_entity *curr, unsigned long granularity)
{ {
u64 tmp; u64 tmp;
if (likely(curr->load.weight == NICE_0_LOAD))
return granularity;
/* /*
* Negative nice levels get the same granularity as nice-0: * Positive nice levels get the same granularity as nice-0:
*/ */
if (likely(curr->load.weight >= NICE_0_LOAD)) if (likely(curr->load.weight < NICE_0_LOAD)) {
return granularity; tmp = curr->load.weight * (u64)granularity;
return (long) (tmp >> NICE_0_SHIFT);
}
/* /*
* Positive nice level tasks get linearly finer * Negative nice level tasks get linearly finer
* granularity: * granularity:
*/ */
tmp = curr->load.weight * (u64)granularity; tmp = curr->load.inv_weight * (u64)granularity;
/* /*
* It will always fit into 'long': * It will always fit into 'long':
*/ */
return (long) (tmp >> NICE_0_SHIFT); return (long) (tmp >> WMULT_SHIFT);
} }
static inline void static inline void
...@@ -281,26 +285,25 @@ add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta) ...@@ -281,26 +285,25 @@ add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
* are not in our scheduling class. * are not in our scheduling class.
*/ */
static inline void static inline void
__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr, u64 now) __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{ {
unsigned long delta, delta_exec, delta_fair; unsigned long delta, delta_exec, delta_fair, delta_mine;
long delta_mine;
struct load_weight *lw = &cfs_rq->load; struct load_weight *lw = &cfs_rq->load;
unsigned long load = lw->weight; unsigned long load = lw->weight;
if (unlikely(!load))
return;
delta_exec = curr->delta_exec; delta_exec = curr->delta_exec;
schedstat_set(curr->exec_max, max((u64)delta_exec, curr->exec_max)); schedstat_set(curr->exec_max, max((u64)delta_exec, curr->exec_max));
curr->sum_exec_runtime += delta_exec; curr->sum_exec_runtime += delta_exec;
cfs_rq->exec_clock += delta_exec; cfs_rq->exec_clock += delta_exec;
if (unlikely(!load))
return;
delta_fair = calc_delta_fair(delta_exec, lw); delta_fair = calc_delta_fair(delta_exec, lw);
delta_mine = calc_delta_mine(delta_exec, curr->load.weight, lw); delta_mine = calc_delta_mine(delta_exec, curr->load.weight, lw);
if (cfs_rq->sleeper_bonus > sysctl_sched_stat_granularity) { if (cfs_rq->sleeper_bonus > sysctl_sched_granularity) {
delta = calc_delta_mine(cfs_rq->sleeper_bonus, delta = calc_delta_mine(cfs_rq->sleeper_bonus,
curr->load.weight, lw); curr->load.weight, lw);
if (unlikely(delta > cfs_rq->sleeper_bonus)) if (unlikely(delta > cfs_rq->sleeper_bonus))
...@@ -321,7 +324,7 @@ __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr, u64 now) ...@@ -321,7 +324,7 @@ __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr, u64 now)
add_wait_runtime(cfs_rq, curr, delta_mine - delta_exec); add_wait_runtime(cfs_rq, curr, delta_mine - delta_exec);
} }
static void update_curr(struct cfs_rq *cfs_rq, u64 now) static void update_curr(struct cfs_rq *cfs_rq)
{ {
struct sched_entity *curr = cfs_rq_curr(cfs_rq); struct sched_entity *curr = cfs_rq_curr(cfs_rq);
unsigned long delta_exec; unsigned long delta_exec;
...@@ -334,22 +337,22 @@ static void update_curr(struct cfs_rq *cfs_rq, u64 now) ...@@ -334,22 +337,22 @@ static void update_curr(struct cfs_rq *cfs_rq, u64 now)
* since the last time we changed load (this cannot * since the last time we changed load (this cannot
* overflow on 32 bits): * overflow on 32 bits):
*/ */
delta_exec = (unsigned long)(now - curr->exec_start); delta_exec = (unsigned long)(rq_of(cfs_rq)->clock - curr->exec_start);
curr->delta_exec += delta_exec; curr->delta_exec += delta_exec;
if (unlikely(curr->delta_exec > sysctl_sched_stat_granularity)) { if (unlikely(curr->delta_exec > sysctl_sched_stat_granularity)) {
__update_curr(cfs_rq, curr, now); __update_curr(cfs_rq, curr);
curr->delta_exec = 0; curr->delta_exec = 0;
} }
curr->exec_start = now; curr->exec_start = rq_of(cfs_rq)->clock;
} }
static inline void static inline void
update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
se->wait_start_fair = cfs_rq->fair_clock; se->wait_start_fair = cfs_rq->fair_clock;
schedstat_set(se->wait_start, now); schedstat_set(se->wait_start, rq_of(cfs_rq)->clock);
} }
/* /*
...@@ -377,8 +380,7 @@ calc_weighted(unsigned long delta, unsigned long weight, int shift) ...@@ -377,8 +380,7 @@ calc_weighted(unsigned long delta, unsigned long weight, int shift)
/* /*
* Task is being enqueued - update stats: * Task is being enqueued - update stats:
*/ */
static void static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
{ {
s64 key; s64 key;
...@@ -387,7 +389,7 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -387,7 +389,7 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
* a dequeue/enqueue event is a NOP) * a dequeue/enqueue event is a NOP)
*/ */
if (se != cfs_rq_curr(cfs_rq)) if (se != cfs_rq_curr(cfs_rq))
update_stats_wait_start(cfs_rq, se, now); update_stats_wait_start(cfs_rq, se);
/* /*
* Update the key: * Update the key:
*/ */
...@@ -407,7 +409,8 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -407,7 +409,8 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
(WMULT_SHIFT - NICE_0_SHIFT); (WMULT_SHIFT - NICE_0_SHIFT);
} else { } else {
tmp = se->wait_runtime; tmp = se->wait_runtime;
key -= (tmp * se->load.weight) >> NICE_0_SHIFT; key -= (tmp * se->load.inv_weight) >>
(WMULT_SHIFT - NICE_0_SHIFT);
} }
} }
...@@ -418,11 +421,12 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -418,11 +421,12 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
* Note: must be called with a freshly updated rq->fair_clock. * Note: must be called with a freshly updated rq->fair_clock.
*/ */
static inline void static inline void
__update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) __update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
unsigned long delta_fair = se->delta_fair_run; unsigned long delta_fair = se->delta_fair_run;
schedstat_set(se->wait_max, max(se->wait_max, now - se->wait_start)); schedstat_set(se->wait_max, max(se->wait_max,
rq_of(cfs_rq)->clock - se->wait_start));
if (unlikely(se->load.weight != NICE_0_LOAD)) if (unlikely(se->load.weight != NICE_0_LOAD))
delta_fair = calc_weighted(delta_fair, se->load.weight, delta_fair = calc_weighted(delta_fair, se->load.weight,
...@@ -432,7 +436,7 @@ __update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -432,7 +436,7 @@ __update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
} }
static void static void
update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
unsigned long delta_fair; unsigned long delta_fair;
...@@ -442,7 +446,7 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -442,7 +446,7 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
se->delta_fair_run += delta_fair; se->delta_fair_run += delta_fair;
if (unlikely(abs(se->delta_fair_run) >= if (unlikely(abs(se->delta_fair_run) >=
sysctl_sched_stat_granularity)) { sysctl_sched_stat_granularity)) {
__update_stats_wait_end(cfs_rq, se, now); __update_stats_wait_end(cfs_rq, se);
se->delta_fair_run = 0; se->delta_fair_run = 0;
} }
...@@ -451,34 +455,34 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -451,34 +455,34 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
} }
static inline void static inline void
update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
update_curr(cfs_rq, now); update_curr(cfs_rq);
/* /*
* Mark the end of the wait period if dequeueing a * Mark the end of the wait period if dequeueing a
* waiting task: * waiting task:
*/ */
if (se != cfs_rq_curr(cfs_rq)) if (se != cfs_rq_curr(cfs_rq))
update_stats_wait_end(cfs_rq, se, now); update_stats_wait_end(cfs_rq, se);
} }
/* /*
* We are picking a new current task - update its stats: * We are picking a new current task - update its stats:
*/ */
static inline void static inline void
update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
/* /*
* We are starting a new run period: * We are starting a new run period:
*/ */
se->exec_start = now; se->exec_start = rq_of(cfs_rq)->clock;
} }
/* /*
* We are descheduling a task - update its stats: * We are descheduling a task - update its stats:
*/ */
static inline void static inline void
update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
se->exec_start = 0; se->exec_start = 0;
} }
...@@ -487,8 +491,7 @@ update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -487,8 +491,7 @@ update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
* Scheduling class queueing methods: * Scheduling class queueing methods:
*/ */
static void static void __enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
__enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
{ {
unsigned long load = cfs_rq->load.weight, delta_fair; unsigned long load = cfs_rq->load.weight, delta_fair;
long prev_runtime; long prev_runtime;
...@@ -522,8 +525,7 @@ __enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -522,8 +525,7 @@ __enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
schedstat_add(cfs_rq, wait_runtime, se->wait_runtime); schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
} }
static void static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
{ {
struct task_struct *tsk = task_of(se); struct task_struct *tsk = task_of(se);
unsigned long delta_fair; unsigned long delta_fair;
...@@ -538,7 +540,7 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -538,7 +540,7 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
se->delta_fair_sleep += delta_fair; se->delta_fair_sleep += delta_fair;
if (unlikely(abs(se->delta_fair_sleep) >= if (unlikely(abs(se->delta_fair_sleep) >=
sysctl_sched_stat_granularity)) { sysctl_sched_stat_granularity)) {
__enqueue_sleeper(cfs_rq, se, now); __enqueue_sleeper(cfs_rq, se);
se->delta_fair_sleep = 0; se->delta_fair_sleep = 0;
} }
...@@ -546,7 +548,7 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -546,7 +548,7 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
#ifdef CONFIG_SCHEDSTATS #ifdef CONFIG_SCHEDSTATS
if (se->sleep_start) { if (se->sleep_start) {
u64 delta = now - se->sleep_start; u64 delta = rq_of(cfs_rq)->clock - se->sleep_start;
if ((s64)delta < 0) if ((s64)delta < 0)
delta = 0; delta = 0;
...@@ -558,7 +560,7 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -558,7 +560,7 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
se->sum_sleep_runtime += delta; se->sum_sleep_runtime += delta;
} }
if (se->block_start) { if (se->block_start) {
u64 delta = now - se->block_start; u64 delta = rq_of(cfs_rq)->clock - se->block_start;
if ((s64)delta < 0) if ((s64)delta < 0)
delta = 0; delta = 0;
...@@ -573,26 +575,24 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -573,26 +575,24 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
} }
static void static void
enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup)
int wakeup, u64 now)
{ {
/* /*
* Update the fair clock. * Update the fair clock.
*/ */
update_curr(cfs_rq, now); update_curr(cfs_rq);
if (wakeup) if (wakeup)
enqueue_sleeper(cfs_rq, se, now); enqueue_sleeper(cfs_rq, se);
update_stats_enqueue(cfs_rq, se, now); update_stats_enqueue(cfs_rq, se);
__enqueue_entity(cfs_rq, se); __enqueue_entity(cfs_rq, se);
} }
static void static void
dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
int sleep, u64 now)
{ {
update_stats_dequeue(cfs_rq, se, now); update_stats_dequeue(cfs_rq, se);
if (sleep) { if (sleep) {
se->sleep_start_fair = cfs_rq->fair_clock; se->sleep_start_fair = cfs_rq->fair_clock;
#ifdef CONFIG_SCHEDSTATS #ifdef CONFIG_SCHEDSTATS
...@@ -600,9 +600,9 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, ...@@ -600,9 +600,9 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
struct task_struct *tsk = task_of(se); struct task_struct *tsk = task_of(se);
if (tsk->state & TASK_INTERRUPTIBLE) if (tsk->state & TASK_INTERRUPTIBLE)
se->sleep_start = now; se->sleep_start = rq_of(cfs_rq)->clock;
if (tsk->state & TASK_UNINTERRUPTIBLE) if (tsk->state & TASK_UNINTERRUPTIBLE)
se->block_start = now; se->block_start = rq_of(cfs_rq)->clock;
} }
cfs_rq->wait_runtime -= se->wait_runtime; cfs_rq->wait_runtime -= se->wait_runtime;
#endif #endif
...@@ -629,7 +629,7 @@ __check_preempt_curr_fair(struct cfs_rq *cfs_rq, struct sched_entity *se, ...@@ -629,7 +629,7 @@ __check_preempt_curr_fair(struct cfs_rq *cfs_rq, struct sched_entity *se,
} }
static inline void static inline void
set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{ {
/* /*
* Any task has to be enqueued before it get to execute on * Any task has to be enqueued before it get to execute on
...@@ -638,49 +638,46 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now) ...@@ -638,49 +638,46 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
* done a put_prev_task_fair() shortly before this, which * done a put_prev_task_fair() shortly before this, which
* updated rq->fair_clock - used by update_stats_wait_end()) * updated rq->fair_clock - used by update_stats_wait_end())
*/ */
update_stats_wait_end(cfs_rq, se, now); update_stats_wait_end(cfs_rq, se);
update_stats_curr_start(cfs_rq, se, now); update_stats_curr_start(cfs_rq, se);
set_cfs_rq_curr(cfs_rq, se); set_cfs_rq_curr(cfs_rq, se);
} }
static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq, u64 now) static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
{ {
struct sched_entity *se = __pick_next_entity(cfs_rq); struct sched_entity *se = __pick_next_entity(cfs_rq);
set_next_entity(cfs_rq, se, now); set_next_entity(cfs_rq, se);
return se; return se;
} }
static void static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev, u64 now)
{ {
/* /*
* If still on the runqueue then deactivate_task() * If still on the runqueue then deactivate_task()
* was not called and update_curr() has to be done: * was not called and update_curr() has to be done:
*/ */
if (prev->on_rq) if (prev->on_rq)
update_curr(cfs_rq, now); update_curr(cfs_rq);
update_stats_curr_end(cfs_rq, prev, now); update_stats_curr_end(cfs_rq, prev);
if (prev->on_rq) if (prev->on_rq)
update_stats_wait_start(cfs_rq, prev, now); update_stats_wait_start(cfs_rq, prev);
set_cfs_rq_curr(cfs_rq, NULL); set_cfs_rq_curr(cfs_rq, NULL);
} }
static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{ {
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *next; struct sched_entity *next;
u64 now = __rq_clock(rq);
/* /*
* Dequeue and enqueue the task to update its * Dequeue and enqueue the task to update its
* position within the tree: * position within the tree:
*/ */
dequeue_entity(cfs_rq, curr, 0, now); dequeue_entity(cfs_rq, curr, 0);
enqueue_entity(cfs_rq, curr, 0, now); enqueue_entity(cfs_rq, curr, 0);
/* /*
* Reschedule if another task tops the current one. * Reschedule if another task tops the current one.
...@@ -785,8 +782,7 @@ static inline int is_same_group(struct task_struct *curr, struct task_struct *p) ...@@ -785,8 +782,7 @@ static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
* increased. Here we update the fair scheduling stats and * increased. Here we update the fair scheduling stats and
* then put the task into the rbtree: * then put the task into the rbtree:
*/ */
static void static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup)
enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
{ {
struct cfs_rq *cfs_rq; struct cfs_rq *cfs_rq;
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
...@@ -795,7 +791,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, u64 now) ...@@ -795,7 +791,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
if (se->on_rq) if (se->on_rq)
break; break;
cfs_rq = cfs_rq_of(se); cfs_rq = cfs_rq_of(se);
enqueue_entity(cfs_rq, se, wakeup, now); enqueue_entity(cfs_rq, se, wakeup);
} }
} }
...@@ -804,15 +800,14 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, u64 now) ...@@ -804,15 +800,14 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
* decreased. We remove the task from the rbtree and * decreased. We remove the task from the rbtree and
* update the fair scheduling stats: * update the fair scheduling stats:
*/ */
static void static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep, u64 now)
{ {
struct cfs_rq *cfs_rq; struct cfs_rq *cfs_rq;
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
for_each_sched_entity(se) { for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se); cfs_rq = cfs_rq_of(se);
dequeue_entity(cfs_rq, se, sleep, now); dequeue_entity(cfs_rq, se, sleep);
/* Don't dequeue parent if it has other entities besides us */ /* Don't dequeue parent if it has other entities besides us */
if (cfs_rq->load.weight) if (cfs_rq->load.weight)
break; break;
...@@ -825,14 +820,14 @@ dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep, u64 now) ...@@ -825,14 +820,14 @@ dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep, u64 now)
static void yield_task_fair(struct rq *rq, struct task_struct *p) static void yield_task_fair(struct rq *rq, struct task_struct *p)
{ {
struct cfs_rq *cfs_rq = task_cfs_rq(p); struct cfs_rq *cfs_rq = task_cfs_rq(p);
u64 now = __rq_clock(rq);
__update_rq_clock(rq);
/* /*
* Dequeue and enqueue the task to update its * Dequeue and enqueue the task to update its
* position within the tree: * position within the tree:
*/ */
dequeue_entity(cfs_rq, &p->se, 0, now); dequeue_entity(cfs_rq, &p->se, 0);
enqueue_entity(cfs_rq, &p->se, 0, now); enqueue_entity(cfs_rq, &p->se, 0);
} }
/* /*
...@@ -845,7 +840,8 @@ static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p) ...@@ -845,7 +840,8 @@ static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
unsigned long gran; unsigned long gran;
if (unlikely(rt_prio(p->prio))) { if (unlikely(rt_prio(p->prio))) {
update_curr(cfs_rq, rq_clock(rq)); update_rq_clock(rq);
update_curr(cfs_rq);
resched_task(curr); resched_task(curr);
return; return;
} }
...@@ -861,7 +857,7 @@ static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p) ...@@ -861,7 +857,7 @@ static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
__check_preempt_curr_fair(cfs_rq, &p->se, &curr->se, gran); __check_preempt_curr_fair(cfs_rq, &p->se, &curr->se, gran);
} }
static struct task_struct *pick_next_task_fair(struct rq *rq, u64 now) static struct task_struct *pick_next_task_fair(struct rq *rq)
{ {
struct cfs_rq *cfs_rq = &rq->cfs; struct cfs_rq *cfs_rq = &rq->cfs;
struct sched_entity *se; struct sched_entity *se;
...@@ -870,7 +866,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq, u64 now) ...@@ -870,7 +866,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq, u64 now)
return NULL; return NULL;
do { do {
se = pick_next_entity(cfs_rq, now); se = pick_next_entity(cfs_rq);
cfs_rq = group_cfs_rq(se); cfs_rq = group_cfs_rq(se);
} while (cfs_rq); } while (cfs_rq);
...@@ -880,14 +876,14 @@ static struct task_struct *pick_next_task_fair(struct rq *rq, u64 now) ...@@ -880,14 +876,14 @@ static struct task_struct *pick_next_task_fair(struct rq *rq, u64 now)
/* /*
* Account for a descheduled task: * Account for a descheduled task:
*/ */
static void put_prev_task_fair(struct rq *rq, struct task_struct *prev, u64 now) static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
{ {
struct sched_entity *se = &prev->se; struct sched_entity *se = &prev->se;
struct cfs_rq *cfs_rq; struct cfs_rq *cfs_rq;
for_each_sched_entity(se) { for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se); cfs_rq = cfs_rq_of(se);
put_prev_entity(cfs_rq, se, now); put_prev_entity(cfs_rq, se);
} }
} }
...@@ -930,6 +926,7 @@ static struct task_struct *load_balance_next_fair(void *arg) ...@@ -930,6 +926,7 @@ static struct task_struct *load_balance_next_fair(void *arg)
return __load_balance_iterator(cfs_rq, cfs_rq->rb_load_balance_curr); return __load_balance_iterator(cfs_rq, cfs_rq->rb_load_balance_curr);
} }
#ifdef CONFIG_FAIR_GROUP_SCHED
static int cfs_rq_best_prio(struct cfs_rq *cfs_rq) static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
{ {
struct sched_entity *curr; struct sched_entity *curr;
...@@ -943,12 +940,13 @@ static int cfs_rq_best_prio(struct cfs_rq *cfs_rq) ...@@ -943,12 +940,13 @@ static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
return p->prio; return p->prio;
} }
#endif
static int static unsigned long
load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
unsigned long max_nr_move, unsigned long max_load_move, unsigned long max_nr_move, unsigned long max_load_move,
struct sched_domain *sd, enum cpu_idle_type idle, struct sched_domain *sd, enum cpu_idle_type idle,
int *all_pinned, unsigned long *total_load_moved) int *all_pinned, int *this_best_prio)
{ {
struct cfs_rq *busy_cfs_rq; struct cfs_rq *busy_cfs_rq;
unsigned long load_moved, total_nr_moved = 0, nr_moved; unsigned long load_moved, total_nr_moved = 0, nr_moved;
...@@ -959,10 +957,10 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, ...@@ -959,10 +957,10 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
cfs_rq_iterator.next = load_balance_next_fair; cfs_rq_iterator.next = load_balance_next_fair;
for_each_leaf_cfs_rq(busiest, busy_cfs_rq) { for_each_leaf_cfs_rq(busiest, busy_cfs_rq) {
#ifdef CONFIG_FAIR_GROUP_SCHED
struct cfs_rq *this_cfs_rq; struct cfs_rq *this_cfs_rq;
long imbalance; long imbalances;
unsigned long maxload; unsigned long maxload;
int this_best_prio, best_prio, best_prio_seen = 0;
this_cfs_rq = cpu_cfs_rq(busy_cfs_rq, this_cpu); this_cfs_rq = cpu_cfs_rq(busy_cfs_rq, this_cpu);
...@@ -976,27 +974,17 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, ...@@ -976,27 +974,17 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
imbalance /= 2; imbalance /= 2;
maxload = min(rem_load_move, imbalance); maxload = min(rem_load_move, imbalance);
this_best_prio = cfs_rq_best_prio(this_cfs_rq); *this_best_prio = cfs_rq_best_prio(this_cfs_rq);
best_prio = cfs_rq_best_prio(busy_cfs_rq); #else
#define maxload rem_load_move
/* #endif
* Enable handling of the case where there is more than one task
* with the best priority. If the current running task is one
* of those with prio==best_prio we know it won't be moved
* and therefore it's safe to override the skip (based on load)
* of any task we find with that prio.
*/
if (cfs_rq_curr(busy_cfs_rq) == &busiest->curr->se)
best_prio_seen = 1;
/* pass busy_cfs_rq argument into /* pass busy_cfs_rq argument into
* load_balance_[start|next]_fair iterators * load_balance_[start|next]_fair iterators
*/ */
cfs_rq_iterator.arg = busy_cfs_rq; cfs_rq_iterator.arg = busy_cfs_rq;
nr_moved = balance_tasks(this_rq, this_cpu, busiest, nr_moved = balance_tasks(this_rq, this_cpu, busiest,
max_nr_move, maxload, sd, idle, all_pinned, max_nr_move, maxload, sd, idle, all_pinned,
&load_moved, this_best_prio, best_prio, &load_moved, this_best_prio, &cfs_rq_iterator);
best_prio_seen, &cfs_rq_iterator);
total_nr_moved += nr_moved; total_nr_moved += nr_moved;
max_nr_move -= nr_moved; max_nr_move -= nr_moved;
...@@ -1006,9 +994,7 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, ...@@ -1006,9 +994,7 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
break; break;
} }
*total_load_moved = max_load_move - rem_load_move; return max_load_move - rem_load_move;
return total_nr_moved;
} }
/* /*
...@@ -1032,14 +1018,14 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr) ...@@ -1032,14 +1018,14 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr)
* monopolize the CPU. Note: the parent runqueue is locked, * monopolize the CPU. Note: the parent runqueue is locked,
* the child is not running yet. * the child is not running yet.
*/ */
static void task_new_fair(struct rq *rq, struct task_struct *p, u64 now) static void task_new_fair(struct rq *rq, struct task_struct *p)
{ {
struct cfs_rq *cfs_rq = task_cfs_rq(p); struct cfs_rq *cfs_rq = task_cfs_rq(p);
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
sched_info_queued(p); sched_info_queued(p);
update_stats_enqueue(cfs_rq, se, now); update_stats_enqueue(cfs_rq, se);
/* /*
* Child runs first: we let it run before the parent * Child runs first: we let it run before the parent
* until it reschedules once. We set up the key so that * until it reschedules once. We set up the key so that
...@@ -1072,15 +1058,10 @@ static void task_new_fair(struct rq *rq, struct task_struct *p, u64 now) ...@@ -1072,15 +1058,10 @@ static void task_new_fair(struct rq *rq, struct task_struct *p, u64 now)
*/ */
static void set_curr_task_fair(struct rq *rq) static void set_curr_task_fair(struct rq *rq)
{ {
struct task_struct *curr = rq->curr; struct sched_entity *se = &rq->curr.se;
struct sched_entity *se = &curr->se;
u64 now = rq_clock(rq);
struct cfs_rq *cfs_rq;
for_each_sched_entity(se) { for_each_sched_entity(se)
cfs_rq = cfs_rq_of(se); set_next_entity(cfs_rq_of(se), se);
set_next_entity(cfs_rq, se, now);
}
} }
#else #else
static void set_curr_task_fair(struct rq *rq) static void set_curr_task_fair(struct rq *rq)
...@@ -1109,12 +1090,11 @@ struct sched_class fair_sched_class __read_mostly = { ...@@ -1109,12 +1090,11 @@ struct sched_class fair_sched_class __read_mostly = {
}; };
#ifdef CONFIG_SCHED_DEBUG #ifdef CONFIG_SCHED_DEBUG
void print_cfs_stats(struct seq_file *m, int cpu, u64 now) static void print_cfs_stats(struct seq_file *m, int cpu)
{ {
struct rq *rq = cpu_rq(cpu);
struct cfs_rq *cfs_rq; struct cfs_rq *cfs_rq;
for_each_leaf_cfs_rq(rq, cfs_rq) for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
print_cfs_rq(m, cpu, cfs_rq, now); print_cfs_rq(m, cpu, cfs_rq);
} }
#endif #endif
...@@ -13,7 +13,7 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p) ...@@ -13,7 +13,7 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p)
resched_task(rq->idle); resched_task(rq->idle);
} }
static struct task_struct *pick_next_task_idle(struct rq *rq, u64 now) static struct task_struct *pick_next_task_idle(struct rq *rq)
{ {
schedstat_inc(rq, sched_goidle); schedstat_inc(rq, sched_goidle);
...@@ -25,7 +25,7 @@ static struct task_struct *pick_next_task_idle(struct rq *rq, u64 now) ...@@ -25,7 +25,7 @@ static struct task_struct *pick_next_task_idle(struct rq *rq, u64 now)
* message if some code attempts to do it: * message if some code attempts to do it:
*/ */
static void static void
dequeue_task_idle(struct rq *rq, struct task_struct *p, int sleep, u64 now) dequeue_task_idle(struct rq *rq, struct task_struct *p, int sleep)
{ {
spin_unlock_irq(&rq->lock); spin_unlock_irq(&rq->lock);
printk(KERN_ERR "bad: scheduling from the idle thread!\n"); printk(KERN_ERR "bad: scheduling from the idle thread!\n");
...@@ -33,15 +33,15 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int sleep, u64 now) ...@@ -33,15 +33,15 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int sleep, u64 now)
spin_lock_irq(&rq->lock); spin_lock_irq(&rq->lock);
} }
static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, u64 now) static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
{ {
} }
static int static unsigned long
load_balance_idle(struct rq *this_rq, int this_cpu, struct rq *busiest, load_balance_idle(struct rq *this_rq, int this_cpu, struct rq *busiest,
unsigned long max_nr_move, unsigned long max_load_move, unsigned long max_nr_move, unsigned long max_load_move,
struct sched_domain *sd, enum cpu_idle_type idle, struct sched_domain *sd, enum cpu_idle_type idle,
int *all_pinned, unsigned long *total_load_moved) int *all_pinned, int *this_best_prio)
{ {
return 0; return 0;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Update the current task's runtime statistics. Skip current tasks that * Update the current task's runtime statistics. Skip current tasks that
* are not in our scheduling class. * are not in our scheduling class.
*/ */
static inline void update_curr_rt(struct rq *rq, u64 now) static inline void update_curr_rt(struct rq *rq)
{ {
struct task_struct *curr = rq->curr; struct task_struct *curr = rq->curr;
u64 delta_exec; u64 delta_exec;
...@@ -15,18 +15,17 @@ static inline void update_curr_rt(struct rq *rq, u64 now) ...@@ -15,18 +15,17 @@ static inline void update_curr_rt(struct rq *rq, u64 now)
if (!task_has_rt_policy(curr)) if (!task_has_rt_policy(curr))
return; return;
delta_exec = now - curr->se.exec_start; delta_exec = rq->clock - curr->se.exec_start;
if (unlikely((s64)delta_exec < 0)) if (unlikely((s64)delta_exec < 0))
delta_exec = 0; delta_exec = 0;
schedstat_set(curr->se.exec_max, max(curr->se.exec_max, delta_exec)); schedstat_set(curr->se.exec_max, max(curr->se.exec_max, delta_exec));
curr->se.sum_exec_runtime += delta_exec; curr->se.sum_exec_runtime += delta_exec;
curr->se.exec_start = now; curr->se.exec_start = rq->clock;
} }
static void static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup)
enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
{ {
struct rt_prio_array *array = &rq->rt.active; struct rt_prio_array *array = &rq->rt.active;
...@@ -37,12 +36,11 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup, u64 now) ...@@ -37,12 +36,11 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
/* /*
* Adding/removing a task to/from a priority array: * Adding/removing a task to/from a priority array:
*/ */
static void static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep)
dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep, u64 now)
{ {
struct rt_prio_array *array = &rq->rt.active; struct rt_prio_array *array = &rq->rt.active;
update_curr_rt(rq, now); update_curr_rt(rq);
list_del(&p->run_list); list_del(&p->run_list);
if (list_empty(array->queue + p->prio)) if (list_empty(array->queue + p->prio))
...@@ -75,7 +73,7 @@ static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p) ...@@ -75,7 +73,7 @@ static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p)
resched_task(rq->curr); resched_task(rq->curr);
} }
static struct task_struct *pick_next_task_rt(struct rq *rq, u64 now) static struct task_struct *pick_next_task_rt(struct rq *rq)
{ {
struct rt_prio_array *array = &rq->rt.active; struct rt_prio_array *array = &rq->rt.active;
struct task_struct *next; struct task_struct *next;
...@@ -89,14 +87,14 @@ static struct task_struct *pick_next_task_rt(struct rq *rq, u64 now) ...@@ -89,14 +87,14 @@ static struct task_struct *pick_next_task_rt(struct rq *rq, u64 now)
queue = array->queue + idx; queue = array->queue + idx;
next = list_entry(queue->next, struct task_struct, run_list); next = list_entry(queue->next, struct task_struct, run_list);
next->se.exec_start = now; next->se.exec_start = rq->clock;
return next; return next;
} }
static void put_prev_task_rt(struct rq *rq, struct task_struct *p, u64 now) static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
{ {
update_curr_rt(rq, now); update_curr_rt(rq);
p->se.exec_start = 0; p->se.exec_start = 0;
} }
...@@ -172,28 +170,15 @@ static struct task_struct *load_balance_next_rt(void *arg) ...@@ -172,28 +170,15 @@ static struct task_struct *load_balance_next_rt(void *arg)
return p; return p;
} }
static int static unsigned long
load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest,
unsigned long max_nr_move, unsigned long max_load_move, unsigned long max_nr_move, unsigned long max_load_move,
struct sched_domain *sd, enum cpu_idle_type idle, struct sched_domain *sd, enum cpu_idle_type idle,
int *all_pinned, unsigned long *load_moved) int *all_pinned, int *this_best_prio)
{ {
int this_best_prio, best_prio, best_prio_seen = 0;
int nr_moved; int nr_moved;
struct rq_iterator rt_rq_iterator; struct rq_iterator rt_rq_iterator;
unsigned long load_moved;
best_prio = sched_find_first_bit(busiest->rt.active.bitmap);
this_best_prio = sched_find_first_bit(this_rq->rt.active.bitmap);
/*
* Enable handling of the case where there is more than one task
* with the best priority. If the current running task is one
* of those with prio==best_prio we know it won't be moved
* and therefore it's safe to override the skip (based on load)
* of any task we find with that prio.
*/
if (busiest->curr->prio == best_prio)
best_prio_seen = 1;
rt_rq_iterator.start = load_balance_start_rt; rt_rq_iterator.start = load_balance_start_rt;
rt_rq_iterator.next = load_balance_next_rt; rt_rq_iterator.next = load_balance_next_rt;
...@@ -203,11 +188,10 @@ load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, ...@@ -203,11 +188,10 @@ load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest,
rt_rq_iterator.arg = busiest; rt_rq_iterator.arg = busiest;
nr_moved = balance_tasks(this_rq, this_cpu, busiest, max_nr_move, nr_moved = balance_tasks(this_rq, this_cpu, busiest, max_nr_move,
max_load_move, sd, idle, all_pinned, load_moved, max_load_move, sd, idle, all_pinned, &load_moved,
this_best_prio, best_prio, best_prio_seen, this_best_prio, &rt_rq_iterator);
&rt_rq_iterator);
return nr_moved; return load_moved;
} }
static void task_tick_rt(struct rq *rq, struct task_struct *p) static void task_tick_rt(struct rq *rq, struct task_struct *p)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册