[RFC][PATCH 2/3] export time until next timer interrupt using NOHZ

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux