summaryrefslogtreecommitdiffstats
path: root/glances/plugins/irq/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'glances/plugins/irq/__init__.py')
-rw-r--r--glances/plugins/irq/__init__.py198
1 files changed, 198 insertions, 0 deletions
diff --git a/glances/plugins/irq/__init__.py b/glances/plugins/irq/__init__.py
index e69de29b..81b30093 100644
--- a/glances/plugins/irq/__init__.py
+++ b/glances/plugins/irq/__init__.py
@@ -0,0 +1,198 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Glances.
+#
+# Copyright (C) 2018 Angelo Poerio <angelo.poerio@gmail.com>
+#
+# SPDX-License-Identifier: LGPL-3.0-only
+#
+
+"""IRQ plugin."""
+
+import os
+import operator
+
+from glances.globals import LINUX
+from glances.timer import getTimeSinceLastUpdate
+from glances.plugins.plugin.model import GlancesPluginModel
+
+
+class PluginModel(GlancesPluginModel):
+ """Glances IRQ plugin.
+
+ stats is a list
+ """
+
+ def __init__(self, args=None, config=None):
+ """Init the plugin."""
+ super(PluginModel, self).__init__(args=args, config=config, stats_init_value=[])
+
+ # We want to display the stat in the curse interface
+ self.display_curse = True
+
+ # Init the stats
+ self.irq = GlancesIRQ()
+
+ def get_key(self):
+ """Return the key of the list."""
+ return self.irq.get_key()
+
+ @GlancesPluginModel._check_decorator
+ @GlancesPluginModel._log_result_decorator
+ def update(self):
+ """Update the IRQ stats."""
+ # Init new stats
+ stats = self.get_init_value()
+
+ # IRQ plugin only available on GNU/Linux
+ if not LINUX:
+ return self.stats
+
+ if self.input_method == 'local':
+ # Grab the stats
+ stats = self.irq.get()
+
+ elif self.input_method == 'snmp':
+ # not available
+ pass
+
+ # Get the TOP 5 (by rate/s)
+ stats = sorted(stats, key=operator.itemgetter('irq_rate'), reverse=True)[:5]
+
+ # Update the stats
+ self.stats = stats
+
+ return self.stats
+
+ def update_views(self):
+ """Update stats views."""
+ # Call the father's method
+ super(PluginModel, self).update_views()
+
+ def msg_curse(self, args=None, max_width=None):
+ """Return the dict to display in the curse interface."""
+ # Init the return message
+ ret = []
+
+ # Only available on GNU/Linux
+ # Only process if stats exist and display plugin enable...
+ if not LINUX or not self.stats or self.is_disabled():
+ return ret
+
+ # Max size for the interface name
+ name_max_width = max_width - 7
+
+ # Build the string message
+ # Header
+ msg = '{:{width}}'.format('IRQ', width=name_max_width)
+ ret.append(self.curse_add_line(msg, "TITLE"))
+ msg = '{:>9}'.format('Rate/s')
+ ret.append(self.curse_add_line(msg))
+
+ for i in self.stats:
+ ret.append(self.curse_new_line())
+ msg = '{:{width}}'.format(i['irq_line'][:name_max_width], width=name_max_width)
+ ret.append(self.curse_add_line(msg))
+ msg = '{:>9}'.format(str(i['irq_rate']))
+ ret.append(self.curse_add_line(msg))
+
+ return ret
+
+
+class GlancesIRQ(object):
+ """This class manages the IRQ file."""
+
+ IRQ_FILE = '/proc/interrupts'
+
+ def __init__(self):
+ """Init the class.
+
+ The stat are stored in a internal list of dict
+ """
+ self.lasts = {}
+ self.reset()
+
+ def reset(self):
+ """Reset the stats."""
+ self.stats = []
+ self.cpu_number = 0
+
+ def get(self):
+ """Return the current IRQ stats."""
+ return self.__update()
+
+ def get_key(self):
+ """Return the key of the dict."""
+ return 'irq_line'
+
+ def __header(self, line):
+ """Build the header (contain the number of CPU).
+
+ CPU0 CPU1 CPU2 CPU3
+ 0: 21 0 0 0 IO-APIC 2-edge timer
+ """
+ self.cpu_number = len(line.split())
+ return self.cpu_number
+
+ def __humanname(self, line):
+ """Return the IRQ name, alias or number (choose the best for human).
+
+ IRQ line samples:
+ 1: 44487 341 44 72 IO-APIC 1-edge i8042
+ LOC: 33549868 22394684 32474570 21855077 Local timer interrupts
+ """
+ splitted_line = line.split()
+ irq_line = splitted_line[0].replace(':', '')
+ if irq_line.isdigit():
+ # If the first column is a digit, use the alias (last column)
+ irq_line += '_{}'.format(splitted_line[-1])
+ return irq_line
+
+ def __sum(self, line):
+ """Return the IRQ sum number.
+
+ IRQ line samples:
+ 1: 44487 341 44 72 IO-APIC 1-edge i8042
+ LOC: 33549868 22394684 32474570 21855077 Local timer interrupts
+ FIQ: usb_fiq
+ """
+ splitted_line = line.split()
+ try:
+ ret = sum(map(int, splitted_line[1 : (self.cpu_number + 1)]))
+ except ValueError:
+ # Correct issue #1007 on some conf (Raspberry Pi with Raspbian)
+ ret = 0
+ return ret
+
+ def __update(self):
+ """Load the IRQ file and update the internal dict."""
+ self.reset()
+
+ if not os.path.exists(self.IRQ_FILE):
+ # Correct issue #947: IRQ file do not exist on OpenVZ container
+ return self.stats
+
+ try:
+ with open(self.IRQ_FILE) as irq_proc:
+ time_since_update = getTimeSinceLastUpdate('irq')
+ # Read the header
+ self.__header(irq_proc.readline())
+ # Read the rest of the lines (one line per IRQ)
+ for line in irq_proc.readlines():
+ irq_line = self.__humanname(line)
+ current_irqs = self.__sum(line)
+ irq_rate = int(
+ current_irqs - self.lasts.get(irq_line) if self.lasts.get(irq_line) else 0 // time_since_update
+ )
+ irq_current = {
+ 'irq_line': irq_line,
+ 'irq_rate': irq_rate,
+ 'key': self.get_key(),
+ 'time_since_update': time_since_update,
+ }
+ self.stats.append(irq_current)
+ self.lasts[irq_line] = current_irqs
+ except (OSError, IOError):
+ pass
+
+ return self.stats