Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.26-rc1 /kernel/sched_fair.c

Filename:/kernel/sched_fair.c
Lines Added:377
Lines Deleted:203
Also changed in: (Previous) 2.6.25-git20  2.6.25-git19  2.6.25-git18  2.6.25-git17  2.6.25-git16  2.6.25-git15 
(Following) 2.6.26-rc1-git4  2.6.26-rc1-git5  2.6.26-rc1-git6  2.6.26-rc1-git7  2.6.26-rc1-git8  2.6.26-rc1-git9 

Location
[  2.6.26-rc1
  [  kernel
     o  sched_fair.c

Patch

diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 0080968..89fa32b 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -62,24 +62,14 @@ const_debug unsigned int sysctl_sched_child_runs_first = 1;
 unsigned int __read_mostly sysctl_sched_compat_yield;
 
 /*
- * SCHED_BATCH wake-up granularity.
- * (default: 10 msec * (1 + ilog(ncpus)), units: nanoseconds)
- *
- * This option delays the preemption effects of decoupled workloads
- * and reduces their over-scheduling. Synchronous workloads will still
- * have immediate wakeup/sleep latencies.
- */
-unsigned int sysctl_sched_batch_wakeup_granularity = 10000000UL;
-
-/*
  * SCHED_OTHER wake-up granularity.
- * (default: 5 msec * (1 + ilog(ncpus)), units: nanoseconds)
+ * (default: 10 msec * (1 + ilog(ncpus)), units: nanoseconds)
  *
  * This option delays the preemption effects of decoupled workloads
  * and reduces their over-scheduling. Synchronous workloads will still
  * have immediate wakeup/sleep latencies.
  */
-unsigned int sysctl_sched_wakeup_granularity = 5000000UL;
+unsigned int sysctl_sched_wakeup_granularity = 10000000UL;
 
 const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
 
@@ -87,6 +77,11 @@ const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
  * CFS operations on generic schedulable entities:
  */
 
+static inline struct task_struct *task_of(struct sched_entity *se)
+{
+   return container_of(se, struct task_struct, se);
+}
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 
 /* cpu runqueue to which this cfs_rq is attached */
@@ -98,6 +93,54 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
 /* An entity is a task if it doesn't "own" a runqueue */
 #define entity_is_task(se)   (!se->my_q)
 
+/* Walk up scheduling entities hierarchy */
+#define for_each_sched_entity(se) \
+      for (; se; se = se->parent)
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+   return p->se.cfs_rq;
+}
+
+/* runqueue on which this entity is (to be) queued */
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+   return se->cfs_rq;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+   return grp->my_q;
+}
+
+/* Given a group's cfs_rq on one cpu, return its corresponding cfs_rq on
+ * another cpu ('this_cpu')
+ */
+static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
+{
+   return cfs_rq->tg->cfs_rq[this_cpu];
+}
+
+/* Iterate thr' all leaf cfs_rq's on a runqueue */
+#define for_each_leaf_cfs_rq(rq, cfs_rq) \
+   list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
+
+/* Do the two (enqueued) entities belong to the same group ? */
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
+{
+   if (se->cfs_rq == pse->cfs_rq)
+      return 1;
+
+   return 0;
+}
+
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+   return se->parent;
+}
+
 #else   /* CONFIG_FAIR_GROUP_SCHED */
 
 static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
@@ -107,13 +150,49 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
 
 #define entity_is_task(se)   1
 
-#endif   /* CONFIG_FAIR_GROUP_SCHED */
+#define for_each_sched_entity(se) \
+      for (; se; se = NULL)
 
-static inline struct task_struct *task_of(struct sched_entity *se)
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
 {
-   return container_of(se, struct task_struct, se);
+   return &task_rq(p)->cfs;
+}
+
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+   struct task_struct *p = task_of(se);
+   struct rq *rq = task_rq(p);
+
+   return &rq->cfs;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+   return NULL;
+}
+
+static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
+{
+   return &cpu_rq(this_cpu)->cfs;
+}
+
+#define for_each_leaf_cfs_rq(rq, cfs_rq) \
+      for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
+
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
+{
+   return 1;
+}
+
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+   return NULL;
 }
 
