[PATCH v3 05/17] pull RT tasks

2007-11-16 Thread Steven Rostedt
This patch adds the algorithm to pull tasks from RT overloaded runqueues.

When a pull RT is initiated, all overloaded runqueues are examined for
a RT task that is higher in prio than the highest prio task queued on the
target runqueue. If another runqueue holds a RT task that is of higher
prio than the highest prio task on the target runqueue is found it is pulled
to the target runqueue.

Signed-off-by: Steven Rostedt <[EMAIL PROTECTED]>

---
 kernel/sched.c|2 
 kernel/sched_rt.c |  196 ++
 2 files changed, 187 insertions(+), 11 deletions(-)

Index: linux-compile.git/kernel/sched.c
===
--- linux-compile.git.orig/kernel/sched.c   2007-11-16 22:11:37.0 
-0500
+++ linux-compile.git/kernel/sched.c2007-11-16 22:12:13.0 -0500
@@ -3646,6 +3646,8 @@ need_resched_nonpreemptible:
switch_count = >nvcsw;
}
 
+   schedule_balance_rt(rq, prev);
+
if (unlikely(!rq->nr_running))
idle_balance(cpu, rq);
 
Index: linux-compile.git/kernel/sched_rt.c
===
--- linux-compile.git.orig/kernel/sched_rt.c2007-11-16 22:12:07.0 
-0500
+++ linux-compile.git/kernel/sched_rt.c 2007-11-16 22:12:13.0 -0500
@@ -176,8 +176,17 @@ static void put_prev_task_rt(struct rq *
 static int double_lock_balance(struct rq *this_rq, struct rq *busiest);
 static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep);
 
+static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
+{
+   if (!task_running(rq, p) &&
+   (cpu < 0 || cpu_isset(cpu, p->cpus_allowed)))
+   return 1;
+   return 0;
+}
+
 /* Return the second highest RT task, NULL otherwise */
-static struct task_struct *pick_next_highest_task_rt(struct rq *rq)
+static struct task_struct *pick_next_highest_task_rt(struct rq *rq,
+int cpu)
 {
struct rt_prio_array *array = >rt.active;
struct task_struct *next;
@@ -196,26 +205,36 @@ static struct task_struct *pick_next_hig
}
 
queue = array->queue + idx;
+   BUG_ON(list_empty(queue));
+
next = list_entry(queue->next, struct task_struct, run_list);
-   if (unlikely(next != rq->curr))
-   return next;
+   if (unlikely(pick_rt_task(rq, next, cpu)))
+   goto out;
 
if (queue->next->next != queue) {
/* same prio task */
next = list_entry(queue->next->next, struct task_struct, 
run_list);
-   return next;
+   if (pick_rt_task(rq, next, cpu))
+   goto out;
}
 
+ retry:
/* slower, but more flexible */
idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1);
-   if (unlikely(idx >= MAX_RT_PRIO)) {
-   WARN_ON(1); /* rt_nr_running was 2 and above! */
+   if (unlikely(idx >= MAX_RT_PRIO))
return NULL;
-   }
 
queue = array->queue + idx;
-   next = list_entry(queue->next, struct task_struct, run_list);
+   BUG_ON(list_empty(queue));
 
+   list_for_each_entry(next, queue, run_list) {
+   if (pick_rt_task(rq, next, cpu))
+   goto out;
+   }
+
+   goto retry;
+
+ out:
return next;
 }
 
