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
- 1 Embedded 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
- 10 CPU 파이프라인 분석 — 5-stage·Cortex-M·Cortex-A 비교
- 11 Pipeline Stall 분석 — Data·Structural·Control Hazard·Forwarding
- 12 Branch Prediction 분석 — Static·2-bit·BTB·BHT·Mispredict 비용
- 13 Speculative Execution 분석 — OoO·Reorder Buffer·Register Renaming
- 14 CPU Cache 기초 — L1·L2·L3·Set Associative·Replacement Policy
- 15 Cache Miss 3C Model 분석 — Compulsory·Capacity·Conflict
- 16 Cache Line 최적화 — Alignment·Prefetch·False Sharing 처리
- 17 메모리 대역폭 분석 — STREAM·Roofline·Bus Saturation 측정
- 18 SIMD·NEON 활용 — 128-bit Vector·Auto-Vectorization·SVE/SVE2
- 19 PMU·HPM 하드웨어 카운터 분석 — 정밀 성능 진단
- 20 임베디드 Bus Architecture — AHB·AXI·CHI 진화와 5-Channel
- 21 Bus Contention 진단 — Arbitration·QoS·Starvation 측정
- 22 DMA 성능 최적화 — Burst·Scatter-Gather·Chain·Cache 일관성
- 23 DMA vs CPU Copy 성능 비교 — Break-even·Setup Overhead 실측
- 24 Interrupt Latency 분석 — 진입·종료·Tail-Chaining·Late Arrival
- 25 Interrupt Storm 처리 — NAPI·Rate-Limit·Polling 전환
- 26 MMIO 접근 성능 — Cache Policy·Write-Combining·Volatile·Barrier
- 27 Peripheral Clock 분석 — PLL·Divider·Gating·DVFS
- 28 Power vs Performance 트레이드오프 — DVFS·Race-to-Idle·Big.LITTLE
- 29 Thermal Throttling 분석 — Junction Temp·Trip Point·냉각
- 30 CXL Interconnect 분석 — AI 시대 메모리 대역폭 확장
- 31 Concurrency 기초 — Concurrency vs Parallelism·Race·Memory Model
- 32 False Sharing 진단 — Cache Line Ping-Pong·Padding·측정
- 33 Lock Contention 분석 — Wait·Hold·Convoy·측정 기법
- 34 Spinlock 성능 분석 — Spin-Wait vs Context Switch·Ticket·MCS
- 35 Mutex 성능 분석 — Futex·Adaptive·Priority Inheritance
- 36 Reader-Writer Lock 성능 — Reader/Writer Priority·RCU·Seqlock
- 37 Lock-Free 자료구조 성능 — CAS·ABA·Hazard Pointer·Epoch Reclamation
- 38 Memory Ordering 분석 — Acquire·Release·Seq-Cst·ARM Relaxed Model
- 39 Cache Coherency 프로토콜 — MESI·MOESI·Snoop·Directory
- 40 SMP 성능 분석 — Per-Core·Affinity·Load Balance·Scalability
- 41 Linux perf 기초 — stat·record·report 활용
- 42 Linux perf 고급 — Raw Event·Tracepoint·perf script
- 43 ftrace 활용 — function·function_graph·latency tracer
- 44 eBPF·bpftrace 동적 트레이싱 — 커널 무수정 관측
- 45 Flamegraph 분석 — On-CPU·Off-CPU·Differential
- 46 ARM DS·Lauterbach 분석 — Hardware Trace 전문 도구
- 47 Bare-metal 프로파일링 — GPIO·DWT·SysTick·ITM 활용
- 48 NVIDIA 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로 떨어지는 이유
- 55 CXL.mem 지연·대역폭 실측 — Direct·Switch·Pooled 토폴로지 비교
- 56 CXL 성능 프로파일링 도구 — 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 통계.
같은 시리즈에서 이어 읽기