+#endif   /* CONFIG_FAIR_GROUP_SCHED */
+
 
 /**************************************************************
  * Scheduling class tree data structure manipulation methods:
@@ -255,6 +334,34 @@ int sched_nr_latency_handler(struct ctl_table *table, int write,
 #endif
 
 /*
+ * delta *= w / rw
+ */
+static inline unsigned long
+calc_delta_weight(unsigned long delta, struct sched_entity *se)
+{
+   for_each_sched_entity(se) {
+      delta = calc_delta_mine(delta,
+            se->load.weight, &cfs_rq_of(se)->load);
+   }
+
+   return delta;
+}
+
+/*
+ * delta *= rw / w
+ */
+static inline unsigned long
+calc_delta_fair(unsigned long delta, struct sched_entity *se)
+{
+   for_each_sched_entity(se) {
+      delta = calc_delta_mine(delta,
+            cfs_rq_of(se)->load.weight, &se->load);
+   }
+
+   return delta;
+}
+
+/*
  * The idea is to set a period in which each task runs once.
  *
  * When there are too many tasks (sysctl_sched_nr_latency) we have to stretch
@@ -283,29 +390,54 @@ static u64 __sched_period(unsigned long nr_running)
  */
 static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-   return calc_delta_mine(__sched_period(cfs_rq->nr_running),
-                se->load.weight, &cfs_rq->load);
+   return calc_delta_weight(__sched_period(cfs_rq->nr_running), se);
 }
 
 /*
- * We calculate the vruntime slice.
+ * We calculate the vruntime slice of a to be inserted task
  *
- * vs = s/w = p/rw
+ * vs = s*rw/w = p
  */
-static u64 __sched_vslice(unsigned long rq_weight, unsigned long nr_running)
+static u64 sched_vslice_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-   u64 vslice = __sched_period(nr_running);
+   unsigned long nr_running = cfs_rq->nr_running;
 
-   vslice *= NICE_0_LOAD;
-   do_div(vslice, rq_weight);
+   if (!se->on_rq)
+      nr_running++;
 
-   return vslice;
+   return __sched_period(nr_running);
 }
 
-static u64 sched_vslice_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
+/*
+ * The goal of calc_delta_asym() is to be asymmetrically around NICE_0_LOAD, in
+ * that it favours >=0 over <0.
+ *
+ *   -20         |
+ *               |
+ *     0 --------+-------
+ *             .'
+ *    19     .'
+ *
+ */
+static unsigned long
+calc_delta_asym(unsigned long delta, struct sched_entity *se)
 {
-   return __sched_vslice(cfs_rq->load.weight + se->load.weight,
-         cfs_rq->nr_running + 1);
+   struct load_weight lw = {
+      .weight = NICE_0_LOAD,
+      .inv_weight = 1UL << (WMULT_SHIFT-NICE_0_SHIFT)
+   };
+
+   for_each_sched_entity(se) {
+      struct load_weight *se_lw = &se->load;
+
+      if (se->load.weight < NICE_0_LOAD)
+         se_lw = &lw;
+
+      delta = calc_delta_mine(delta,
+            cfs_rq_of(se)->load.weight, se_lw);
+   }
+
+   return delta;
 }
 
 /*
@@ -322,11 +454,7 @@ __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
 
    curr->sum_exec_runtime += delta_exec;
    schedstat_add(cfs_rq, exec_clock, delta_exec);
-   delta_exec_weighted = delta_exec;
-   if (unlikely(curr->load.weight != NICE_0_LOAD)) {
-      delta_exec_weighted = calc_delta_fair(delta_exec_weighted,
-                     &curr->load);
-   }
+   delta_exec_weighted = calc_delta_fair(delta_exec, curr);
    curr->vruntime += delta_exec_weighted;
 }
 
@@ -413,20 +541,43 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
  * Scheduling class queueing methods:
  */
 
+#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
+static void
+add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
+{
+   cfs_rq->task_weight += weight;
+}
+#else
+static inline void
+add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
+{
+}
+#endif
+
 static void
 account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
    update_load_add(&cfs_rq->load, se->load.weight);
