Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / kernel / sched_fair.c
index 43dc6d1d9e88588bb0fa1ad43f8494e77f6eeab5..10d218ab69f2ba4eac39a2d07461c0b2b256de34 100644 (file)
@@ -711,7 +711,7 @@ 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)) {
+               if (sched_feat(FAIR_SLEEPERS)) {
                        unsigned long thresh = sysctl_sched_latency;
 
                        /*
@@ -725,6 +725,13 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
                                         task_of(se)->policy != SCHED_IDLE))
                                thresh = calc_delta_fair(thresh, se);
 
+                       /*
+                        * Halve their sleep time's effect, to allow
+                        * for a gentler effect of sleepers:
+                        */
+                       if (sched_feat(GENTLE_FAIR_SLEEPERS))
+                               thresh >>= 1;
+
                        vruntime -= thresh;
                }
        }
@@ -757,10 +764,10 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup)
 
 static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       if (cfs_rq->last == se)
+       if (!se || cfs_rq->last == se)
                cfs_rq->last = NULL;
 
-       if (cfs_rq->next == se)
+       if (!se || cfs_rq->next == se)
                cfs_rq->next = NULL;
 }
 
@@ -1165,9 +1172,17 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
        load      = source_load(prev_cpu, idx);
        this_load = target_load(this_cpu, idx);
 
-       if (sync && (curr->se.avg_overlap > sysctl_sched_migration_cost ||
-                       p->se.avg_overlap > sysctl_sched_migration_cost))
-               sync = 0;
+       if (sync) {
+              if (sched_feat(SYNC_LESS) &&
+                  (curr->se.avg_overlap > sysctl_sched_migration_cost ||
+                   p->se.avg_overlap > sysctl_sched_migration_cost))
+                      sync = 0;
+       } else {
+               if (sched_feat(SYNC_MORE) &&
+                   (curr->se.avg_overlap < sysctl_sched_migration_cost &&
+                    p->se.avg_overlap < sysctl_sched_migration_cost))
+                       sync = 1;
+       }
 
        /*
         * If sync wakeup then subtract the (maximum possible)
@@ -1232,11 +1247,11 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
  * domain.
  */
 static struct sched_group *
