]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - kernel/sched.c
[PATCH] sched: use softirq for load balancing
[mirror_ubuntu-zesty-kernel.git] / kernel / sched.c
index 14a8d9050cd431c6420769e712d71468445c653b..0a3e748d737d96362887e559cb31abdf1bb70243 100644 (file)
@@ -227,6 +227,7 @@ struct rq {
        unsigned long expired_timestamp;
        unsigned long long timestamp_last_tick;
        struct task_struct *curr, *idle;
+       unsigned long next_balance;
        struct mm_struct *prev_mm;
        struct prio_array *active, *expired, arrays[2];
        int best_expired_prio;
@@ -2858,7 +2859,7 @@ static void update_load(struct rq *this_rq)
 }
 
 /*
- * rebalance_tick will get called every timer tick, on every CPU.
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
  *
  * It checks each scheduling domain to see if it is due to be balanced,
  * and initiates a balancing operation if so.
@@ -2866,9 +2867,10 @@ static void update_load(struct rq *this_rq)
  * Balancing parameters are set up in arch_init_sched_domains.
  */
 
-static void
-rebalance_tick(int this_cpu, struct rq *this_rq)
+static void run_rebalance_domains(struct softirq_action *h)
 {
+       int this_cpu = smp_processor_id();
+       struct rq *this_rq = cpu_rq(this_cpu);
        unsigned long interval;
        struct sched_domain *sd;
        /*
@@ -2877,6 +2879,8 @@ rebalance_tick(int this_cpu, struct rq *this_rq)
         */
        enum idle_type idle = !this_rq->nr_running ?
                                SCHED_IDLE : NOT_IDLE;
+       /* Earliest time when we have to call run_rebalance_domains again */
+       unsigned long next_balance = jiffies + 60*HZ;
 
        for_each_domain(this_cpu, sd) {
                if (!(sd->flags & SD_LOAD_BALANCE))
@@ -2891,7 +2895,7 @@ rebalance_tick(int this_cpu, struct rq *this_rq)
                if (unlikely(!interval))
                        interval = 1;
 
-               if (jiffies - sd->last_balance >= interval) {
+               if (time_after_eq(jiffies, sd->last_balance + interval)) {
                        if (load_balance(this_cpu, this_rq, sd, idle)) {
                                /*
                                 * We've pulled tasks over so either we're no
@@ -2902,7 +2906,10 @@ rebalance_tick(int this_cpu, struct rq *this_rq)
                        }
                        sd->last_balance += interval;
                }
+               if (time_after(next_balance, sd->last_balance + interval))
+                       next_balance = sd->last_balance + interval;
        }
+       this_rq->next_balance = next_balance;
 }
 #else
 /*
@@ -3155,7 +3162,8 @@ void scheduler_tick(void)
                task_running_tick(rq, p);
 #ifdef CONFIG_SMP
        update_load(rq);
-       rebalance_tick(cpu, rq);
+       if (time_after_eq(jiffies, rq->next_balance))
+               raise_softirq(SCHED_SOFTIRQ);
 #endif
 }
 
@@ -6859,6 +6867,10 @@ void __init sched_init(void)
 
        set_load_weight(&init_task);
 
+#ifdef CONFIG_SMP
+       open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL);
+#endif
+
 #ifdef CONFIG_RT_MUTEXES
        plist_head_init(&init_task.pi_waiters, &init_task.pi_lock);
 #endif