#!/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]} [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()