Interrupt Storm 처리 — NAPI·Rate-Limit·Polling 전환
#한 줄 요약
“IRQ가 너무 많으면 CPU가 100% ISR에 잡힙니다.” context switch overhead 때문에 throughput이 오히려 떨어집니다.
#Storm 발생 시나리오
Gigabit Ethernet에서 1 Gbps × 64-byte frame = 1.95 Mpps. 매 패킷마다 IRQ를 걸면:
| 항목 | 값 |
|---|---|
| IRQ 빈도 | 1.95 M IRQ/sec |
| ISR 비용 | 진입 12 cycle + 처리 100 cycle |
| 총 cycle | 112 × 1.95 M = 220 Mcycle/sec |
| 1 GHz CPU 점유 | 22% ISR overhead만으로 |
10 Gbit에서는 CPU 100%까지 갈 수 있습니다. 그러면 데이터 처리를 전혀 못 해서 throughput이 0이 됩니다.
#Top-Half 짧음 + Bottom-Half에서 batch
volatile int pending = 0;
void net_rx_irq(void) { pending = 1; // 매우 짧음 NET->IMR &= ~RX_INT; // IRQ mask (다음 IRQ 차단)}
void net_task(void) { while (pending) { pending = 0; process_all_packets(); // batch NET->IMR |= RX_INT; // IRQ unmask }}핵심은 ISR이 자기 IRQ를 disable하는 것입니다. 이렇게 하면 storm이 끝날 때까지 ISR이 한 번만 호출됩니다.
#NAPI - Linux Pattern
/* NAPI (New API) - Linux network driver 표준 */
static int net_napi_poll(struct napi_struct *napi, int budget) { int packets = 0; while (packets < budget) { struct sk_buff *skb = rx_one_packet(...); if (!skb) break; netif_receive_skb(skb); packets++; }
if (packets < budget) { napi_complete(napi); // budget 안 채움 → IRQ 다시 enable enable_rx_irq(); } return packets;}
static irqreturn_t net_irq(int irq, void *dev_id) { disable_rx_irq(); napi_schedule(&napi); return IRQ_HANDLED;}- IRQ 한 번이 들어오면 poll mode로 전환합니다.
- Budget만큼 처리합니다 (예: 64 packet).
- Queue가 비면 IRQ를 다시 enable합니다.
효과는 트래픽이 많을 때는 polling으로 overhead가 0이 되고, 적을 때는 IRQ로 짧은 latency를 얻는 것입니다.
#Interrupt Coalescing (Hardware)
/* 네트워크·SATA·NVMe 칩 - coalescing register */NIC->IRQ_COALESCE = COALESCE_TIME(50us) | COALESCE_COUNT(16);/* → 16 패킷 또는 50µs마다 IRQ */장점은 IRQ rate가 줄어드는 것이고, 단점은 평균 latency가 늘어나는 것입니다.
Trade-off:
- short coalesce: low latency, high CPU
- long coalesce: high throughput, high latency
이더넷에서는 50µs / 16 packet이 일반적인 default입니다.
#Adaptive Coalescing
if (cpu_load > 80%) coalesce_time = 200us; // CPU 보호else coalesce_time = 20us; // latency 우선Linux ethtool -C eth0 adaptive-rx on.
#DMA Coalescing
/* Cortex-M DMA - circular buffer + half/full transfer IRQ */HAL_UART_Receive_DMA(&huart, rx_buf, 4096);/* → IRQ at 2048 byte (half) + 4096 byte (full) */매 byte마다가 아니라 buffer 절반마다 IRQ를 걸어 IRQ rate를 1/2000로 줄입니다.
#Polling Mode - Traffic Heavy
/* 1 Mpps 이상이면 IRQ 자체가 무의미합니다 */while (1) { while (rx_queue_not_empty()) { process_packet(); } /* short sleep */}DPDK와 SPDK 패턴이 바로 이 user-space polling입니다. IRQ 0개로 60 Mpps까지 달성합니다.
#Hybrid - busy-poll Linux
sysctl net.core.busy_poll = 50 // 50 µs polling 후 IRQ로 fallbackLow-latency app에서는 IRQ로 깰 때까지 짧게 polling을 시도합니다.
#IRQ Affinity
echo 2 > /proc/irq/24/smp_affinity # IRQ 24 → CPU 1만이더넷 IRQ를 특정 코어에 고정하면 cache locality를 얻고 다른 코어를 보호할 수 있습니다.
# RSS (Receive Side Scaling) — 자동 분산ethtool -X eth0 equal 4 # 4 CPU에 균등 분산#ICMP Flood - 공격 시 storm
악의적 트래픽 (ICMP flood) → ISR storm → CPU 100% → OS hang해결책은 다음과 같습니다.
sysctl net.ipv4.icmp_ratelimit = 100으로 rate limit을 겁니다.- 방화벽에서 NIC IRQ 전에 drop합니다 (XDP 사용).
XDP (eXpress Data Path)는 Linux BPF로 driver 단계에서 drop하는 기법입니다.
#Embedded - IRQ Budget 계산
RTOS task 주기 10 ms, ISR overhead 1 µs/IRQ:
| 단계 | 값 |
|---|---|
| 이론 IRQ budget | 10 ms × 100% = 10,000 IRQ |
| 실제 budget (50% for task) | 5,000 IRQ |
| 안전 마진 (20% headroom) | 4,000 IRQ → 0.4 MHz max IRQ rate |
IRQ rate가 budget을 넘으면 task가 deadline을 놓칩니다. CAN bus 1 Mbps에서 메시지가 폭주할 때 흔히 발생합니다.
#Lock Pendling vs IRQ Off
/* Path 1: IRQ off in critical */__disable_irq();critical_code();__enable_irq();/* → critical 동안 모든 IRQ 차단 */
/* Path 2: pending PendSV */__set_BASEPRI(SYSCALL_PRI); // selectivecritical_code();__set_BASEPRI(0);/* → low priority IRQ만 차단 */Path 2가 storm에 더 강합니다. high priority IRQ는 그대로 동작하기 때문입니다.
#자주 하는 실수
⚠️ ISR에서 처리 다 함
void net_irq(void) { while (rx_queue_not_empty()) { process_packet(); // ISR 안에서 무한 loop }}처리는 task에 위임해야 합니다. 그렇지 않으면 storm 발생 시 ISR에 영원히 머무릅니다.
⚠️ Coalescing 0 / 1
NIC->IRQ_COALESCE = 0;/* → 매 packet마다 IRQ. 보통은 쓰지 않습니다 */기본값(50µs 또는 16 packet)을 사용합니다.
⚠️ DMA half-transfer IRQ 무시
HAL_UART_Receive_DMA(&huart, buf, 4096);/* full transfer IRQ만 처리하면 buffer 절반은 *나중에야* 처리됩니다 */매 half에서 해당 절반을 처리하면 latency를 절반으로 줄일 수 있습니다.
⚠️ 우선순위 잘못
낮은 priority IRQ가 상시 대기 상태가 되면 high IRQ 처리 동안 storm이 발생해 high IRQ 처리가 지연됩니다.
#정리
- Storm은 IRQ rate가 CPU 처리 능력을 넘어선 상태입니다.
- NAPI 패턴은 IRQ → polling → IRQ를 동적으로 전환합니다.
- Coalescing으로 hardware IRQ rate를 제한합니다.
- 큰 transfer에서는 DMA와 buffer IRQ를 함께 씁니다(매 byte 아님).
- IRQ affinity와 RSS로 다중 코어에 분산합니다.
- DPDK와 XDP는 driver/kernel을 우회합니다.
다음 편은 MMIO 접근을 다룹니다.
#관련 항목
Embedded Performance Engineering · 25 of 57
- 1Embedded Performance Engineering — 임베디드 성능 엔지니어링 시리즈 소개
- 2임베디드 성능 분석 방법론 — Measure → Analyze → Optimize 사이클
- 3성능 지표 정의 — Latency·Throughput·Utilization 분석
- 4성능 측정의 기본 — Wall-Clock·CPU Cycle·Instruction Count
- 5성능 데이터 통계적 분석 — Percentile·Histogram·평균의 함정
- 6실시간 성능 분석 — WCET·Jitter·Deadline Miss 측정
- 7임베디드 벤치마킹 기초 — 재현성·Warmup·노이즈 제거
- 8성능 모델링 — Amdahl·Gustafson·Roofline Model 적용
- 9프로파일링 기법 개요 — Sampling vs Instrumentation·PGO·LTO
- 10CPU 파이프라인 분석 — 5-stage·Cortex-M·Cortex-A 비교
- 11Pipeline Stall 분석 — Data·Structural·Control Hazard·Forwarding
- 12Branch Prediction 분석 — Static·2-bit·BTB·BHT·Mispredict 비용
- 13Speculative Execution 분석 — OoO·Reorder Buffer·Register Renaming
- 14CPU Cache 기초 — L1·L2·L3·Set Associative·Replacement Policy
- 15Cache Miss 3C Model 분석 — Compulsory·Capacity·Conflict
- 16Cache Line 최적화 — Alignment·Prefetch·False Sharing 처리
- 17메모리 대역폭 분석 — STREAM·Roofline·Bus Saturation 측정
- 18SIMD·NEON 활용 — 128-bit Vector·Auto-Vectorization·SVE/SVE2
- 19PMU·HPM 하드웨어 카운터 분석 — 정밀 성능 진단
- 20임베디드 Bus Architecture — AHB·AXI·CHI 진화와 5-Channel
- 21Bus Contention 진단 — Arbitration·QoS·Starvation 측정
- 22DMA 성능 최적화 — Burst·Scatter-Gather·Chain·Cache 일관성
- 23DMA vs CPU Copy 성능 비교 — Break-even·Setup Overhead 실측
- 24Interrupt Latency 분석 — 진입·종료·Tail-Chaining·Late Arrival
- 25Interrupt Storm 처리 — NAPI·Rate-Limit·Polling 전환
- 26MMIO 접근 성능 — Cache Policy·Write-Combining·Volatile·Barrier
- 27Peripheral Clock 분석 — PLL·Divider·Gating·DVFS
- 28Power vs Performance 트레이드오프 — DVFS·Race-to-Idle·Big.LITTLE
- 29Thermal Throttling 분석 — Junction Temp·Trip Point·냉각
- 30CXL Interconnect 분석 — AI 시대 메모리 대역폭 확장
- 31Concurrency 기초 — Concurrency vs Parallelism·Race·Memory Model
- 32False Sharing 진단 — Cache Line Ping-Pong·Padding·측정
- 33Lock Contention 분석 — Wait·Hold·Convoy·측정 기법
- 34Spinlock 성능 분석 — Spin-Wait vs Context Switch·Ticket·MCS
- 35Mutex 성능 분석 — Futex·Adaptive·Priority Inheritance
- 36Reader-Writer Lock 성능 — Reader/Writer Priority·RCU·Seqlock
- 37Lock-Free 자료구조 성능 — CAS·ABA·Hazard Pointer·Epoch Reclamation
- 38Memory Ordering 분석 — Acquire·Release·Seq-Cst·ARM Relaxed Model
- 39Cache Coherency 프로토콜 — MESI·MOESI·Snoop·Directory
- 40SMP 성능 분석 — Per-Core·Affinity·Load Balance·Scalability
- 41Linux perf 기초 — stat·record·report 활용
- 42Linux perf 고급 — Raw Event·Tracepoint·perf script
- 43ftrace 활용 — function·function_graph·latency tracer
- 44eBPF·bpftrace 동적 트레이싱 — 커널 무수정 관측
- 45Flamegraph 분석 — On-CPU·Off-CPU·Differential
- 46ARM DS·Lauterbach 분석 — Hardware Trace 전문 도구
- 47Bare-metal 프로파일링 — GPIO·DWT·SysTick·ITM 활용
- 48NVIDIA Nsight Systems — GPU·NPU 포함 시스템 분석
- 49모던 프로파일러 비교 — Tracy·Hotspot·uftrace·Coz
- 50연속 프로파일링 — Parca·Pixie·Pyroscope·Tetragon
- 51실전 사례 — ISR Latency 100µs Deadline Miss 추적
- 52실전 사례 — Matrix Multiply가 예상의 10배 느린 이유
- 53실전 사례 — 8-core가 4-core를 넘으면 throughput이 떨어지는 이유
- 54실전 사례 — 카메라 1080p 60fps가 30fps로 떨어지는 이유
- 55CXL.mem 지연·대역폭 실측 — Direct·Switch·Pooled 토폴로지 비교
- 56CXL 성능 프로파일링 도구 — cxl-cli·DAMON·perf-mem 활용
- 57실전 사례 — CXL.mem 추가로 LLM inference KV cache 처리량 회복
관련 글
Interrupt Latency 분석 — 진입·종료·Tail-Chaining·Late Arrival
Cortex-M 12-cycle latency. Tail-chaining 6-cycle. Late arrival, lazy stacking, FreeRTOS hooks.
실전 사례 — CXL.mem 추가로 LLM inference KV cache 처리량 회복
70B 모델 KV cache가 HBM 한계를 넘어 throughput이 무너졌을 때, CXL.mem 256 GB pool 추가로 회복한 실전 케이스.
CXL 성능 프로파일링 도구 — cxl-cli·DAMON·perf-mem 활용
CXL.mem 환경 성능 도구 — cxl-cli 토폴로지·DAMON page activity·perf-mem로 보는 CXL 트래픽·numastat 통계.