powernap parses /proc/interrupts incorrectly

Bug #1497782 reported by Ben on 2015-09-20
42
This bug affects 8 people
Affects Status Importance Assigned to Milestone
powernap
Undecided
Dustin Kirkland 

Bug Description

Running powernap 2.21-0ubuntu-1 on Ubuntu-15.10. Kernel 4.2.0-10

Powernap tries to parse /proc/interrupts to discover IRQs for the keyboard and mouse. However, the format of this file seems to have changed in recent kernels, and this causes the following error and backtrace in /var/log/powernap.err

Traceback (most recent call last):
  File "/usr/sbin/powernapd", line 342, in <module>
    MONITORS = powernap.get_monitors()
  File "/usr/lib/python2.7/dist-packages/powernap/powernap.py", line 183, in get_monitors
    p = ConsoleMonitor.ConsoleMonitor(config)
  File "/usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py", line 53, in __init__
    self._time, self._irqs = get_console_activity()
  File "/usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py", line 28, in get_console_activity
    irqs = get_interrupts()
  File "/usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py", line 42, in get_interrupts
    interrupts += int(i)
ValueError: invalid literal for int() with base 10: 'IR-IO-APIC'

On another machine, running linux 3.13, lines in /proc/interrupts looks like this:

           CPU0 CPU1
  0: 251660783 0 IO-APIC-edge timer
  8: 1 0 IO-APIC-edge rtc0
  9: 3 0 IO-APIC-fasteoi acpi

On 4.2 (and maybe earlier?), there is another column on the right hand side, e.g.

           CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
  0: 16 0 0 0 0 0 0 0 IR-IO-APIC 2-edge timer
  1: 2 0 0 0 0 0 0 0 IR-IO-APIC 1-edge i8042

get_interrupts() in /usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py searches this file for i8042/keyboard/mouse. When it finds a valid line, it drops the first and two last columns. The remaining columns are assumed to be IRQ numbers and parsed as integers. Since there is an extra column, 'IR-IO-APIC' gets read and it crashes when trying to parse this as an int.

A simple fix would be:

--- /tmp/ConsoleMonitor.py 2015-09-20 21:39:51.862439624 +0100
+++ /usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py 2015-09-20 21:40:08.922204486 +0100
@@ -38,6 +38,7 @@
         if source == "i8042" or source == "keyboard" or source == "mouse":
             items.pop(0)
             items.pop()
+ items.pop()
             for i in items:
                 interrupts += int(i)
     f.close()

Of course, this isn't a great fix since it won't work properly on older kernels. Perhaps something like this instead:

--- /tmp/ConsoleMonitor.py 2015-09-20 21:39:51.862439624 +0100
+++ /usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py 2015-09-20 21:50:38.785528258 +0100
@@ -39,7 +39,10 @@
             items.pop(0)
             items.pop()
             for i in items:
- interrupts += int(i)
+ try:
+ interrupts += int(i)
+ except:
+ pass
     f.close()
     return interrupts

Both seem to work on my system. However, I hardly know any python, so there's probably a much nicer way to fix this.

Edward (ecadman) wrote :

I'd guess this bug is affecting a lot more people than are represented here. Powernap is effectively broken in 15.10, it seems.

Zak Kipling (zak-k) wrote :

This affects me also, on upgrading a Trusty install to use the Xenial HWE stack (using both the powernap from Trusty, and the one from Xenial backported).

Traceback (most recent call last):
  File "/usr/sbin/powernapd", line 342, in <module>
    MONITORS = powernap.get_monitors()
  File "/usr/lib/python2.7/dist-packages/powernap/powernap.py", line 183, in get_monitors
    p = ConsoleMonitor.ConsoleMonitor(config)
  File "/usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py", line 53, in __init__
    self._time, self._irqs = get_console_activity()
  File "/usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py", line 28, in get_console_activity
    irqs = get_interrupts()
  File "/usr/lib/python2.7/dist-packages/powernap/monitors/ConsoleMonitor.py", line 42, in get_interrupts
    interrupts += int(i)
ValueError: invalid literal for int() with base 10: 'IO-APIC'

My /proc/interrupts looks like this:

           CPU0 CPU1
  0: 45 0 IO-APIC 2-edge timer
  1: 9 0 IO-APIC 1-edge i8042
  8: 0 0 IO-APIC 8-edge rtc0
  9: 0 0 IO-APIC 20-fasteoi acpi
 14: 114592 0 IO-APIC 14-edge ata_piix
 15: 114591 0 IO-APIC 15-edge ata_piix
 16: 0 0 IO-APIC 16-fasteoi uhci_hcd:usb2
 17: 48960 36725 IO-APIC 17-fasteoi firewire_ohci, eth0
 18: 12777984 12975175 IO-APIC 18-fasteoi uhci_hcd:usb4, 0000:02:02.0
 19: 0 0 IO-APIC 19-fasteoi uhci_hcd:usb3
 23: 0 0 IO-APIC 23-fasteoi ehci_hcd:usb1
...
(other lines not containing "IO-APIC")

Zak Kipling (zak-k) wrote :

I should add, however, that I can get the rest of powernap to run if I disable the console monitor:

  [ConsoleMonitor]
    ptmx = n

Fortunately, in my case this isn't a deal-breaker since it's running on a mostly-headless machine, but this may not be a viable solution for others.

Kestutis (kestutiz) wrote :

Powernap stopped working, identical error as above (Zak) after upgrade ubuntu 14.04 kernel to Linux 4.4.0-96-generic on x86_64.
I applied first Ben's fix and now working again.

fritzr (robertf-hp) on 2018-02-03
Changed in powernap:
status: New → Confirmed
assignee: nobody → Dustin Kirkland  (kirkland)
fritzr (robertf-hp) wrote :

I found this thread helpful. Dustin, as package owner, could you add this fix in the official package (or deprecate the package if no longer maintained)?

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers