interrupt monitor

This commit is contained in:
Richard
2026-07-09 19:42:56 +00:00
parent 047de27b32
commit a37a82b346

100
monitor-interrupts-by-type.py Executable file
View File

@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Monitor per-second interrupt rates for one CPU (or TOTAL), sorted by type."""
import sys
import time
def parse_interrupts():
"""Parse /proc/interrupts.
Returns (cpu_names, rows) where rows maps label -> (counts, description).
counts is a list of per-CPU integers; description is the trailing text
(e.g. "IO-APIC 2-edge timer" or "Local timer interrupts").
"""
rows = {}
with open("/proc/interrupts") as f:
cpu_names = f.readline().split()
num_cpus = len(cpu_names)
for line in f:
parts = line.split()
if not parts:
continue
label = parts[0].rstrip(":")
counts = []
i = 1
while i < len(parts) and len(counts) < num_cpus:
try:
counts.append(int(parts[i]))
except ValueError:
break
i += 1
if not counts:
continue
description = " ".join(parts[i:])
rows[label] = (counts, description)
return cpu_names, rows
def resolve_cpu(arg, cpu_names):
"""Resolve a CPU argument to an index, or None for TOTAL."""
if arg.upper() == "TOTAL":
return None
name = arg if arg.upper().startswith("CPU") else f"CPU{arg}"
name = name.upper()
for idx, cpu in enumerate(cpu_names):
if cpu.upper() == name:
return idx
print(f"Unknown CPU '{arg}'. Available: {', '.join(cpu_names)}, TOTAL", file=sys.stderr)
sys.exit(1)
def value_for(counts, cpu_idx):
"""Return the count for the selected CPU, or the sum for TOTAL."""
if cpu_idx is None:
return sum(counts)
if cpu_idx < len(counts):
return counts[cpu_idx]
return 0
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <cpu-index|CPU0|TOTAL> [interval-secs]", file=sys.stderr)
sys.exit(1)
cpu_names, prev_rows = parse_interrupts()
cpu_idx = resolve_cpu(sys.argv[1], cpu_names)
interval = float(sys.argv[2]) if len(sys.argv) > 2 else 1.0
target = "TOTAL (all CPUs)" if cpu_idx is None else cpu_names[cpu_idx]
print(f"Monitoring interrupts on {target} every {interval:g}s, sorted by rate (Ctrl-C to stop)\n")
prev = {label: value_for(counts, cpu_idx) for label, (counts, _) in prev_rows.items()}
try:
while True:
time.sleep(interval)
_, curr_rows = parse_interrupts()
deltas = []
for label, (counts, description) in curr_rows.items():
curr = value_for(counts, cpu_idx)
delta = curr - prev.get(label, curr)
if delta > 0:
deltas.append((delta, label, description))
prev[label] = curr
deltas.sort(reverse=True)
total = sum(d for d, _, _ in deltas)
print(f"===== {total} interrupts/{interval:g}s on {target} =====")
print(f"{'RATE':>10} {'IRQ':<8} {'TYPE'}")
print("-" * 60)
for delta, label, description in deltas:
print(f"{delta:>10} {label:<8} {description}")
print()
except KeyboardInterrupt:
print()
if __name__ == "__main__":
main()