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

Flamegraph 분석 — On-CPU·Off-CPU·Differential

· Hawk · 4분 읽기

#한 줄 요약

“Flamegraph는 수천 개의 stack sample을 한 장의 가로폭으로 압축해, 어디서 시간을 쓰는지 한눈에 보여 줍니다.”

#어떤 문제를 푸는가

perf report의 tree view는 정확하지만 한 화면에 한 path만 보여 줍니다. 100개 함수가 균등하게 hot하면 모든 path를 펼쳐 보며 비교해야 합니다.

Flamegraph는 동일한 stack sample을 가로폭으로 합쳐 보여 줍니다. 가로폭이 넓으면 hot, 세로가 높으면 깊은 호출입니다. 색상은 의미가 없고 시각적 구분 용도이며, 정렬은 알파벳 순입니다.

이 글에서는 perf로 stack을 수집해 flamegraph로 변환하는 표준 workflow, off-CPU flamegraph, 차분 flamegraph를 살펴봅니다.

#표준 Workflow — perf → flamegraph

Brendan Gregg의 flamegraph 스크립트는 GitHub에서 받습니다.

Terminal window
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph

수집과 변환은 세 단계입니다.

Terminal window
# 1. perf record로 99 Hz로 stack sample 수집
perf record -F 99 -g --call-graph dwarf -- ./app
# 또는 PID 지정
perf record -F 99 -g -p <pid> -- sleep 30
# 2. perf script로 텍스트로 dump
perf script > out.perf
# 3. stackcollapse-perf.pl로 collapsed format으로
./stackcollapse-perf.pl out.perf > out.folded
# 4. flamegraph.pl로 SVG 생성
./flamegraph.pl out.folded > flame.svg

생성된 SVG는 브라우저에서 열면 클릭과 검색이 가능합니다.

#Collapsed Format 이해

stackcollapse-perf.pl의 출력은 매우 단순합니다.

app;main;process_request;parse_json 1234
app;main;process_request;db_query 567
app;main;write_response 89

세미콜론으로 구분된 stack과 sample 횟수입니다. 이 포맷이 단순하므로 다른 source에서도 같은 형식으로만 만들면 동일한 flamegraph를 그릴 수 있습니다.

Terminal window
# BCC profile이 직접 만들어 줌
profile-bpfcc -F 99 -af 30 > out.folded
flamegraph.pl < out.folded > flame.svg
# Java용
stackcollapse-jstack.pl jstack.txt > out.folded

#읽는 법

폭 — 해당 stack의 sample 비율 (전체 시간에서 차지하는 비중)
높이 — 호출 깊이
색상 — 무의미 (시각 구분용)
정렬 — 알파벳 순 (시간 순서 아님)

가장 흔한 패턴은 다음과 같습니다.

[main ] ← 폭 = 전체
[ a ][ b ] ← a는 30%, b는 70% 시간
[ a1][ b1][b2] ← 자식들

a가 30%의 시간을 쓰고 b가 70%라면, b의 자식 중 가장 넓은 것이 가장 큰 hot spot입니다. 폭이 좁은 leaf는 무시해도 됩니다.

해부도로 정리하면 hot leaf와 무시할 좁은 bar의 차이가 분명해집니다.

Flamegraph 해부 — x축 sample 비율, y축 call depth, hot leaf 강조

#Off-CPU Flamegraph

일반 flamegraph는 on-CPU 시간만 보여 줍니다. 즉 sleep, I/O 대기, lock 대기 같은 blocked 시간은 빠집니다. 100ms 응답 시간 중 99ms를 I/O로 대기하면 on-CPU flamegraph는 1ms 영역만 보여 줍니다.

Off-CPU flamegraph는 sched_switch tracepoint로 task가 CPU를 떠나는 순간 stack을 기록합니다.

Terminal window
# BCC offcputime
offcputime-bpfcc -df 30 > out.stacks
flamegraph.pl --color=io --title="Off-CPU Time" < out.stacks > offcpu.svg
# 또는 perf로
perf record -e sched:sched_switch -g --call-graph dwarf -- sleep 30
perf script | ./stackcollapse-perf.pl > out.folded
flamegraph.pl --color=io < out.folded > offcpu.svg

I/O 대기와 mutex contention이 우측에 큰 면적으로 나타납니다.

#On-CPU와 Off-CPU 함께 보기

응답 시간 = on-CPU + off-CPU

두 flamegraph를 나란히 두고 보면 병목의 정체가 드러납니다.