+   if (!parent_entity(se))
+      inc_cpu_load(rq_of(cfs_rq), se->load.weight);
+   if (entity_is_task(se))
+      add_cfs_task_weight(cfs_rq, se->load.weight);
    cfs_rq->nr_running++;
    se->on_rq = 1;
+   list_add(&se->group_node, &cfs_rq->tasks);
 }
 
 static void
 account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
    update_load_sub(&cfs_rq->load, se->load.weight);
+   if (!parent_entity(se))
+      dec_cpu_load(rq_of(cfs_rq), se->load.weight);
+   if (entity_is_task(se))
+      add_cfs_task_weight(cfs_rq, -se->load.weight);
    cfs_rq->nr_running--;
    se->on_rq = 0;
+   list_del_init(&se->group_node);
 }
 
 static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
@@ -510,8 +661,12 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
 
    if (!initial) {
       /* sleeps upto a single latency don't count. */
-      if (sched_feat(NEW_FAIR_SLEEPERS))
-         vruntime -= sysctl_sched_latency;
+      if (sched_feat(NEW_FAIR_SLEEPERS)) {
+         if (sched_feat(NORMALIZED_SLEEPER))
+            vruntime -= calc_delta_weight(sysctl_sched_latency, se);
+         else
+            vruntime -= sysctl_sched_latency;
+      }
 
       /* ensure we never gain time by being placed backwards. */
       vruntime = max_vruntime(se->vruntime, vruntime);
@@ -627,20 +782,16 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
    se->prev_sum_exec_runtime = se->sum_exec_runtime;
 }
 
