diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2008-04-19 13:44:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-19 13:44:58 -0400 |
commit | ac086bc22997a2be24fc40fc8d46522fe7e03d11 (patch) | |
tree | 7a484ba13acbdf0fa98c896ce58e807b4b5b1af9 /kernel/sched.c | |
parent | d0b27fa77854b149ad4af08b0fe47fe712a47ade (diff) |
sched: rt-group: smp balancing
Currently the rt group scheduling does a per cpu runtime limit, however
the rt load balancer makes no guarantees about an equal spread of real-
time tasks, just that at any one time, the highest priority tasks run.
Solve this by making the runtime limit a global property by borrowing
excessive runtime from the other cpus once the local limit runs out.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index bb20323f7d09..313cd4f057cf 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -164,6 +164,7 @@ struct rt_prio_array { | |||
164 | struct rt_bandwidth { | 164 | struct rt_bandwidth { |
165 | ktime_t rt_period; | 165 | ktime_t rt_period; |
166 | u64 rt_runtime; | 166 | u64 rt_runtime; |
167 | spinlock_t rt_runtime_lock; | ||
167 | struct hrtimer rt_period_timer; | 168 | struct hrtimer rt_period_timer; |
168 | }; | 169 | }; |
169 | 170 | ||
@@ -198,6 +199,8 @@ void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime) | |||
198 | rt_b->rt_period = ns_to_ktime(period); | 199 | rt_b->rt_period = ns_to_ktime(period); |
199 | rt_b->rt_runtime = runtime; | 200 | rt_b->rt_runtime = runtime; |
200 | 201 | ||
202 | spin_lock_init(&rt_b->rt_runtime_lock); | ||
203 | |||
201 | hrtimer_init(&rt_b->rt_period_timer, | 204 | hrtimer_init(&rt_b->rt_period_timer, |
202 | CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 205 | CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
203 | rt_b->rt_period_timer.function = sched_rt_period_timer; | 206 | rt_b->rt_period_timer.function = sched_rt_period_timer; |
@@ -414,6 +417,8 @@ struct rt_rq { | |||
414 | #endif | 417 | #endif |
415 | int rt_throttled; | 418 | int rt_throttled; |
416 | u64 rt_time; | 419 | u64 rt_time; |
420 | u64 rt_runtime; | ||
421 | spinlock_t rt_runtime_lock; | ||
417 | 422 | ||
418 | #ifdef CONFIG_RT_GROUP_SCHED | 423 | #ifdef CONFIG_RT_GROUP_SCHED |
419 | unsigned long rt_nr_boosted; | 424 | unsigned long rt_nr_boosted; |
@@ -7299,6 +7304,8 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) | |||
7299 | 7304 | ||
7300 | rt_rq->rt_time = 0; | 7305 | rt_rq->rt_time = 0; |
7301 | rt_rq->rt_throttled = 0; | 7306 | rt_rq->rt_throttled = 0; |
7307 | rt_rq->rt_runtime = 0; | ||
7308 | spin_lock_init(&rt_rq->rt_runtime_lock); | ||
7302 | 7309 | ||
7303 | #ifdef CONFIG_RT_GROUP_SCHED | 7310 | #ifdef CONFIG_RT_GROUP_SCHED |
7304 | rt_rq->rt_nr_boosted = 0; | 7311 | rt_rq->rt_nr_boosted = 0; |
@@ -7335,6 +7342,7 @@ static void init_tg_rt_entry(struct rq *rq, struct task_group *tg, | |||
7335 | init_rt_rq(rt_rq, rq); | 7342 | init_rt_rq(rt_rq, rq); |
7336 | rt_rq->tg = tg; | 7343 | rt_rq->tg = tg; |
7337 | rt_rq->rt_se = rt_se; | 7344 | rt_rq->rt_se = rt_se; |
7345 | rt_rq->rt_runtime = tg->rt_bandwidth.rt_runtime; | ||
7338 | if (add) | 7346 | if (add) |
7339 | list_add(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list); | 7347 | list_add(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list); |
7340 | 7348 | ||
@@ -7391,6 +7399,8 @@ void __init sched_init(void) | |||
7391 | init_tg_rt_entry(rq, &init_task_group, | 7399 | init_tg_rt_entry(rq, &init_task_group, |
7392 | &per_cpu(init_rt_rq, i), | 7400 | &per_cpu(init_rt_rq, i), |
7393 | &per_cpu(init_sched_rt_entity, i), i, 1); | 7401 | &per_cpu(init_sched_rt_entity, i), i, 1); |
7402 | #else | ||
7403 | rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime; | ||
7394 | #endif | 7404 | #endif |
7395 | 7405 | ||
7396 | for (j = 0; j < CPU_LOAD_IDX_MAX; j++) | 7406 | for (j = 0; j < CPU_LOAD_IDX_MAX; j++) |
@@ -7974,11 +7984,11 @@ static inline int tg_has_rt_tasks(struct task_group *tg) | |||
7974 | static int tg_set_bandwidth(struct task_group *tg, | 7984 | static int tg_set_bandwidth(struct task_group *tg, |
7975 | u64 rt_period, u64 rt_runtime) | 7985 | u64 rt_period, u64 rt_runtime) |
7976 | { | 7986 | { |
7977 | int err = 0; | 7987 | int i, err = 0; |
7978 | 7988 | ||
7979 | mutex_lock(&rt_constraints_mutex); | 7989 | mutex_lock(&rt_constraints_mutex); |
7980 | read_lock(&tasklist_lock); | 7990 | read_lock(&tasklist_lock); |
7981 | if (rt_runtime_us == 0 && tg_has_rt_tasks(tg)) { | 7991 | if (rt_runtime == 0 && tg_has_rt_tasks(tg)) { |
7982 | err = -EBUSY; | 7992 | err = -EBUSY; |
7983 | goto unlock; | 7993 | goto unlock; |
7984 | } | 7994 | } |
@@ -7986,8 +7996,19 @@ static int tg_set_bandwidth(struct task_group *tg, | |||
7986 | err = -EINVAL; | 7996 | err = -EINVAL; |
7987 | goto unlock; | 7997 | goto unlock; |
7988 | } | 7998 | } |
7999 | |||
8000 | spin_lock_irq(&tg->rt_bandwidth.rt_runtime_lock); | ||
7989 | tg->rt_bandwidth.rt_period = ns_to_ktime(rt_period); | 8001 | tg->rt_bandwidth.rt_period = ns_to_ktime(rt_period); |
7990 | tg->rt_bandwidth.rt_runtime = rt_runtime; | 8002 | tg->rt_bandwidth.rt_runtime = rt_runtime; |
8003 | |||
8004 | for_each_possible_cpu(i) { | ||
8005 | struct rt_rq *rt_rq = tg->rt_rq[i]; | ||
8006 | |||
8007 | spin_lock(&rt_rq->rt_runtime_lock); | ||
8008 | rt_rq->rt_runtime = rt_runtime; | ||
8009 | spin_unlock(&rt_rq->rt_runtime_lock); | ||
8010 | } | ||
8011 | spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock); | ||
7991 | unlock: | 8012 | unlock: |
7992 | read_unlock(&tasklist_lock); | 8013 | read_unlock(&tasklist_lock); |
7993 | mutex_unlock(&rt_constraints_mutex); | 8014 | mutex_unlock(&rt_constraints_mutex); |
@@ -8052,6 +8073,19 @@ static int sched_rt_global_constraints(void) | |||
8052 | #else | 8073 | #else |
8053 | static int sched_rt_global_constraints(void) | 8074 | static int sched_rt_global_constraints(void) |
8054 | { | 8075 | { |
8076 | unsigned long flags; | ||
8077 | int i; | ||
8078 | |||
8079 | spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags); | ||
8080 | for_each_possible_cpu(i) { | ||
8081 | struct rt_rq *rt_rq = &cpu_rq(i)->rt; | ||
8082 | |||
8083 | spin_lock(&rt_rq->rt_runtime_lock); | ||
8084 | rt_rq->rt_runtime = global_rt_runtime(); | ||
8085 | spin_unlock(&rt_rq->rt_runtime_lock); | ||
8086 | } | ||
8087 | spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags); | ||
8088 | |||
8055 | return 0; | 8089 | return 0; |
8056 | } | 8090 | } |
8057 | #endif | 8091 | #endif |
@@ -8168,7 +8202,7 @@ static u64 cpu_shares_read_uint(struct cgroup *cgrp, struct cftype *cft) | |||
8168 | #endif | 8202 | #endif |
8169 | 8203 | ||
8170 | #ifdef CONFIG_RT_GROUP_SCHED | 8204 | #ifdef CONFIG_RT_GROUP_SCHED |
8171 | static int cpu_rt_runtime_write(struct cgroup *cgrp, struct cftype *cft, | 8205 | static ssize_t cpu_rt_runtime_write(struct cgroup *cgrp, struct cftype *cft, |
8172 | struct file *file, | 8206 | struct file *file, |
8173 | const char __user *userbuf, | 8207 | const char __user *userbuf, |
8174 | size_t nbytes, loff_t *unused_ppos) | 8208 | size_t nbytes, loff_t *unused_ppos) |