aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched.c
diff options
context:
space:
mode:
authorGregory Haskins <ghaskins@novell.com>2008-12-29 09:39:53 -0500
committerGregory Haskins <ghaskins@novell.com>2008-12-29 09:39:53 -0500
commit917b627d4d981dc614519d7b34ea31a976b14e12 (patch)
treeedb1744bd3f943ee79ee4f6c995c48a28421504c /kernel/sched.c
parent4075134e40804821f90866d7de56802e4dcecb1e (diff)
sched: create "pushable_tasks" list to limit pushing to one attempt
The RT scheduler employs a "push/pull" design to actively balance tasks within the system (on a per disjoint cpuset basis). When a task is awoken, it is immediately determined if there are any lower priority cpus which should be preempted. This is opposed to the way normal SCHED_OTHER tasks behave, which will wait for a periodic rebalancing operation to occur before spreading out load. When a particular RQ has more than 1 active RT task, it is said to be in an "overloaded" state. Once this occurs, the system enters the active balancing mode, where it will try to push the task away, or persuade a different cpu to pull it over. The system will stay in this state until the system falls back below the <= 1 queued RT task per RQ. However, the current implementation suffers from a limitation in the push logic. Once overloaded, all tasks (other than current) on the RQ are analyzed on every push operation, even if it was previously unpushable (due to affinity, etc). Whats more, the operation stops at the first task that is unpushable and will not look at items lower in the queue. This causes two problems: 1) We can have the same tasks analyzed over and over again during each push, which extends out the fast path in the scheduler for no gain. Consider a RQ that has dozens of tasks that are bound to a core. Each one of those tasks will be encountered and skipped for each push operation while they are queued. 2) There may be lower-priority tasks under the unpushable task that could have been successfully pushed, but will never be considered until either the unpushable task is cleared, or a pull operation succeeds. The net result is a potential latency source for mid priority tasks. This patch aims to rectify these two conditions by introducing a new priority sorted list: "pushable_tasks". A task is added to the list each time a task is activated or preempted. It is removed from the list any time it is deactivated, made current, or fails to push. This works because a task only needs to be attempted to push once. After an initial failure to push, the other cpus will eventually try to pull the task when the conditions are proper. This also solves the problem that we don't completely analyze all tasks due to encountering an unpushable tasks. Now every task will have a push attempted (when appropriate). This reduces latency both by shorting the critical section of the rq->lock for certain workloads, and by making sure the algorithm considers all eligible tasks in the system. [ rostedt: added a couple more BUG_ONs ] Signed-off-by: Gregory Haskins <ghaskins@novell.com> Acked-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r--kernel/sched.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 3acbad8991a..24ab80c2876 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -471,6 +471,7 @@ struct rt_rq {
471#ifdef CONFIG_SMP 471#ifdef CONFIG_SMP
472 unsigned long rt_nr_migratory; 472 unsigned long rt_nr_migratory;
473 int overloaded; 473 int overloaded;
474 struct plist_head pushable_tasks;
474#endif 475#endif
475 int rt_throttled; 476 int rt_throttled;
476 u64 rt_time; 477 u64 rt_time;
@@ -2481,6 +2482,8 @@ void sched_fork(struct task_struct *p, int clone_flags)
2481 /* Want to start with kernel preemption disabled. */ 2482 /* Want to start with kernel preemption disabled. */
2482 task_thread_info(p)->preempt_count = 1; 2483 task_thread_info(p)->preempt_count = 1;
2483#endif 2484#endif
2485 plist_node_init(&p->pushable_tasks, MAX_PRIO);
2486
2484 put_cpu(); 2487 put_cpu();
2485} 2488}
2486 2489
@@ -8237,6 +8240,7 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq)
8237#ifdef CONFIG_SMP 8240#ifdef CONFIG_SMP
8238 rt_rq->rt_nr_migratory = 0; 8241 rt_rq->rt_nr_migratory = 0;
8239 rt_rq->overloaded = 0; 8242 rt_rq->overloaded = 0;
8243 plist_head_init(&rq->rt.pushable_tasks, &rq->lock);
8240#endif 8244#endif
8241 8245
8242 rt_rq->rt_time = 0; 8246 rt_rq->rt_time = 0;