본문으로 건너뛰기
Embedded Performance Engineering · 23/57

Interrupt Latency 분석 — 진입·종료·Tail-Chaining·Late Arrival

· Hawk · 4분 읽기

#한 줄 요약

“Interrupt latency는 IRQ 발생부터 ISR의 첫 명령까지 걸리는 시간입니다.” 짧을수록 real-time 응답이 강력해집니다.

#Cortex-M Interrupt Latency

CPUCycle@ 168 MHz
Cortex-M01695 ns
Cortex-M0+1589 ns
Cortex-M31271 ns
Cortex-M41271 ns
Cortex-M712 (lower with cache)71 ns
Cortex-M331165 ns

내부적으로는 8개 register의 hardware pushvector fetch, pipeline refill로 구성됩니다.

Cortex-M interrupt latency 구성 — instruction 완료, register push, vector fetch, pipeline refill

#Tail-Chaining - 핵심 트릭

Tail-chaining 비교 — 옛 ARM7은 pop/push를 반복하지만 Cortex-M은 pop을 생략하고 곧바로 ISR B에 진입한다

연속 IRQ 상황에서 50% 효율을 얻습니다.

#Late Arrival

Late arrival — A의 push 진행 중에 더 높은 priority B가 도착하면 push를 그대로 활용하고 vector fetch만 B로 변경한다

Higher priority IRQ가 최소 손실로 선점합니다. Cortex-M3 이상의 표준 동작입니다.

#Lazy Stacking (M4·M7 with FP)

FPU를 사용할 때는 16개 floating register를 추가로 push해야 해서 latency가 32 cycle 더 늘어납니다.

ISR 진입 시 FPU context는 *push하지 않음* (lazy)
ISR이 FPU 명령을 쓰면 그때 push (lazy stacking trigger)
ISR이 FPU를 안 쓰면 push 자체를 생략 (latency 절약)
FPU->FPCCR |= FPU_FPCCR_LSPEN_Msk; // lazy stacking enable (기본)
FPU->FPCCR &= ~FPU_FPCCR_LSPEN_Msk; // disable - 항상 push

#IRQ 진입·종료 시간 측정하기

volatile uint32_t isr_entry_cycle;
void EXTI0_IRQHandler(void) {
isr_entry_cycle = DWT->CYCCNT; // ← 진입 시점
/* ... */
EXTI->PR1 = EXTI_PR1_PIF0;
}
/* Main */
__DSB();
uint32_t t = DWT->CYCCNT;
EXTI->SWIER1 |= EXTI_SWIER1_SWI0; // soft trigger IRQ
__DSB();
uint32_t latency = isr_entry_cycle - t;
printf("Latency: %u cycle\n", latency);

#ISR 처리 시간 단축 - Top-Half / Bottom-Half

volatile uint32_t flag;
void UART_IRQHandler(void) {
/* Top half - *짧게* */
uint8_t byte = UART->RDR;
ring_buffer_put(byte);
flag = 1; // signal
}
void main_loop(void) {
if (flag) {
flag = 0;
process_packet(); // Bottom half - task context
}
}

RTOS에서는 semaphore와 event group으로 bottom half를 깨웁니다.

void UART_IRQHandler(void) {
BaseType_t hp = pdFALSE;
uint8_t byte = UART->RDR;
xQueueSendFromISR(rx_queue, &byte, &hp);
portYIELD_FROM_ISR(hp);
}

#NVIC Priority Grouping

NVIC_SetPriorityGrouping(3); // 4 group, 4 sub-priority
NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(3, 1, 0));
/* group, preempt, sub */
  • Preempt priority가 높으면 다른 IRQ를 선점할 수 있습니다.
  • Sub priority는 pending 중인 IRQ의 선택 순서를 결정합니다.

같은 preempt 그룹이면 먼저 발생한 IRQ가 먼저 처리됩니다. Critical signal에는 높은 preempt를 줍니다.

#Critical Section - IRQ Disable

__disable_irq();
/* critical */
__enable_irq();

Disable 동안 모든 IRQ가 차단되어 response 시간이 늘어납니다. 최대 disable 시간을 측정하는 것이 곧 worst-case latency 측정입니다.

#BASEPRI - Selective Disable

__set_BASEPRI(0x40); // priority 4 이상 차단, 0-3는 통과
/* critical, 그러나 high IRQ는 처리됨 */
__set_BASEPRI(0);

FreeRTOS의 portENTER_CRITICAL이 BASEPRI를 사용합니다.

#Cortex-A - GIC IRQ Latency

