diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-20 13:35:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-20 13:35:05 -0400 |
commit | 53795ced6e270fbb5cef7b527a71ffbb69657c78 (patch) | |
tree | 0e0532682837493bb84a38df10bc115521226c81 /kernel | |
parent | f78602ab7cbc902559406d2e8e21517056708295 (diff) | |
parent | 8f6189684eb4e85e6c593cd710693f09c944450a (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.
* 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
sched: Fix migration thread runtime bogosity
sched,rt: fix isolated CPUs leaving root_task_group indefinitely throttled
sched,cgroup: Fix up task_groups list
sched: fix divide by zero at {thread_group,task}_times
sched, cgroup: Reduce rq->lock hold times for large cgroup hierarchies
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched/core.c | 35 | ||||
-rw-r--r-- | kernel/sched/fair.c | 11 | ||||
-rw-r--r-- | kernel/sched/rt.c | 13 | ||||
-rw-r--r-- | kernel/sched/sched.h | 8 | ||||
-rw-r--r-- | kernel/sched/stop_task.c | 22 |
5 files changed, 70 insertions, 19 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 82ad284f823b..fbf1fd098dc6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -3142,6 +3142,20 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) | |||
3142 | # define nsecs_to_cputime(__nsecs) nsecs_to_jiffies(__nsecs) | 3142 | # define nsecs_to_cputime(__nsecs) nsecs_to_jiffies(__nsecs) |
3143 | #endif | 3143 | #endif |
3144 | 3144 | ||
3145 | static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total) | ||
3146 | { | ||
3147 | u64 temp = (__force u64) rtime; | ||
3148 | |||
3149 | temp *= (__force u64) utime; | ||
3150 | |||
3151 | if (sizeof(cputime_t) == 4) | ||
3152 | temp = div_u64(temp, (__force u32) total); | ||
3153 | else | ||
3154 | temp = div64_u64(temp, (__force u64) total); | ||
3155 | |||
3156 | return (__force cputime_t) temp; | ||
3157 | } | ||
3158 | |||
3145 | void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) | 3159 | void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) |
3146 | { | 3160 | { |
3147 | cputime_t rtime, utime = p->utime, total = utime + p->stime; | 3161 | cputime_t rtime, utime = p->utime, total = utime + p->stime; |
@@ -3151,13 +3165,9 @@ void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) | |||
3151 | */ | 3165 | */ |
3152 | rtime = nsecs_to_cputime(p->se.sum_exec_runtime); | 3166 | rtime = nsecs_to_cputime(p->se.sum_exec_runtime); |
3153 | 3167 | ||
3154 | if (total) { | 3168 | if (total) |
3155 | u64 temp = (__force u64) rtime; | 3169 | utime = scale_utime(utime, rtime, total); |
3156 | 3170 | else | |
3157 | temp *= (__force u64) utime; | ||
3158 | do_div(temp, (__force u32) total); | ||
3159 | utime = (__force cputime_t) temp; | ||
3160 | } else | ||
3161 | utime = rtime; | 3171 | utime = rtime; |
3162 | 3172 | ||
3163 | /* | 3173 | /* |
@@ -3184,13 +3194,9 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) | |||
3184 | total = cputime.utime + cputime.stime; | 3194 | total = cputime.utime + cputime.stime; |
3185 | rtime = nsecs_to_cputime(cputime.sum_exec_runtime); | 3195 | rtime = nsecs_to_cputime(cputime.sum_exec_runtime); |
3186 | 3196 | ||
3187 | if (total) { | 3197 | if (total) |
3188 | u64 temp = (__force u64) rtime; | 3198 | utime = scale_utime(cputime.utime, rtime, total); |
3189 | 3199 | else | |
3190 | temp *= (__force u64) cputime.utime; | ||
3191 | do_div(temp, (__force u32) total); | ||
3192 | utime = (__force cputime_t) temp; | ||
3193 | } else | ||
3194 | utime = rtime; | 3200 | utime = rtime; |
3195 | 3201 | ||
3196 | sig->prev_utime = max(sig->prev_utime, utime); | 3202 | sig->prev_utime = max(sig->prev_utime, utime); |
@@ -7246,6 +7252,7 @@ int in_sched_functions(unsigned long addr) | |||
7246 | 7252 | ||
7247 | #ifdef CONFIG_CGROUP_SCHED | 7253 | #ifdef CONFIG_CGROUP_SCHED |
7248 | struct task_group root_task_group; | 7254 | struct task_group root_task_group; |
7255 | LIST_HEAD(task_groups); | ||
7249 | #endif | 7256 | #endif |
7250 | 7257 | ||
7251 | DECLARE_PER_CPU(cpumask_var_t, load_balance_tmpmask); | 7258 | DECLARE_PER_CPU(cpumask_var_t, load_balance_tmpmask); |
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index d0cc03b3e70b..c219bf8d704c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
@@ -3387,6 +3387,14 @@ static int tg_load_down(struct task_group *tg, void *data) | |||
3387 | 3387 | ||
3388 | static void update_h_load(long cpu) | 3388 | static void update_h_load(long cpu) |
3389 | { | 3389 | { |
3390 | struct rq *rq = cpu_rq(cpu); | ||
3391 | unsigned long now = jiffies; | ||
3392 | |||
3393 | if (rq->h_load_throttle == now) | ||
3394 | return; | ||
3395 | |||
3396 | rq->h_load_throttle = now; | ||
3397 | |||
3390 | rcu_read_lock(); | 3398 | rcu_read_lock(); |
3391 | walk_tg_tree(tg_load_down, tg_nop, (void *)cpu); | 3399 | walk_tg_tree(tg_load_down, tg_nop, (void *)cpu); |
3392 | rcu_read_unlock(); | 3400 | rcu_read_unlock(); |
@@ -4293,11 +4301,10 @@ redo: | |||
4293 | env.src_rq = busiest; | 4301 | env.src_rq = busiest; |
4294 | env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running); | 4302 | env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running); |
4295 | 4303 | ||
4304 | update_h_load(env.src_cpu); | ||
4296 | more_balance: | 4305 | more_balance: |
4297 | local_irq_save(flags); | 4306 | local_irq_save(flags); |
4298 | double_rq_lock(this_rq, busiest); | 4307 | double_rq_lock(this_rq, busiest); |
4299 | if (!env.loop) | ||
4300 | update_h_load(env.src_cpu); | ||
4301 | 4308 | ||
4302 | /* | 4309 | /* |
4303 | * cur_ld_moved - load moved in current iteration | 4310 | * cur_ld_moved - load moved in current iteration |
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 573e1ca01102..944cb68420e9 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c | |||
@@ -788,6 +788,19 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun) | |||
788 | const struct cpumask *span; | 788 | const struct cpumask *span; |
789 | 789 | ||
790 | span = sched_rt_period_mask(); | 790 | span = sched_rt_period_mask(); |
791 | #ifdef CONFIG_RT_GROUP_SCHED | ||
792 | /* | ||
793 | * FIXME: isolated CPUs should really leave the root task group, | ||
794 | * whether they are isolcpus or were isolated via cpusets, lest | ||
795 | * the timer run on a CPU which does not service all runqueues, | ||
796 | * potentially leaving other CPUs indefinitely throttled. If | ||
797 | * isolation is really required, the user will turn the throttle | ||
798 | * off to kill the perturbations it causes anyway. Meanwhile, | ||
799 | * this maintains functionality for boot and/or troubleshooting. | ||
800 | */ | ||
801 | if (rt_b == &root_task_group.rt_bandwidth) | ||
802 | span = cpu_online_mask; | ||
803 | #endif | ||
791 | for_each_cpu(i, span) { | 804 | for_each_cpu(i, span) { |
792 | int enqueue = 0; | 805 | int enqueue = 0; |
793 | struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i); | 806 | struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i); |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c35a1a7dd4d6..f6714d009e77 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -80,7 +80,7 @@ extern struct mutex sched_domains_mutex; | |||
80 | struct cfs_rq; | 80 | struct cfs_rq; |
81 | struct rt_rq; | 81 | struct rt_rq; |
82 | 82 | ||
83 | static LIST_HEAD(task_groups); | 83 | extern struct list_head task_groups; |
84 | 84 | ||
85 | struct cfs_bandwidth { | 85 | struct cfs_bandwidth { |
86 | #ifdef CONFIG_CFS_BANDWIDTH | 86 | #ifdef CONFIG_CFS_BANDWIDTH |
@@ -374,7 +374,11 @@ struct rq { | |||
374 | #ifdef CONFIG_FAIR_GROUP_SCHED | 374 | #ifdef CONFIG_FAIR_GROUP_SCHED |
375 | /* list of leaf cfs_rq on this cpu: */ | 375 | /* list of leaf cfs_rq on this cpu: */ |
376 | struct list_head leaf_cfs_rq_list; | 376 | struct list_head leaf_cfs_rq_list; |
377 | #endif | 377 | #ifdef CONFIG_SMP |
378 | unsigned long h_load_throttle; | ||
379 | #endif /* CONFIG_SMP */ | ||
380 | #endif /* CONFIG_FAIR_GROUP_SCHED */ | ||
381 | |||
378 | #ifdef CONFIG_RT_GROUP_SCHED | 382 | #ifdef CONFIG_RT_GROUP_SCHED |
379 | struct list_head leaf_rt_rq_list; | 383 | struct list_head leaf_rt_rq_list; |
380 | #endif | 384 | #endif |
diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c index 7b386e86fd23..da5eb5bed84a 100644 --- a/kernel/sched/stop_task.c +++ b/kernel/sched/stop_task.c | |||
@@ -27,8 +27,10 @@ static struct task_struct *pick_next_task_stop(struct rq *rq) | |||
27 | { | 27 | { |
28 | struct task_struct *stop = rq->stop; | 28 | struct task_struct *stop = rq->stop; |
29 | 29 | ||
30 | if (stop && stop->on_rq) | 30 | if (stop && stop->on_rq) { |
31 | stop->se.exec_start = rq->clock_task; | ||
31 | return stop; | 32 | return stop; |
33 | } | ||
32 | 34 | ||
33 | return NULL; | 35 | return NULL; |
34 | } | 36 | } |
@@ -52,6 +54,21 @@ static void yield_task_stop(struct rq *rq) | |||
52 | 54 | ||
53 | static void put_prev_task_stop(struct rq *rq, struct task_struct *prev) | 55 | static void put_prev_task_stop(struct rq *rq, struct task_struct *prev) |
54 | { | 56 | { |
57 | struct task_struct *curr = rq->curr; | ||
58 | u64 delta_exec; | ||
59 | |||
60 | delta_exec = rq->clock_task - curr->se.exec_start; | ||
61 | if (unlikely((s64)delta_exec < 0)) | ||
62 | delta_exec = 0; | ||
63 | |||
64 | schedstat_set(curr->se.statistics.exec_max, | ||
65 | max(curr->se.statistics.exec_max, delta_exec)); | ||
66 | |||
67 | curr->se.sum_exec_runtime += delta_exec; | ||
68 | account_group_exec_runtime(curr, delta_exec); | ||
69 | |||
70 | curr->se.exec_start = rq->clock_task; | ||
71 | cpuacct_charge(curr, delta_exec); | ||
55 | } | 72 | } |
56 | 73 | ||
57 | static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued) | 74 | static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued) |
@@ -60,6 +77,9 @@ static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued) | |||
60 | 77 | ||
61 | static void set_curr_task_stop(struct rq *rq) | 78 | static void set_curr_task_stop(struct rq *rq) |
62 | { | 79 | { |
80 | struct task_struct *stop = rq->stop; | ||
81 | |||
82 | stop->se.exec_start = rq->clock_task; | ||
63 | } | 83 | } |
64 | 84 | ||
65 | static void switched_to_stop(struct rq *rq, struct task_struct *p) | 85 | static void switched_to_stop(struct rq *rq, struct task_struct *p) |