]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/time/tick-sched.c
highres: improve debug output
[linux-2.6-omap-h63xx.git] / kernel / time / tick-sched.c
index 95e41f7f850b46762fa882c81cb4e4f2652c686c..b416995b975727ca8b6dbf8b331de5351a1ef7f5 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/sched.h>
 #include <linux/tick.h>
 
+#include <asm/irq_regs.h>
+
 #include "tick-internal.h"
 
 /*
@@ -165,7 +167,15 @@ void tick_nohz_stop_sched_tick(void)
                goto end;
 
        cpu = smp_processor_id();
-       BUG_ON(local_softirq_pending());
+       if (unlikely(local_softirq_pending())) {
+               static int ratelimit;
+
+               if (ratelimit < 10) {
+                       printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
+                              local_softirq_pending());
+                       ratelimit++;
+               }
+       }
 
        now = ktime_get();
        /*
@@ -191,19 +201,19 @@ void tick_nohz_stop_sched_tick(void)
        next_jiffies = get_next_timer_interrupt(last_jiffies);
        delta_jiffies = next_jiffies - last_jiffies;
 
+       if (rcu_needs_cpu(cpu))
+               delta_jiffies = 1;
        /*
         * Do not stop the tick, if we are only one off
         * or if the cpu is required for rcu
         */
-       if (!ts->tick_stopped && (delta_jiffies == 1 || rcu_needs_cpu(cpu)))
+       if (!ts->tick_stopped && delta_jiffies == 1)
                goto out;
 
        /* Schedule the tick, if we are at least one jiffie off */
        if ((long)delta_jiffies >= 1) {
 
-               if (rcu_needs_cpu(cpu))
-                       delta_jiffies = 1;
-               else
+               if (delta_jiffies > 1)
                        cpu_set(cpu, nohz_cpu_mask);
                /*
                 * nohz_stop_sched_tick can be called several times before
@@ -213,10 +223,45 @@ void tick_nohz_stop_sched_tick(void)
                 * the scheduler tick in nohz_restart_sched_tick.
                 */
                if (!ts->tick_stopped) {
+                       if (select_nohz_load_balancer(1)) {
+                               /*
+                                * sched tick not stopped!
+                                */
+                               cpu_clear(cpu, nohz_cpu_mask);
+                               goto out;
+                       }
+
                        ts->idle_tick = ts->sched_timer.expires;
                        ts->tick_stopped = 1;
                        ts->idle_jiffies = last_jiffies;
                }
+
+               /*
+                * If this cpu is the one which updates jiffies, then
+                * give up the assignment and let it be taken by the
+                * cpu which runs the tick timer next, which might be
+                * this cpu as well. If we don't drop this here the
+                * jiffies might be stale and do_timer() never
+                * invoked.
+                */
+               if (cpu == tick_do_timer_cpu)
+                       tick_do_timer_cpu = -1;
+
+               ts->idle_sleeps++;
+
+               /*
+                * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
+                * there is no timer pending or at least extremly far
+                * into the future (12 days for HZ=1000). In this case
+                * we simply stop the tick timer:
+                */
+               if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
+                       ts->idle_expires.tv64 = KTIME_MAX;
+                       if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
+                               hrtimer_cancel(&ts->sched_timer);
+                       goto out;
+               }
+
                /*
                 * calculate the expiry time for the next timer wheel
                 * timer
@@ -224,7 +269,6 @@ void tick_nohz_stop_sched_tick(void)
                expires = ktime_add_ns(last_update, tick_period.tv64 *
                                       delta_jiffies);
                ts->idle_expires = expires;
-               ts->idle_sleeps++;
 
                if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
                        hrtimer_start(&ts->sched_timer, expires,
@@ -269,6 +313,7 @@ void tick_nohz_restart_sched_tick(void)
        now = ktime_get();
 
        local_irq_disable();
+       select_nohz_load_balancer(0);
        tick_do_update_jiffies64(now);
        cpu_clear(cpu, nohz_cpu_mask);
 
@@ -334,12 +379,24 @@ static void tick_nohz_handler(struct clock_event_device *dev)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
        struct pt_regs *regs = get_irq_regs();
+       int cpu = smp_processor_id();
        ktime_t now = ktime_get();
 
        dev->next_event.tv64 = KTIME_MAX;
 
+       /*
+        * Check if the do_timer duty was dropped. We don't care about
+        * concurrency: This happens only when the cpu in charge went
+        * into a long sleep. If two cpus happen to assign themself to
+        * this duty, then the jiffies update is still serialized by
+        * xtime_lock.
+        */
+       if (unlikely(tick_do_timer_cpu == -1))
+               tick_do_timer_cpu = cpu;
+
        /* Check, if the jiffies need an update */
-       tick_do_update_jiffies64(now);
+       if (tick_do_timer_cpu == cpu)
+               tick_do_update_jiffies64(now);
 
        /*
         * When we are idle and the tick is stopped, we have to touch
@@ -427,9 +484,23 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
        struct hrtimer_cpu_base *base = timer->base->cpu_base;
        struct pt_regs *regs = get_irq_regs();
        ktime_t now = ktime_get();
+       int cpu = smp_processor_id();
+
+#ifdef CONFIG_NO_HZ
+       /*
+        * Check if the do_timer duty was dropped. We don't care about
+        * concurrency: This happens only when the cpu in charge went
+        * into a long sleep. If two cpus happen to assign themself to
+        * this duty, then the jiffies update is still serialized by
+        * xtime_lock.
+        */
+       if (unlikely(tick_do_timer_cpu == -1))
+               tick_do_timer_cpu = cpu;
+#endif
 
        /* Check, if the jiffies need an update */
-       tick_do_update_jiffies64(now);
+       if (tick_do_timer_cpu == cpu)
+               tick_do_update_jiffies64(now);
 
        /*
         * Do not call, when we are not in irq context and have
@@ -475,6 +546,7 @@ void tick_setup_sched_timer(void)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
        ktime_t now = ktime_get();
+       u64 offset;
 
        /*
         * Emulate tick processing via per-CPU hrtimers:
@@ -483,8 +555,12 @@ void tick_setup_sched_timer(void)
        ts->sched_timer.function = tick_sched_timer;
        ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
 
-       /* Get the next period */
+       /* Get the next period (per cpu) */
        ts->sched_timer.expires = tick_init_jiffy_update();
+       offset = ktime_to_ns(tick_period) >> 1;
+       do_div(offset, NR_CPUS);
+       offset *= smp_processor_id();
+       ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);
 
        for (;;) {
                hrtimer_forward(&ts->sched_timer, now, tick_period);