+static int
+wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
+
 static struct sched_entity *
 pick_next(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-   s64 diff, gran;
-
    if (!cfs_rq->next)
       return se;
 
-   diff = cfs_rq->next->vruntime - se->vruntime;
-   if (diff < 0)
-      return se;
-
-   gran = calc_delta_fair(sysctl_sched_wakeup_granularity, &cfs_rq->load);
-   if (diff > gran)
+   if (wakeup_preempt_entity(cfs_rq->next, se) != 0)
       return se;
 
    return cfs_rq->next;
@@ -708,101 +859,6 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
  * CFS operations on tasks:
  */
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-
-/* Walk up scheduling entities hierarchy */
-#define for_each_sched_entity(se) \
-      for (; se; se = se->parent)
-
-static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
-{
-   return p->se.cfs_rq;
-}
-
-/* runqueue on which this entity is (to be) queued */
-static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
-{
-   return se->cfs_rq;
-}
-
-/* runqueue "owned" by this group */
-static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
-{
-   return grp->my_q;
-}
-
-/* Given a group's cfs_rq on one cpu, return its corresponding cfs_rq on
- * another cpu ('this_cpu')
- */
-static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
-{
-   return cfs_rq->tg->cfs_rq[this_cpu];
-}
-
-/* Iterate thr' all leaf cfs_rq's on a runqueue */
-#define for_each_leaf_cfs_rq(rq, cfs_rq) \
-   list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
-
-/* Do the two (enqueued) entities belong to the same group ? */
-static inline int
-is_same_group(struct sched_entity *se, struct sched_entity *pse)
-{
-   if (se->cfs_rq == pse->cfs_rq)
-      return 1;
-
-   return 0;
-}
-
-static inline struct sched_entity *parent_entity(struct sched_entity *se)
-{
-   return se->parent;
-}
-
-#else   /* CONFIG_FAIR_GROUP_SCHED */
-
-#define for_each_sched_entity(se) \
-      for (; se; se = NULL)
-
-static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
-{
-   return &task_rq(p)->cfs;
-}
-
-static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
-{
-   struct task_struct *p = task_of(se);
-   struct rq *rq = task_rq(p);
-
-   return &rq->cfs;
-}
-
-/* runqueue "owned" by this group */
-static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
-{
-   return NULL;
-}
-
-static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
-{
-   return &cpu_rq(this_cpu)->cfs;
-}
-
-#define for_each_leaf_cfs_rq(rq, cfs_rq) \
-      for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
-
-static inline int
-is_same_group(struct sched_entity *se, struct sched_entity *pse)
-{
-   return 1;
-}
-
-static inline struct sched_entity *parent_entity(struct sched_entity *se)
-{
-   return NULL;
-}
-
-#endif   /* CONFIG_FAIR_GROUP_SCHED */
-
 #ifdef CONFIG_SCHED_HRTICK
 static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
 {
@@ -916,7 +972,7 @@ static void yield_task_fair(struct rq *rq)
    /*
     * Already in the rightmost position?
     */
-   if (unlikely(rightmost->vruntime < se->vruntime))
+   if (unlikely(!rightmost || rightmost->vruntime < se->vruntime))
       return;
 
    /*
@@ -955,7 +1011,9 @@ static int wake_idle(int cpu, struct task_struct *p)
       return cpu;
 
    for_each_domain(cpu, sd) {
-      if (sd->flags & SD_WAKE_IDLE) {
+      if ((sd->flags & SD_WAKE_IDLE)
+          || ((sd->flags & SD_WAKE_IDLE_FAR)
+         && !task_hot(p, task_rq(p)->clock, sd))) {
          cpus_and(tmp, sd->span, p->cpus_allowed);
          for_each_cpu_mask(i, tmp) {
             if (idle_cpu(i)) {
@@ -1099,6 +1157,58 @@ out:
 }
 #endif /* CONFIG_SMP */
 
+static unsigned long wakeup_gran(struct sched_entity *se)
+{
+   unsigned long gran = sysctl_sched_wakeup_granularity;
+
+   /*
+    * More easily preempt - nice tasks, while not making it harder for
+    * + nice tasks.
+    */
+   gran = calc_delta_asym(sysctl_sched_wakeup_granularity, se);
+
+   return gran;
+}
+
+/*
+ * Should 'se' preempt 'curr'.
+ *
+ *             |s1
+ *        |s2
+ *   |s3
+ *         g
+ *      |<--->|c
+ *
+ *  w(c, s1) = -1
+ *  w(c, s2) =  0
+ *  w(c, s3) =  1
+ *
+ */
+static int
+wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
+{
+   s64 gran, vdiff = curr->vruntime - se->vruntime;
+
+   if (vdiff < 0)
+      return -1;
+
+   gran = wakeup_gran(curr);
+   if (vdiff > gran)
+      return 1;
+
+   return 0;
+}
+
+/* return depth at which a sched entity is present in the hierarchy */
+static inline int depth_se(struct sched_entity *se)
+{
+   int depth = 0;
+
+   for_each_sched_entity(se)
+      depth++;
+
+   return depth;
+}
 
 /*
  * Preempt the current task with a newly woken task if needed:
@@ -1108,7 +1218,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
    struct task_struct *curr = rq->curr;
    struct cfs_rq *cfs_rq = task_cfs_rq(curr);
    struct sched_entity *se = &curr->se, *pse = &p->se;
-   unsigned long gran;
+   int se_depth, pse_depth;
 
    if (unlikely(rt_prio(p->prio))) {
       update_rq_clock(rq);
@@ -1133,20 +1243,33 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
    if (!sched_feat(WAKEUP_PREEMPT))
       return;
 
-   while (!is_same_group(se, pse)) {
+   /*
+    * preemption test can be made between sibling entities who are in the
+    * same cfs_rq i.e who have a common parent. Walk up the hierarchy of
+    * both tasks until we find their ancestors who are siblings of common
+    * parent.
+    */
+
+   /* First walk up until both entities are at same depth */
+   se_depth = depth_se(se);
+   pse_depth = depth_se(pse);
+
+   while (se_depth > pse_depth) {
+      se_depth--;
       se = parent_entity(se);
+   }
+
+   while (pse_depth > se_depth) {
+      pse_depth--;
       pse = parent_entity(pse);
    }
 
-   gran = sysctl_sched_wakeup_granularity;
-   /*
-    * More easily preempt - nice tasks, while not making
-    * it harder for + nice tasks.
-    */
-   if (unlikely(se->load.weight > NICE_0_LOAD))
-      gran = calc_delta_fair(gran, &se->load);
+   while (!is_same_group(se, pse)) {
+      se = parent_entity(se);
+      pse = parent_entity(pse);
+   }
 
-   if (pse->vruntime + gran < se->vruntime)
+   if (wakeup_preempt_entity(se, pse) == 1)
       resched_task(curr);
 }
 
@@ -1197,15 +1320,27 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
  * the current task:
  */
 static struct task_struct *
-__load_balance_iterator(struct cfs_rq *cfs_rq, struct rb_node *curr)
+__load_balance_iterator(struct cfs_rq *cfs_rq, struct list_head *next)
 {
-   struct task_struct *p;
+   struct task_struct *p = NULL;
+   struct sched_entity *se;
+
+   if (next == &cfs_rq->tasks)
+      return NULL;
+
+   /* Skip over entities that are not tasks */
+   do {
+      se = list_entry(next, struct sched_entity, group_node);
+      next = next->next;
+   } while (next != &cfs_rq->tasks && !entity_is_task(se));
 
-   if (!curr)
+   if (next == &cfs_rq->tasks)
       return NULL;
 
-   p = rb_entry(curr, struct task_struct, se.run_node);
-   cfs_rq->rb_load_balance_curr = rb_next(curr);
+   cfs_rq->balance_iterator = next;
+
+   if (entity_is_task(se))
+      p = task_of(se);
 
    return p;
 }
@@ -1214,85 +1349,100 @@ static struct task_struct *load_balance_start_fair(void *arg)
 {
    struct cfs_rq *cfs_rq = arg;
 
-   return __load_balance_iterator(cfs_rq, first_fair(cfs_rq));
+   return __load_balance_iterator(cfs_rq, cfs_rq->tasks.next);
 }
 
 static struct task_struct *load_balance_next_fair(void *arg)
 {
    struct cfs_rq *cfs_rq = arg;
 
-   return __load_balance_iterator(cfs_rq, cfs_rq->rb_load_balance_curr);
+   return __load_balance_iterator(cfs_rq, cfs_rq->balance_iterator);
 }
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
+static unsigned long
+__load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+      unsigned long max_load_move, struct sched_domain *sd,
+      enum cpu_idle_type idle, int *all_pinned, int *this_best_prio,
+      struct cfs_rq *cfs_rq)
 {
-   struct sched_entity *curr;
-   struct task_struct *p;
-
-   if (!cfs_rq->nr_running || !first_fair(cfs_rq))
-      return MAX_PRIO;
-
-   curr = cfs_rq->curr;
-   if (!curr)
-      curr = __pick_next_entity(cfs_rq);
+   struct rq_iterator cfs_rq_iterator;
 
-   p = task_of(curr);
+   cfs_rq_iterator.start = load_balance_start_fair;
+   cfs_rq_iterator.next = load_balance_next_fair;
+   cfs_rq_iterator.arg = cfs_rq;
 
-   return p->prio;
+   return balance_tasks(this_rq, this_cpu, busiest,
+         max_load_move, sd, idle, all_pinned,
+         this_best_prio, &cfs_rq_iterator);
 }