@@ -300,13 +319,15 @@ static int push_rt_task(struct rq *this_
 
assert_spin_locked(_rq->lock);
 
-   next_task = pick_next_highest_task_rt(this_rq);
+   next_task = pick_next_highest_task_rt(this_rq, -1);
if (!next_task)
return 0;
 
  retry:
-   if (unlikely(next_task == this_rq->curr))
+   if (unlikely(next_task == this_rq->curr)) {
+   WARN_ON(1);
return 0;
+   }
 
/*
 * It's possible that the next_task slipped in of
@@ -330,7 +351,7 @@ static int push_rt_task(struct rq *this_
 * so it is possible that next_task has changed.
 * If it has, then try again.
 */
-   task = pick_next_highest_task_rt(this_rq);
+   task = pick_next_highest_task_rt(this_rq, -1);
if (unlikely(task != next_task) && task && paranoid--) {
put_task_struct(next_task);
next_task = task;
@@ -373,6 +394,158 @@ static void push_rt_tasks(struct rq *rq)
;
 }
 
+static int pull_rt_task(struct rq *this_rq)
+{
+   struct task_struct *next;
+   struct task_struct *p;
+   struct rq *src_rq;
+   cpumask_t *rto_cpumask;
+   int this_cpu = this_rq->cpu;
+   int cpu;
+   int ret = 0;
+
+   assert_spin_locked(_rq->lock);
+
+   /*
+* If cpusets are used, and we have overlapping
+* run queue cpusets, then this algorithm may not catch all.
+* This is just the 

[PATCH v3 05/17] pull RT tasks

2007-11-16 Thread Steven Rostedt
This patch adds the algorithm to pull tasks from RT overloaded runqueues.

When a pull RT is initiated, all overloaded runqueues are examined for
a RT task that is higher in prio than the highest prio task queued on the
target runqueue. If another runqueue holds a RT task that is of higher
prio than the highest prio task on the target runqueue is found it is pulled
to the target runqueue.

Signed-off-by: Steven Rostedt [EMAIL PROTECTED]

---
 kernel/sched.c|2 
 kernel/sched_rt.c |  196 ++
 2 files changed, 187 insertions(+), 11 deletions(-)

Index: linux-compile.git/kernel/sched.c
===
--- linux-compile.git.orig/kernel/sched.c   2007-11-16 22:11:37.0 
-0500
+++ linux-compile.git/kernel/sched.c2007-11-16 22:12:13.0 -0500
@@ -3646,6 +3646,8 @@ need_resched_nonpreemptible:
switch_count = prev-nvcsw;
}
 
+   schedule_balance_rt(rq, prev);
+
if (unlikely(!rq-nr_running))
idle_balance(cpu, rq);
 
Index: linux-compile.git/kernel/sched_rt.c
===
--- linux-compile.git.orig/kernel/sched_rt.c2007-11-16 22:12:07.0 
-0500
+++ linux-compile.git/kernel/sched_rt.c 2007-11-16 22:12:13.0 -0500
@@ -176,8 +176,17 @@ static void put_prev_task_rt(struct rq *
 static int double_lock_balance(struct rq *this_rq, struct rq *busiest);
 static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep);
 
+static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
+{
+   if (!task_running(rq, p) 
+   (cpu  0 || cpu_isset(cpu, p-cpus_allowed)))
+   return 1;
+   return 0;
+}
+
 /* Return the second highest RT task, NULL otherwise */
-static struct task_struct *pick_next_highest_task_rt(struct rq *rq)
+static struct task_struct *pick_next_highest_task_rt(struct rq *rq,
+int cpu)
 {
struct rt_prio_array *array = rq-rt.active;
struct task_struct *next;
@@ -196,26 +205,36 @@ static struct task_struct *pick_next_hig
}
 
queue = array-queue + idx;
+   BUG_ON(list_empty(queue));
+
next = list_entry(queue-next, struct task_struct, run_list);
-   if (unlikely(next != rq-curr))
-   return next;
+   if (unlikely(pick_rt_task(rq, next, cpu)))
+   goto out;
 
if (queue-next-next != queue) {
/* same prio task */
next = list_entry(queue-next-next, struct task_struct, 
run_list);
-   return next;
+   if (pick_rt_task(rq, next, cpu))
+   goto out;
}
 
+ retry:
/* slower, but more flexible */
idx = find_next_bit(array-bitmap, MAX_RT_PRIO, idx+1);
-   if (unlikely(idx = MAX_RT_PRIO)) {
-   WARN_ON(1); /* rt_nr_running was 2 and above! */
+   if (unlikely(idx = MAX_RT_PRIO))
return NULL;
-   }
 
queue = array-queue + idx;
-   next = list_entry(queue-next, struct task_struct, run_list);
+   BUG_ON(list_empty(queue));
 
+   list_for_each_entry(next, queue, run_list) {
+   if (pick_rt_task(rq, next, cpu))
+   goto out;
+   }
+
+   goto retry;
+
+ out:
return next;
 }
 
@@ -300,13 +319,15 @@ static int push_rt_task(struct rq *this_
 
assert_spin_locked(this_rq-lock);
 
-   next_task = pick_next_highest_task_rt(this_rq);
+   next_task = pick_next_highest_task_rt(this_rq, -1);
if (!next_task)
return 0;
 
  retry:
-   if (unlikely(next_task == this_rq-curr))
+   if (unlikely(next_task == this_rq-curr)) {
+   WARN_ON(1);
return 0;
+   }
 
/*
 * It's possible that the next_task slipped in of
@@ -330,7 +351,7 @@ static int push_rt_task(struct rq *this_
 * so it is possible that next_task has changed.
 * If it has, then try again.
 */
-   task = pick_next_highest_task_rt(this_rq);
+   task = pick_next_highest_task_rt(this_rq, -1);
if (unlikely(task != next_task)  task  paranoid--) {
put_task_struct(next_task);
next_task = task;
@@ -373,6 +394,158 @@ static void push_rt_tasks(struct rq *rq)
;
 }
 
+static int pull_rt_task(struct rq *this_rq)
+{
+   struct task_struct *next;
+   struct task_struct *p;
+   struct rq *src_rq;
+   cpumask_t *rto_cpumask;
+   int this_cpu = this_rq-cpu;
+   int cpu;
+   int ret = 0;
+
+   assert_spin_locked(this_rq-lock);
+
+   /*
+* If cpusets are used, and we have overlapping
+* run queue cpusets, then this algorithm may not catch all.
+* This is just the price you pay