The Physics of Interrupts: Top Half, Bottom Half & Latency

Why the CPU stops everything when you type a key. The physics of Pipeline Flushes, the IDT (Interrupt Descriptor Table), and the 'Top Half' constraint.

Beginner 40 min read Expert Version →

🎯 What You'll Learn

  • Trace the electrical path of an IRQ (Pin -> APIC -> CPU)
  • Deconstruct the cost of a Pipeline Flush (~2000 cycles)
  • Differentiate Top Half (Hard IRQ) vs Bottom Half (SoftIRQ)
  • Pin Interrupts to specific Cores (SMP Affinity)
  • Debug Interrupt Storms using `perf` and `/proc`

Introduction

In the physical world, if you are reading a book and someone taps your shoulder, you stop reading. You lose your place. You have to “context switch” to listen to them.

This is exactly what happens to a CPU. An Interrupt (IRQ) is not a polite request. It is an electrical voltage on a specific pin that forces the CPU Control Unit to Abandon the Current Instruction Stream and jump to a specific memory address.

This lesson explores the physics of that “jump”-and why it is the enemy of low latency.


The Physics: The Pipeline Flush

Modern CPUs are superscalar pipelines. They fetch, decode, and execute 100+ instructions in parallel. When an Interrupt occurs, the CPU must:

  1. Stop Fetching: No new instructions.
  2. Drain the Pipeline: Finish what is partially done.
  3. Flush: Discard speculative work.
  4. Save Registers: Push RIP, RFLAGS, CS to the stack.
  5. Jump: Load the Interrupt Handler address from the IDT.

The Cost: A “Pipeline Flush” costs ~2000+ CPU cycles. If you process 1 Million Packets per Second (1M Interrupts), you burn 2 Billion cycles just on flushing pipelines. This is why we poll (NAPI).


The Handling: Top Half vs Bottom Half

The Kernel is terrified of Interrupts. Why? Because when an Interrupt Handler runs, it often disables all other interrupts on that core. If the handler takes too long (e.g., 1ms), the NIC buffer overflows, and packets are dropped forever.

To solve this, Linux splits the work:

1. The Top Half (Hard IRQ)

  • Goal: Acknowledge hardware as fast as possible.
  • Physics: Runs with Interrupts Disabled.
  • Action:
    • Saves timestamp.
    • Copies data from hardware register.
    • Schedules the Bottom Half.
    • Exits (Total time: < 10 microseconds).

2. The Bottom Half (SoftIRQ / Tasklet)

  • Goal: Do the actual work (Processing TCP, writing to disk).
  • Physics: Runs with Interrupts Enabled.
  • Action: Can take milliseconds. Can be preempted by other Hard IRQs.

Strategy: CPU Affinity (SMP)

By default, an interrupt can hit any CPU core. This is bad for cache locality. If Packet 1 hits Core 0, and Packet 2 hits Core 1, the L1/L2 caches are cold.

We use SMP Affinity to pin interrupts to specific cores.

The Bitmask

In /proc/irq/<IRQ_ID>/smp_affinity, we write a hexadecimal bitmask.

  • 1 (0001) -> CPU 0
  • 2 (0010) -> CPU 1
  • 4 (0100) -> CPU 2
  • f (1111) -> All CPUs (0-3)

Example: Pinning the Network Card (IRQ 120) to CPU 3:

echo 8 > /proc/irq/120/smp_affinity
# 8 is 1000 in binary -> CPU 3

Code: Detecting Interrupt Storms

An “Interrupt Storm” occurs when hardware is broken and screams for attention 100,000 times a second.

#!/bin/bash
# irq_storm_detector.sh

# Snapshot 1
cat /proc/interrupts > /tmp/irq1

sleep 1

# Snapshot 2
cat /proc/interrupts > /tmp/irq2

# Calculate Delta (Simplified)
# We look for lines where difference > 10000
echo "Monitoring for IRQ Storms..."
diff /tmp/irq1 /tmp/irq2 | grep -E "[0-9]{5}"

If you see an implementation like acpi or usb firing 50k times a second, that device is likely malfunctioning.


Practice Exercises

Exercise 1: The Watcher (Beginner)

Task: Run watch -n 1 "cat /proc/interrupts". Action: Move your mouse rapidly. Observation: Watch the i8042 or xhci_hcd (USB) interrupt counts skyrocket. Your physical movement is generating electrical signals that stop the CPU.

Exercise 2: Binding (Intermediate)

Task: Identify your WiFi card IRQ (iwlwifi). Action: Bind it to CPU 0 only (echo 1 > ...). Observation: Verify in /proc/interrupts that only CPU 0’s counter increments for that row.

Exercise 3: Isolation (Advanced)

Task: Isolate CPU 3 from the kernel scheduler (isolcpus=3 in grub). Action: Manually assign the NIC IRQ to CPU 3. Result: You now have a “dedicated packet processing core” that does nothing but handle network traffic, free from OS jitter.


Knowledge Check

  1. What happens to the CPU pipeline during an interrupt?
  2. Why does the Top Half run with interrupts disabled?
  3. What is the hex affinity mask for CPU 0 and CPU 1 together?
  4. Why is irqbalance bad for low-latency systems?
  5. Which runs first: Hard IRQ or SoftIRQ?
Answers
  1. It is flushed. All speculative instructions are discarded.
  2. Race Conditions. To prevent the same handler from re-entering itself recursively.
  3. 3. (Binary 0011).
  4. Jitter. It moves IRQs around randomly, destroying CPU cache locality.
  5. Hard IRQ. The Hard IRQ schedules the SoftIRQ.

Summary

  • Interrupts: Destroy pipeline efficiency.
  • Top Half: Fast, crucial, greedy.
  • Bottom Half: Slow, thorough, safe.
  • Affinity: Pinning work to keeping caches hot.

Questions about this lesson? Working on related infrastructure?

Let's discuss