-#endif
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
 static unsigned long
 load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
         unsigned long max_load_move,
         struct sched_domain *sd, enum cpu_idle_type idle,
         int *all_pinned, int *this_best_prio)
 {
-   struct cfs_rq *busy_cfs_rq;
    long rem_load_move = max_load_move;
-   struct rq_iterator cfs_rq_iterator;
-
-   cfs_rq_iterator.start = load_balance_start_fair;
-   cfs_rq_iterator.next = load_balance_next_fair;
+   int busiest_cpu = cpu_of(busiest);
+   struct task_group *tg;
 
-   for_each_leaf_cfs_rq(busiest, busy_cfs_rq) {
-#ifdef CONFIG_FAIR_GROUP_SCHED
-      struct cfs_rq *this_cfs_rq;
+   rcu_read_lock();
+   list_for_each_entry(tg, &task_groups, list) {
       long imbalance;
-      unsigned long maxload;
+      unsigned long this_weight, busiest_weight;
+      long rem_load, max_load, moved_load;
+
+      /*
+       * empty group
+       */
+      if (!aggregate(tg, sd)->task_weight)
+         continue;
+
+      rem_load = rem_load_move * aggregate(tg, sd)->rq_weight;
+      rem_load /= aggregate(tg, sd)->load + 1;
+
+      this_weight = tg->cfs_rq[this_cpu]->task_weight;
+      busiest_weight = tg->cfs_rq[busiest_cpu]->task_weight;
+
+      imbalance = (busiest_weight - this_weight) / 2;
 
-      this_cfs_rq = cpu_cfs_rq(busy_cfs_rq, this_cpu);
+      if (imbalance < 0)
+         imbalance = busiest_weight;
 
-      imbalance = busy_cfs_rq->load.weight - this_cfs_rq->load.weight;
-      /* Don't pull if this_cfs_rq has more load than busy_cfs_rq */
-      if (imbalance <= 0)
+      max_load = max(rem_load, imbalance);
+      moved_load = __load_balance_fair(this_rq, this_cpu, busiest,
+            max_load, sd, idle, all_pinned, this_best_prio,
+            tg->cfs_rq[busiest_cpu]);
+
+      if (!moved_load)
          continue;
 
-      /* Don't pull more than imbalance/2 */
-      imbalance /= 2;
-      maxload = min(rem_load_move, imbalance);
+      move_group_shares(tg, sd, busiest_cpu, this_cpu);
 
-      *this_best_prio = cfs_rq_best_prio(this_cfs_rq);
-#else
-# define maxload rem_load_move
-#endif
-      /*
-       * pass busy_cfs_rq argument into
-       * load_balance_[start|next]_fair iterators
-       */
-      cfs_rq_iterator.arg = busy_cfs_rq;
-      rem_load_move -= balance_tasks(this_rq, this_cpu, busiest,
-                      maxload, sd, idle, all_pinned,
-                      this_best_prio,
-                      &cfs_rq_iterator);
+      moved_load *= aggregate(tg, sd)->load;
+      moved_load /= aggregate(tg, sd)->rq_weight + 1;
 
-      if (rem_load_move <= 0)
+      rem_load_move -= moved_load;
+      if (rem_load_move < 0)
          break;
    }
+   rcu_read_unlock();
 
    return max_load_move - rem_load_move;
 }
+#else
+static unsigned long
+load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+        unsigned long max_load_move,
+        struct sched_domain *sd, enum cpu_idle_type idle,
+        int *all_pinned, int *this_best_prio)
+{
+   return __load_balance_fair(this_rq, this_cpu, busiest,
+         max_load_move, sd, idle, all_pinned,
+         this_best_prio, &busiest->cfs);
+}
+#endif
 
 static int
 move_one_task_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