단계Cycle
Distribute → CPU IF~5
Acknowledge (read GIC)~10
Pipeline flush·context save~30 (OoO 시)
ISR 진입~50 cycle

Cortex-A53 1 GHz 기준으로 50 ns 수준입니다. 다만 cache miss와 OoO drain이 겹치면 수백 cycle까지 늘어납니다.

자동차 brake와 airbag처럼 sub-µs response가 필요한 곳에서는 Cortex-R5(in-order, 8-cycle IRQ)를 씁니다.

#IRQ Storm 회피

void timer_isr(void) {
/* 매 µs 트리거 - CPU를 다 잡아먹음 */
}

해결책은 다음과 같습니다.

  • Coalescing으로 N개 이벤트마다 한 번만 처리합니다.
  • Polling 전환은 매우 빈번한 이벤트에 적합합니다.
  • DMA로 IRQ 자체를 회피하는 방법도 있습니다.

#FreeRTOS의 ISR Overhead

configMAX_SYSCALL_INTERRUPT_PRIORITY = 5 가정
IRQ priority 5+ - FromISR API 사용
→ entry: 12 cycle (hardware)
→ kernel hook: ~30 cycle
→ bottom half wake: ~50 cycle
→ portYIELD_FROM_ISR: pendSV pending
→ return + PendSV: ~100 cycle (context switch)
Total: ~200 cycle
IRQ priority 0-4 (configMAX_SYSCALL 위) - 직접 hardware ISR
→ entry: 12 cycle
→ ISR work만
→ exit: 12 cycle
Total: ~25 cycle (FreeRTOS 비관여)

Hard real-time IRQ는 configMAX_SYSCALL 위에 두고 RTOS API를 쓰지 않습니다.

#ISR 안에서 lock 금지

void ISR(void) {
xSemaphoreTake(mtx, ...); // 차단될 수 있어 hard fault로 이어집니다
}

*FromISR이나 hardware-only IRQ를 써야 합니다.

#자주 하는 실수

⚠️ Long ISR

void ADC_IRQ(void) {
process_sample(); // 빠름
calculate_fft(); // 수 ms 걸리며 다른 IRQ를 차단합니다
}

FFT는 task로 defer해야 합니다.

⚠️ Disable IRQ 너무 김

__disable_irq();
xSemaphoreTake(sem, portMAX_DELAY); // block + IRQ 차단으로 deadlock

Critical section은 수 µs 이내로 유지해야 합니다.

⚠️ Tail-chaining 효과 무시

작은 ISR 여러 개와 한 큰 ISR을 비교해 보면 작은 ISR 여러 개가 더 빠를 수도 있습니다 (tail-chain 활용).

⚠️ FPU stacking overhead 미인식

FP를 사용하지 않을 때는 lazy stacking을 활용합니다. FPU register를 clobber하는 함수를 IRQ 안에서 호출하는 것은 권장하지 않습니다.

#정리

  • Cortex-M의 IRQ latency는 M3와 M4 기준 12 cycle입니다.
  • Tail-chaining은 6 cycle, late arrival은 seamless하게 선점합니다.
  • Lazy FP stacking은 M4/M7의 latency를 줄여 줍니다.
  • ISR top half는 짧게 유지하고 bottom half는 task로 미룹니다.
  • BASEPRI로 선택적 disable을 걸면 high IRQ는 통과시킬 수 있습니다.
  • Hard real-time IRQ는 configMAX_SYSCALL 위에 둡니다.

다음 편은 Interrupt Storm을 다룹니다.

#관련 항목

