This patch exposes information about the time remaining until the next
timer interrupt expires by utilizing the dynticks infrastructure.  It
also modifies the main idle loop to allow dynticks to handle
non-interrupt break events (e.g. DMA).  Finally, it exposes sleep ticks
information to external code.  Thomas Gleixner is responsible for much
of the code in this patch.  However, I've made some additional changes,
so I'm probably responsible if there are any bugs or oversights :)

Thanks,
Adam

 arch/i386/kernel/process.c |    3 ++-
 include/linux/tick.h       |   10 ++++++++++
 kernel/softirq.c           |    5 -----
 kernel/time/tick-sched.c   |   24 ++++++++++++++++++++++++
 4 files changed, 36 insertions(+), 6 deletions(-)


diff -urN a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c        2007-03-23 23:02:16.000000000 -0400
+++ b/arch/i386/kernel/process.c        2007-03-24 01:48:33.000000000 -0400
@@ -174,13 +174,14 @@
 
        /* endless idle loop with no priority at all */
        while (1) {
-               tick_nohz_stop_sched_tick();
                while (!need_resched()) {
                        void (*idle)(void);
 
                        if (__get_cpu_var(cpu_idle_state))
                                __get_cpu_var(cpu_idle_state) = 0;
 
+                       tick_nohz_stop_sched_tick();
+
                        rmb();
                        idle = pm_idle;
 
diff -urN a/include/linux/tick.h b/include/linux/tick.h
--- a/include/linux/tick.h      2007-03-23 23:03:03.000000000 -0400
+++ b/include/linux/tick.h      2007-03-24 01:39:03.000000000 -0400
@@ -40,6 +40,7 @@
  * @idle_sleeps:       Number of idle calls, where the sched tick was stopped
  * @idle_entrytime:    Time when the idle call was entered
  * @idle_sleeptime:    Sum of the time slept in idle with sched tick stopped
+ * @sleep_length:      Duration of the current idle sleep
  */
 struct tick_sched {
        struct hrtimer                  sched_timer;
@@ -52,6 +53,7 @@
        unsigned long                   idle_sleeps;
        ktime_t                         idle_entrytime;
        ktime_t                         idle_sleeptime;
+       ktime_t                         sleep_length;
        unsigned long                   last_jiffies;
        unsigned long                   next_jiffies;
        ktime_t                         idle_expires;
@@ -100,10 +102,18 @@
 extern void tick_nohz_stop_sched_tick(void);
 extern void tick_nohz_restart_sched_tick(void);
 extern void tick_nohz_update_jiffies(void);
+extern ktime_t tick_nohz_get_sleep_length(void);
+extern unsigned long tick_nohz_get_idle_jiffies(void);
 # else
 static inline void tick_nohz_stop_sched_tick(void) { }
 static inline void tick_nohz_restart_sched_tick(void) { }
 static inline void tick_nohz_update_jiffies(void) { }
+static inline ktime_t tick_nohz_get_sleep_length(void)
+{
+       ktime_t len = { .tv64 = NSEC_PER_SEC/HZ };
+
+       return len;
+}
 # endif /* !NO_HZ */
 
 #endif
diff -urN a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c  2007-03-23 23:03:03.000000000 -0400
+++ b/kernel/softirq.c  2007-03-24 01:54:11.000000000 -0400
@@ -303,11 +303,6 @@
        if (!in_interrupt() && local_softirq_pending())
                invoke_softirq();
 
-#ifdef CONFIG_NO_HZ
-       /* Make sure that timer wheel updates are propagated */
-       if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
-               tick_nohz_stop_sched_tick();
-#endif
        preempt_enable_no_resched();
 }
 
diff -urN a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
--- a/kernel/time/tick-sched.c  2007-03-23 23:03:03.000000000 -0400
+++ b/kernel/time/tick-sched.c  2007-03-24 01:44:55.000000000 -0400
@@ -153,6 +153,7 @@
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
        struct tick_sched *ts;
        ktime_t last_update, expires, now, delta;
+       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
        int cpu;
 
        local_irq_save(flags);
@@ -250,11 +251,34 @@
 out:
        ts->next_jiffies = next_jiffies;
        ts->last_jiffies = last_jiffies;
+       ts->sleep_length = ktime_sub(dev->next_event, now);
 end:
        local_irq_restore(flags);
 }
 
 /**
+ * tick_nohz_get_sleep_length - return the length of the current sleep
+ *
+ * Called from power state control code with interrupts disabled
+ */
+ktime_t tick_nohz_get_sleep_length(void)
+{
+       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+
+       return ts->sleep_length;
+}
+
+/**
+ * tick_nohz_get_idle_jiffies - returns the current idle jiffie count
+ */
+unsigned long tick_nohz_get_idle_jiffies(void)
+{
+       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+
+       return ts->idle_jiffies;
+}
+
+/**
  * nohz_restart_sched_tick - restart the idle tick from the idle task
  *
  * Restart the idle tick when the CPU is woken up from idle


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to