@@ -1461,16 +1611,40 @@ static const struct sched_class fair_sched_class = {
 };
 
 #ifdef CONFIG_SCHED_DEBUG
+static void
+print_cfs_rq_tasks(struct seq_file *m, struct cfs_rq *cfs_rq, int depth)
+{
+   struct sched_entity *se;
+
+   if (!cfs_rq)
+      return;
+
+   list_for_each_entry_rcu(se, &cfs_rq->tasks, group_node) {
+      int i;
+
+      for (i = depth; i; i--)
+         seq_puts(m, "  ");
+
+      seq_printf(m, "%lu %s %lu\n",
+            se->load.weight,
+            entity_is_task(se) ? "T" : "G",
+            calc_delta_weight(SCHED_LOAD_SCALE, se)
+            );
+      if (!entity_is_task(se))
+         print_cfs_rq_tasks(m, group_cfs_rq(se), depth + 1);
+   }
+}
+
 static void print_cfs_stats(struct seq_file *m, int cpu)
 {
    struct cfs_rq *cfs_rq;
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-   print_cfs_rq(m, cpu, &cpu_rq(cpu)->cfs);
-#endif
    rcu_read_lock();
    for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
       print_cfs_rq(m, cpu, cfs_rq);
+
+   seq_printf(m, "\nWeight tree:\n");
+   print_cfs_rq_tasks(m, &cpu_rq(cpu)->cfs, 1);
    rcu_read_unlock();
 }
 #endif


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.