Embedded Performance Engineering · 24 of 57

  1. 1Embedded Performance Engineering — 임베디드 성능 엔지니어링 시리즈 소개
  2. 2임베디드 성능 분석 방법론 — Measure → Analyze → Optimize 사이클
  3. 3성능 지표 정의 — Latency·Throughput·Utilization 분석
  4. 4성능 측정의 기본 — Wall-Clock·CPU Cycle·Instruction Count
  5. 5성능 데이터 통계적 분석 — Percentile·Histogram·평균의 함정
  6. 6실시간 성능 분석 — WCET·Jitter·Deadline Miss 측정
  7. 7임베디드 벤치마킹 기초 — 재현성·Warmup·노이즈 제거
  8. 8성능 모델링 — Amdahl·Gustafson·Roofline Model 적용
  9. 9프로파일링 기법 개요 — Sampling vs Instrumentation·PGO·LTO
  10. 10CPU 파이프라인 분석 — 5-stage·Cortex-M·Cortex-A 비교
  11. 11Pipeline Stall 분석 — Data·Structural·Control Hazard·Forwarding
  12. 12Branch Prediction 분석 — Static·2-bit·BTB·BHT·Mispredict 비용
  13. 13Speculative Execution 분석 — OoO·Reorder Buffer·Register Renaming
  14. 14CPU Cache 기초 — L1·L2·L3·Set Associative·Replacement Policy
  15. 15Cache Miss 3C Model 분석 — Compulsory·Capacity·Conflict
  16. 16Cache Line 최적화 — Alignment·Prefetch·False Sharing 처리
  17. 17메모리 대역폭 분석 — STREAM·Roofline·Bus Saturation 측정
  18. 18SIMD·NEON 활용 — 128-bit Vector·Auto-Vectorization·SVE/SVE2
  19. 19PMU·HPM 하드웨어 카운터 분석 — 정밀 성능 진단
  20. 20임베디드 Bus Architecture — AHB·AXI·CHI 진화와 5-Channel
  21. 21Bus Contention 진단 — Arbitration·QoS·Starvation 측정
  22. 22DMA 성능 최적화 — Burst·Scatter-Gather·Chain·Cache 일관성
  23. 23DMA vs CPU Copy 성능 비교 — Break-even·Setup Overhead 실측
  24. 24Interrupt Latency 분석 — 진입·종료·Tail-Chaining·Late Arrival
  25. 25Interrupt Storm 처리 — NAPI·Rate-Limit·Polling 전환
  26. 26MMIO 접근 성능 — Cache Policy·Write-Combining·Volatile·Barrier
  27. 27Peripheral Clock 분석 — PLL·Divider·Gating·DVFS
  28. 28Power vs Performance 트레이드오프 — DVFS·Race-to-Idle·Big.LITTLE
  29. 29Thermal Throttling 분석 — Junction Temp·Trip Point·냉각
  30. 30CXL Interconnect 분석 — AI 시대 메모리 대역폭 확장
  31. 31Concurrency 기초 — Concurrency vs Parallelism·Race·Memory Model
  32. 32False Sharing 진단 — Cache Line Ping-Pong·Padding·측정
  33. 33Lock Contention 분석 — Wait·Hold·Convoy·측정 기법
  34. 34Spinlock 성능 분석 — Spin-Wait vs Context Switch·Ticket·MCS
  35. 35Mutex 성능 분석 — Futex·Adaptive·Priority Inheritance
  36. 36Reader-Writer Lock 성능 — Reader/Writer Priority·RCU·Seqlock
  37. 37Lock-Free 자료구조 성능 — CAS·ABA·Hazard Pointer·Epoch Reclamation
  38. 38Memory Ordering 분석 — Acquire·Release·Seq-Cst·ARM Relaxed Model
  39. 39Cache Coherency 프로토콜 — MESI·MOESI·Snoop·Directory
  40. 40SMP 성능 분석 — Per-Core·Affinity·Load Balance·Scalability
  41. 41Linux perf 기초 — stat·record·report 활용
  42. 42Linux perf 고급 — Raw Event·Tracepoint·perf script
  43. 43ftrace 활용 — function·function_graph·latency tracer
  44. 44eBPF·bpftrace 동적 트레이싱 — 커널 무수정 관측
  45. 45Flamegraph 분석 — On-CPU·Off-CPU·Differential
  46. 46ARM DS·Lauterbach 분석 — Hardware Trace 전문 도구
  47. 47Bare-metal 프로파일링 — GPIO·DWT·SysTick·ITM 활용
  48. 48NVIDIA Nsight Systems — GPU·NPU 포함 시스템 분석
  49. 49모던 프로파일러 비교 — Tracy·Hotspot·uftrace·Coz
  50. 50연속 프로파일링 — Parca·Pixie·Pyroscope·Tetragon
  51. 51실전 사례 — ISR Latency 100µs Deadline Miss 추적
  52. 52실전 사례 — Matrix Multiply가 예상의 10배 느린 이유
  53. 53실전 사례 — 8-core가 4-core를 넘으면 throughput이 떨어지는 이유
  54. 54실전 사례 — 카메라 1080p 60fps가 30fps로 떨어지는 이유
  55. 55CXL.mem 지연·대역폭 실측 — Direct·Switch·Pooled 토폴로지 비교
  56. 56CXL 성능 프로파일링 도구 — cxl-cli·DAMON·perf-mem 활용
  57. 57실전 사례 — CXL.mem 추가로 LLM inference KV cache 처리량 회복