Recent Linux kernels have support for percpu HPET timer. These timers appear as
hpet<num> in /proc/timer_list and /proc/interrupts. powertop should not list
these interrupts as wake events as they are delivering timer events which are
already accounted for by one of the waking timers. Skipping these percpu timer
is similar to skipping LOC (local apic timer) and timer 0 in powertop.

Example:

Before the patch wakeup data

Top causes for wakeups:
  23.6% (  9.9)     <kernel core> : hrtimer_start_range_ns (tick_sched_timer) 
  21.4% (  8.9)     <kernel core> : hrtimer_start (tick_sched_timer) 
  10.2% (  4.3)     <kernel core> : schedule_delayed_work_on 
(delayed_work_timer_fn) 
  10.1% (  4.2)       <interrupt> : hpet2 
   9.9% (  4.1)       <interrupt> : hpet5 
   4.6% (  1.9)       <interrupt> : hpet6 
   4.3% (  1.8)       <interrupt> : hpet4 
   3.8% (  1.6)       <interrupt> : ata_piix, ata_piix, uhci_hcd:usb5, 
uhci_hcd:usb6 
   3.4% (  1.4)       <interrupt> : hpet3 
   2.7% (  1.1)       <interrupt> : ehci_hcd:usb1, uhci_hcd:usb7, eth0 
   1.3% (  0.5)     <kernel core> : add_timer (neigh_periodic_timer) 
   1.1% (  0.5)     <kernel core> : e1000_intr (e1000_watchdog) 
: : :
: : :
: : :

After the patch wakeup data

Top causes for wakeups:
  33.9% (  8.9)     <kernel core> : hrtimer_start (tick_sched_timer) 
  30.4% (  8.0)     <kernel core> : hrtimer_start_range_ns (tick_sched_timer) 
  14.2% (  3.7)     <kernel core> : schedule_delayed_work_on 
(delayed_work_timer_fn) 
   7.3% (  1.9)       <interrupt> : ata_piix, ata_piix, uhci_hcd:usb5, 
uhci_hcd:usb6 
   5.3% (  1.4)       <interrupt> : ehci_hcd:usb1, uhci_hcd:usb7, eth0 
   2.0% (  0.5)     <kernel core> : e1000_intr (e1000_watchdog) 
   2.0% (  0.5)     <kernel core> : add_timer (neigh_periodic_timer) 
: : :
: : :
: : :


Patch records the percpu hpet timer info from /proc/timer_list and filters
/proc/interrupts based on that.

Signed-off-by: Venkatesh Pallipadi <[email protected]>

diff -purN powertop-1.11/powertop.c powertop-1.11-new/powertop.c
--- powertop-1.11/powertop.c    2008-12-30 10:52:54.000000000 -0800
+++ powertop-1.11-new/powertop.c        2009-05-28 00:52:32.000000000 -0700
@@ -35,6 +35,7 @@
 #include <assert.h>
 #include <locale.h>
 #include <time.h>
+#include <limits.h>
 #include <sys/stat.h>
 
 #include "powertop.h"
@@ -171,6 +172,58 @@ int update_irq(int irq, uint64_t count, 
        return count;
 }
 
+static int percpu_hpet_timer(char *name)
+{
+       static int timer_list_read;
+       static int percpu_hpet_start = INT_MAX, percpu_hpet_end = INT_MIN;
+       char *c;
+       long hpet_chan;
+
+       if (!timer_list_read) {
+               char file_name[20];
+               char ln[80];
+               FILE *fp;
+
+               timer_list_read = 1;
+               snprintf(file_name, sizeof(file_name), "/proc/timer_list");
+               fp = fopen(file_name, "r");
+               if (fp == NULL)
+                       return 0;
+
+               while (fgets(ln, sizeof(ln), fp) != NULL)
+               {
+                       c = strstr(ln, "Clock Event Device: hpet");
+                       if (!c)
+                               continue;
+
+                       c += 24;
+                       if (!isdigit(c[0]))
+                               continue;
+
+                       hpet_chan = strtol(c, NULL, 10);
+                       if (hpet_chan < percpu_hpet_start)
+                               percpu_hpet_start = hpet_chan;
+                       if (hpet_chan > percpu_hpet_end)
+                               percpu_hpet_end = hpet_chan;
+               }
+               fclose(fp);
+       }
+
+       c = strstr(name, "hpet");
+       if (!c)
+               return 0;
+
+       c += 4;
+       if (!isdigit(c[0]))
+               return 0;
+
+       hpet_chan = strtol(c, NULL, 10);
+       if (percpu_hpet_start <= hpet_chan && hpet_chan <= percpu_hpet_end)
+               return 1;
+
+       return 0;
+}
+
 static void do_proc_irq(void)
 {
        FILE *file;
@@ -253,6 +306,10 @@ static void do_proc_irq(void)
                else
                        sprintf(line2, _("    <interrupt> : %s"), _("PS/2 
keyboard/mouse/touchpad"));
 
+               /* skip per CPU timer interrupts */
+               if (percpu_hpet_timer(name))
+                       delta = 0;
+
                if (nr > 0 && delta > 0)
                        push_line(line2, delta);
                if (nr==0)

_______________________________________________
Power mailing list
[email protected]
http://www.bughost.org/mailman/listinfo/power

Reply via email to