-find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
+find_idlest_group(struct sched_domain *sd, struct task_struct *p,
+                 int this_cpu, int load_idx)
 {
        struct sched_group *idlest = NULL, *this = NULL, *group = sd->groups;
        unsigned long min_load = ULONG_MAX, this_load = 0;
-       int load_idx = sd->forkexec_idx;
        int imbalance = 100 + (sd->imbalance_pct-100)/2;
 
        do {
@@ -1316,16 +1331,17 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
  *
  * preempt must be disabled.
  */
-static int select_task_rq_fair(struct task_struct *p, int flag, int sync)
+static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
 {
-       struct task_struct *t = current;
-       struct sched_domain *tmp, *sd = NULL;
+       struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL;
        int cpu = smp_processor_id();
        int prev_cpu = task_cpu(p);
        int new_cpu = cpu;
        int want_affine = 0;
+       int want_sd = 1;
+       int sync = wake_flags & WF_SYNC;
 
-       if (flag & SD_BALANCE_WAKE) {
+       if (sd_flag & SD_BALANCE_WAKE) {
                if (sched_feat(AFFINE_WAKEUPS))
                        want_affine = 1;
                new_cpu = prev_cpu;
@@ -1337,7 +1353,7 @@ static int select_task_rq_fair(struct task_struct *p, int flag, int sync)
                 * If power savings logic is enabled for a domain, see if we
                 * are not overloaded, if so, don't balance wider.
                 */
-               if (tmp->flags & SD_POWERSAVINGS_BALANCE) {
+               if (tmp->flags & (SD_POWERSAVINGS_BALANCE|SD_PREFER_LOCAL)) {
                        unsigned long power = 0;
                        unsigned long nr_running = 0;
                        unsigned long capacity;
@@ -1350,56 +1366,69 @@ static int select_task_rq_fair(struct task_struct *p, int flag, int sync)
 
                        capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE);
 
-                       if (nr_running/2 < capacity)
-                               break;
-               }
+                       if (tmp->flags & SD_POWERSAVINGS_BALANCE)
+                               nr_running /= 2;
 
-               switch (flag) {
-               case SD_BALANCE_WAKE:
-                       if (!sched_feat(LB_WAKEUP_UPDATE))
-                               break;
-               case SD_BALANCE_FORK:
-               case SD_BALANCE_EXEC:
-                       if (root_task_group_empty())
-                               break;
-                       update_shares(tmp);
-               default:
-                       break;
+                       if (nr_running < capacity)
+                               want_sd = 0;
                }
 
                if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
                    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
 
-                       if (wake_affine(tmp, p, sync)) {
-                               new_cpu = cpu;
-                               goto out;
-                       }
-
+                       affine_sd = tmp;
                        want_affine = 0;
                }
 
-               if (!(tmp->flags & flag))
+               if (!want_sd && !want_affine)
+                       break;
+
+               if (!(tmp->flags & sd_flag))
                        continue;
 
-               sd = tmp;
+               if (want_sd)
+                       sd = tmp;
+       }
+
+       if (sched_feat(LB_SHARES_UPDATE)) {
+               /*
+                * Pick the largest domain to update shares over
+                */
+               tmp = sd;
+               if (affine_sd && (!tmp ||
+                                 cpumask_weight(sched_domain_span(affine_sd)) >
+                                 cpumask_weight(sched_domain_span(sd))))
+                       tmp = affine_sd;
+
+               if (tmp)
+                       update_shares(tmp);
+       }
+
+       if (affine_sd && wake_affine(affine_sd, p, sync)) {
+               new_cpu = cpu;
+               goto out;
        }
 
        while (sd) {
+               int load_idx = sd->forkexec_idx;
                struct sched_group *group;
                int weight;
 
-               if (!(sd->flags & flag)) {
+               if (!(sd->flags & sd_flag)) {
                        sd = sd->child;
                        continue;
                }
 
-               group = find_idlest_group(sd, t, cpu);
+               if (sd_flag & SD_BALANCE_WAKE)
+                       load_idx = sd->wake_idx;
+
+               group = find_idlest_group(sd, p, cpu, load_idx);
                if (!group) {
                        sd = sd->child;
                        continue;
                }
 
-               new_cpu = find_idlest_cpu(group, t, cpu);
+               new_cpu = find_idlest_cpu(group, p, cpu);
                if (new_cpu == -1 || new_cpu == cpu) {
                        /* Now try balancing at a lower domain level of cpu */
                        sd = sd->child;
@@ -1413,7 +1442,7 @@ static int select_task_rq_fair(struct task_struct *p, int flag, int sync)
                for_each_domain(cpu, tmp) {
                        if (weight <= cpumask_weight(sched_domain_span(tmp)))
                                break;
-                       if (tmp->flags & flag)
+                       if (tmp->flags & sd_flag)
                                sd = tmp;
                }
                /* while loop will break here if sd == NULL */
@@ -1534,11 +1563,12 @@ static void set_next_buddy(struct sched_entity *se)
 /*
  * Preempt the current task with a newly woken task if needed:
  */
-static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
+static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
 {
        struct task_struct *curr = rq->curr;
        struct sched_entity *se = &curr->se, *pse = &p->se;
        struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+       int sync = wake_flags & WF_SYNC;
 
        update_curr(cfs_rq);
 
@@ -1564,7 +1594,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
         */
        if (sched_feat(LAST_BUDDY) && likely(se->on_rq && curr != rq->idle))
                set_last_buddy(se);
-       if (sched_feat(NEXT_BUDDY))
+       if (sched_feat(NEXT_BUDDY) && !(wake_flags & WF_FORK))
                set_next_buddy(pse);
 
        /*
@@ -1587,9 +1617,6 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
                return;
        }
 
-       if (!sched_feat(WAKEUP_PREEMPT))
-               return;
-
        if ((sched_feat(WAKEUP_SYNC) && sync) ||
            (sched_feat(WAKEUP_OVERLAP) &&
             (se->avg_overlap < sysctl_sched_migration_cost &&
@@ -1598,6 +1625,17 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
                return;
        }
 
+       if (sched_feat(WAKEUP_RUNNING)) {
+               if (pse->avg_running < se->avg_running) {
+                       set_next_buddy(pse);
+                       resched_task(curr);
+                       return;
+               }
+       }
+
+       if (!sched_feat(WAKEUP_PREEMPT))
+               return;
+
        find_matching_se(&se, &pse);
 
        BUG_ON(!pse);
@@ -1620,8 +1658,13 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)
                /*
                 * If se was a buddy, clear it so that it will have to earn
                 * the favour again.
+                *
+                * If se was not a buddy, clear the buddies because neither
+                * was elegible to run, let them earn it again.
+                *
+                * IOW. unconditionally clear buddies.
                 */
-               __clear_buddies(cfs_rq, se);
+               __clear_buddies(cfs_rq, NULL);
                set_next_entity(cfs_rq, se);
                cfs_rq = group_cfs_rq(se);
        } while (cfs_rq);