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

PMU·HPM 하드웨어 카운터 분석 — 정밀 성능 진단

· Hawk · 6분 읽기

#한 줄 요약

**“PMU = CPU 내장 프로파일러”**입니다. 측정 overhead가 거의 0에 가깝습니다.

#ARMv8 PMU 구조

항목사양
Counter 수Cortex-A53 = 6, A72 = 6, M-class = 4~
Counter 폭32-bit (overflow interrupt)
Cycle counter별도 64-bit (PMCCNTR_EL0)
Event 선택각 counter에 event ID 할당
/* User mode access 활성화 (kernel 권한 필요) */
asm volatile ("msr pmuserenr_el0, %0" :: "r"(1));
asm volatile ("msr pmcntenset_el0, %0" :: "r"(0x80000000)); // CCNT enable
asm volatile ("msr pmcr_el0, %0" :: "r"(1)); // PMU enable
uint64_t cycles;
asm volatile ("mrs %0, pmccntr_el0" : "=r"(cycles));

#ARMv8 표준 Event IDs

ID이름의미
0x00SW_INCR소프트 카운터
0x01L1I_CACHE_REFILLL1 I-cache miss
0x03L1D_CACHE_REFILLL1 D-cache miss
0x04L1D_CACHEL1 D-cache access
0x08INST_RETIRED명령 완료
0x10BR_MIS_PREDbranch mispredict
0x11CPU_CYCLEScycle (CCNT와 동일)
0x13MEM_ACCESSmemory access
0x17L2D_CACHE_REFILLL2 miss
0x18L2D_CACHE_ACCESSL2 access
0x23STALL_FRONTENDfront-end stall
0x24STALL_BACKENDback-end stall

각 CPU별 Technical Reference Manual을 확인해야 합니다. CPU마다 implementation-specific event가 추가로 정의되어 있습니다.

#Linux perf — 가장 흔한 도구

Terminal window
# 기본 측정
perf stat ./prog
# 특정 event
perf stat -e cycles,instructions,branches,branch-misses ./prog
# Raw event (PMU 직접)
perf stat -e r03,r04 ./prog # L1D_CACHE_REFILL, L1D_CACHE
perf stat -e r23,r24 ./prog # STALL_FRONTEND, STALL_BACKEND
# Profiling
perf record -e cycles -g ./prog
perf report

perf record 결과로 function별 cycle 분포를 확인할 수 있고, 이를 통해 hotspot을 발견합니다.

#핵심 비율 — IPC·MPKI

IPC=INST_RETIREDCPU_CYCLES(높을수록 좋음, target 1+)\text{IPC} = \frac{\text{INST\_RETIRED}}{\text{CPU\_CYCLES}} \quad (\text{높을수록 좋음, target } 1+)

MPKI=L1D_CACHE_REFILL×1000INST_RETIRED(낮을수록 좋음)\text{MPKI} = \frac{\text{L1D\_CACHE\_REFILL} \times 1000}{\text{INST\_RETIRED}} \quad (\text{낮을수록 좋음})

MPKI < 10 — cache 효율 좋음
MPKI 10-30 — 보통
MPKI > 30 — cache 문제

Branch mispredict rate=BR_MIS_PREDBRANCHES\text{Branch mispredict rate} = \frac{\text{BR\_MIS\_PRED}}{\text{BRANCHES}}

5% 미만이면 양호, 10% 초과면 문제입니다.

Frontend bound=STALL_FRONTENDCYCLES,Backend bound=STALL_BACKENDCYCLES\text{Frontend bound} = \frac{\text{STALL\_FRONTEND}}{\text{CYCLES}}, \quad \text{Backend bound} = \frac{\text{STALL\_BACKEND}}{\text{CYCLES}}

둘 합이 50% 이상이면 stall 지배적입니다.

#Top-Down Microarchitecture Analysis

Intel이 먼저 도입했고, ARM도 비슷한 분류 체계를 사용합니다.

Top-Down Microarchitecture Analysis — CPU cycle 분배 분석

Bottleneck을 식별한 뒤 적절한 최적화를 적용합니다. cache miss라면 tiling, mispredict라면 branchless 변환이 그 예입니다.

#Cortex-M PMU

Cortex-M3/M4는 작은 PMU를 가집니다.

DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
uint32_t cycles_start = DWT->CYCCNT;
/* code */
uint32_t cycles_end = DWT->CYCCNT;

Cortex-M7 이상은 LSU·FOLD·CPI 등 추가 counter를 제공합니다.

DWT->LSUCNT // load/store cycle
DWT->CPICNT // CPI miss (extra) cycle
DWT->EXCCNT // exception overhead
DWT->FOLDCNT // folded instruction (e.g. IT)
DWT->SLEEPCNT // sleep cycle
float cpi = (float)(DWT->CPICNT + DWT->CYCCNT) / DWT->CYCCNT;