패턴의미
on-CPU가 크고 off-CPU가 작음CPU bound, 알고리즘 최적화
off-CPU가 크고 on-CPU가 작음I/O 또는 lock bound
둘 다 큼시간 사용이 분산, 단계별 진단
둘 다 작음응답 시간이 다른 곳에서 발생 (network round-trip 등)

#차분 Flamegraph — Before/After 비교

성능 개선 전후를 비교할 때 차분 flamegraph가 유용합니다.

Terminal window
# before 측정
perf record -F 99 -g -- ./app-old
perf script | ./stackcollapse-perf.pl > before.folded
# after 측정
perf record -F 99 -g -- ./app-new
perf script | ./stackcollapse-perf.pl > after.folded
# 차분 flamegraph
./difffolded.pl before.folded after.folded | ./flamegraph.pl > diff.svg

빨간색은 after에서 증가한 부분, 파란색은 감소한 부분입니다. 의도한 함수만 파랗게 변했는지, 다른 곳에 회귀가 생겼는지 한눈에 확인할 수 있습니다.

#Icicle Graph — 거꾸로

기본 flamegraph는 bottom-up으로 leaf가 위쪽입니다. Icicle graph는 top-down으로 root가 위쪽입니다.

Terminal window
flamegraph.pl --reverse < out.folded > icicle.svg
flamegraph.pl --inverted < out.folded > inverted.svg

--reverse는 함수 순서를 뒤집어 leaf부터 보여 줍니다. 어떤 leaf 함수가 여러 path에서 호출되는지 확인할 때 유용합니다.

#색상 옵션

Terminal window
flamegraph.pl --color=hot < out.folded > hot.svg # 기본 (warm)
flamegraph.pl --color=mem < out.folded > mem.svg # 초록 계열
flamegraph.pl --color=io < out.folded > io.svg # off-CPU용
flamegraph.pl --color=java < out.folded > java.svg # Java JIT 구분
flamegraph.pl --color=wakeup < out.folded > wake.svg # wakeup analysis

--color=java는 JIT 컴파일된 메서드와 native, GC를 다른 색으로 구분해 줍니다.

#시나리오 — 웹 서비스 응답 시간 분석

Terminal window
# 1. on-CPU 30초
perf record -F 99 -g -p <pid> -- sleep 30
perf script | ./stackcollapse-perf.pl > on.folded
./flamegraph.pl on.folded > on.svg
# 2. off-CPU 30초
offcputime-bpfcc -df -p <pid> 30 > off.folded
./flamegraph.pl --color=io off.folded > off.svg
# 3. 두 SVG를 같이 열고 비교

대부분의 web service는 off-CPU가 80% 이상이며, on-CPU는 JSON 직렬화나 암호화에 집중됩니다.

#자주 보는 함정과 안티패턴

⚠️ Frame pointer 누락

Terminal window
gcc -O2 app.c # -fno-omit-frame-pointer 없음
perf record -g --call-graph fp ./app # → stack 깨짐, flame이 짧고 평평

-fno-omit-frame-pointer로 컴파일하거나 --call-graph dwarf를 사용합니다.

⚠️ Sampling rate가 너무 낮음

Terminal window
perf record -F 9 ./app # 9 Hz → 30초에 270 sample

Sample이 적으면 통계가 부정확합니다. 99 Hz 또는 999 Hz가 표준입니다. 99 Hz는 다른 주기적 작업과 alias가 발생하지 않도록 prime number를 쓰는 관행입니다.

⚠️ On-CPU만 보고 I/O 무시

on-CPU flame이 비어 있음 → "최적화할 곳 없음"으로 결론

응답 시간이 길지만 on-CPU가 비어 있으면 거의 항상 off-CPU에 답이 있습니다.

⚠️ 너무 짧은 측정 시간

Terminal window
perf record -F 99 ./app # 0.1초만 실행

수집 시간이 짧으면 잡음에 묻힙니다. 최소 5초, 가능하면 30초 이상을 기록합니다.

#정리

  • Flamegraph는 collapsed stack format을 SVG로 시각화한 표준 도구입니다.
  • 폭이 hot의 비율을, 높이가 호출 깊이를 나타내며 색상과 정렬은 의미가 없습니다.
  • On-CPU flamegraph는 CPU 시간을, off-CPU flamegraph는 blocked 시간을 보여 줍니다.
  • 차분 flamegraph로 before/after 회귀를 시각적으로 확인합니다.
  • Frame pointer가 없으면 stack이 깨지므로 컴파일 옵션 또는 DWARF를 사용합니다.
  • 99 Hz, 30초 이상이 표준 sampling 설정입니다.

다음 편은 ARM DS / Lauterbach — 임베디드 전용 hardware trace 도구.

#관련 항목

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