2026-04-25
Every time you press a key, receive a network packet, or a timer fires, something must break the CPU out of whatever it's doing right now. That something is the interrupt controller — a dedicated piece of hardware that arbitrates between dozens or hundreds of devices all screaming for attention simultaneously.
The classic x86 design started with the Intel 8259 PIC (Programmable Interrupt Controller), which handled 8 interrupt lines. Two were daisy-chained to give 15 usable IRQs. This worked in 1981. It does not work when your modern server has 200+ MSI-capable PCIe devices across 128 cores.
The modern solution is the APIC (Advanced Programmable Interrupt Controller) architecture, split into two parts:
The critical design challenge is interrupt routing. When a NIC fires an interrupt, which of your 64 cores handles it? Strategies include:
On ARM systems, the equivalent is the GIC (Generic Interrupt Controller), now at version 4. GICv4 adds direct injection of virtual interrupts to guest VMs, eliminating expensive VM exits — a huge win for virtualization.
Real-world example: A 100 Gbps NIC processing 148 million packets per second (64-byte frames) generates one interrupt per batch of ~64 packets with coalescing enabled. Without coalescing, at one interrupt per packet, you'd need to service an interrupt every 6.75 nanoseconds — roughly 20 clock cycles at 3 GHz. That's less time than a single cache miss. This is why interrupt coalescing and RSS (Receive Side Scaling) across cores aren't optional at high speeds; they're survival.
Rule of thumb: Each interrupt costs roughly 2–5 microseconds of CPU time (context save, handler execution, context restore). At 10,000 interrupts/second per core, you lose about 2–5% of that core's throughput just to interrupt overhead.