#RISC-V HPM (Hardware Performance Monitor)

mcycle — cycle counter (64-bit)
minstret — instruction retired
mhpmcounter3 — mhpmcounter31 — 28 programmable counter
mhpmevent3 — mhpmevent31 — event ID 선택

Event ID는 vendor마다 다릅니다. SiFive U74 예시는 다음과 같습니다.

ID의미
0x100I-cache miss
0x101I-cache busy
0x800D-cache miss
0x801D-cache busy
0x100ABranch mispredict
asm volatile ("csrw mhpmevent3, %0" :: "r"(0x800)); // D-cache miss
uint64_t count;
asm volatile ("csrr %0, mhpmcounter3" : "=r"(count));

#Sampling — Statistical Profiling

Terminal window
perf record -F 1000 -g ./prog # 1000 Hz sampling
perf report --stdio

매 1 ms마다 PC와 call stack을 캡쳐합니다. Flamegraph로 시각화하면 다음과 같습니다.

Terminal window
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

overhead가 1-3% 정도로 매우 적어서 production 환경에서도 사용할 수 있습니다.

#Streamline (ARM) / VTune (Intel)

대표적인 GUI 도구들은 다음과 같습니다.

  • ARM Streamline: Cortex-A/M target에서 perf 데이터를 수집합니다.
  • Intel VTune: Top-down 자동 분석을 제공합니다.
  • Apple Instruments: macOS·iOS용입니다.
  • NVIDIA Nsight: GPU와 CPU를 함께 봅니다.

학습 곡선이 가파르지만 강력합니다.

#자동차·항공 — RTOS PMU 활용

자동차 ECU(NXP S32K3, Cortex-M7)에서는 PMU로 WCET 분석을 수행합니다.

void task(void) {
uint32_t start = DWT->CYCCNT;
do_work();
uint32_t cycles = DWT->CYCCNT - start;
if (cycles > WCET_BUDGET) {
log_overrun(cycles); // 디버깅용
}
}

KSLV-II 누리 flight computer에서도 task별 cycle budget을 측정해 안전 마진을 확보합니다.

#Event Multiplexing

PMU counter는 6개인데 측정하고 싶은 event가 12개라면 time-sharing이 필요합니다.

Terminal window
perf stat -e r03,r04,r10,r11,r17,r23,r24 ./prog
# 6 이하면 동시, 초과시 자동 multiplex
# perf가 결과를 normalize (scaling factor)

다만 sampling 방식이라 정확도는 떨어집니다. 가능하면 측정 event 수를 counter 수 이하로 유지하는 것이 좋습니다.

#자주 하는 실수

⚠️ Cycle 측정에 barrier 누락

uint32_t start = DWT->CYCCNT;
do_work();
uint32_t end = DWT->CYCCNT;

OoO CPU에서는 do_work 시작이 start 측정 전에 일어날 수도 있습니다. 다음과 같이 barrier를 넣습니다.

__DSB(); __ISB();
uint32_t start = DWT->CYCCNT;
do_work();
__DSB(); __ISB();
uint32_t end = DWT->CYCCNT;

⚠️ Counter overflow

32-bit 카운터를 1 GHz에서 돌리면 약 4초만에 overflow가 납니다. 긴 측정에서는 overflow handler를 두거나 64-bit cycle counter(ARMv8 PMCCNTR)를 사용합니다.

⚠️ User-mode PMU 접근

기본적으로 PMU 접근은 kernel mode 전용입니다. Linux에서는 /proc/sys/kernel/perf_event_paranoid로 제어합니다.

Terminal window
echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid # user access

Production 서버에서는 보안 위험이 있으므로 신중하게 적용해야 합니다.

⚠️ ISR이 측정 손상

PMU counter는 ISR도 함께 카운트합니다. ISR이 빈번하면 측정 결과에 노이즈가 섞입니다. ISR-free 구간을 잡거나, 측정에서 ISR을 빼는 방법을 씁니다.

#정리

  • PMU는 CPU 내장 hardware counter입니다. overhead가 거의 0입니다.
  • ARMv8은 6개 counter와 별도의 cycle counter를 제공합니다.
  • 핵심 metric은 IPC, MPKI, mispredict rate, STALL입니다.
  • Linux perf가 사실상 표준 도구입니다.
  • Cortex-M은 DWT counter, Cortex-A는 PMU를 씁니다.
  • RISC-V는 mhpmcounter로 programmable counter를 제공합니다.
  • WCET 검증, hotspot 파악, top-down 분석에 핵심적인 도구입니다.

다음 파트에서는 Compiler & Optimization을 다룹니다.

#관련 항목

Embedded Performance Engineering · 19 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 처리량 회복