성능 데이터 통계적 분석 — Percentile·Histogram·평균의 함정
#한 줄 요약
**“평균은 거짓말”**입니다. Latency 분포는 long tail을 가지므로, p99와 max가 진실에 가깝습니다.
#평균의 함정
Latency 측정 100회:99회: 10 ms 1회: 1000 ms
Average: (99 × 10 + 1 × 1000) / 100 = 19.9 msMedian (p50): 10 msMax: 1000 ms평균 20 ms만 보고 OK라고 판단하면, 1% 사용자가 1초를 기다린다는 사실을 놓칩니다. Real-time 시스템이라면 곧바로 fail입니다.
#Percentile — 분포의 점
| Percentile | 의미 |
|---|---|
| p50 (median) | 절반이 더 빠름 |
| p90 | 10% 더 느림 |
| p99 | 1% 더 느림 — user experience의 표준 |
| p999 | 0.1% — 1000 req 중 1 |
| p9999 | 0.01% |
| max | worst-case |
Web service는 p99를 보장합니다. Real-time system은 max를 보장합니다.
#Histogram
분포를 시각화합니다. bucket 개수 × 카운트 형태로 표현합니다.
< 1 ms: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ (140)1-2 ms: ▓▓▓▓▓▓▓▓ (80)2-5 ms: ▓▓ (20)5-10 ms: ▓ (10)10-50 ms: ▓ (5)> 50 ms: ▓ (3) ← long tail평균은 보이지 않지만 분포는 눈으로 즉시 식별할 수 있습니다. Mode, skew, outlier가 모두 한눈에 들어옵니다.
#HdrHistogram — 정밀 분포
HdrHistogram은 Gil Tene이 Azul Systems에서 만든 도구입니다. Logarithmic bucket과 configurable precision을 제공합니다.
#include "hdr_histogram.h"
struct hdr_histogram *h;hdr_init(1, 60 * 1000 * 1000, 3, &h); // 1µs~60s, 3 significant digits
hdr_record_value(h, latency_us);
// 결과int64_t p99 = hdr_value_at_percentile(h, 99.0);int64_t p999 = hdr_value_at_percentile(h, 99.9);int64_t max = hdr_max(h);1 µs~60 s 범위에 3 자리 정밀도를 가지면서, 메모리는 수십 KB만 씁니다. Web과 database benchmark의 표준입니다.
#임베디드 — Fixed-Bucket Histogram
HdrHistogram이 너무 크면 고정 64-128 bucket log2 분포를 쓰면 됩니다.
#define BUCKETS 64static uint32_t hist[BUCKETS];
void record(uint32_t us) { int idx; if (us == 0) idx = 0; else if (us >= (1u << (BUCKETS - 1))) idx = BUCKETS - 1; else idx = 32 - __clz(us); hist[idx]++;}
void print(void) { for (int i = 0; i < BUCKETS; i++) if (hist[i]) printf("%d-%d us: %u\n", 1<<i, (1<<(i+1))-1, hist[i]);}64 bucket × 4 byte = 256 byte입니다. 임베디드에서도 충분합니다. p99와 max는 bucket을 누적해서 계산합니다.
#통계 지표 — 본질
| 지표 | 공식 | 의미 |
|---|---|---|
| Mean | 평균 — outlier에 민감 | |
| Median | 50th percentile — robust | |
| Mode | 가장 빈번 값 | 일상적 값 |
| Variance | 분산 | |
| Stdev | 표준편차 | |
| Min, Max | — | 극단값 |
Real-time에서는 max에 신경 써야 합니다. Mean과 stdev는 정규분포를 가정하지만, latency는 비대칭 long-tail이라 적합하지 않습니다.
#Outlier — 무시할까 분석할까
99회: 10 ms (정상) 1회: 1000 ms (outlier)1초 outlier의 원인이 cache miss나 context switch라면, 이는 시스템 자체의 특성입니다. random noise가 아니라 systematic인 현상입니다.
그래서 outlier 분석이야말로 핵심 가치입니다. 평균만 보면 해결해야 할 진짜 문제를 못 봅니다.
#Coordinated Omission
Gil Tene의 유명한 글입니다. Load generator가 측정 도중 멈추면 measurement 자체가 누락됩니다.
시스템이 1초 freeze:
- 그 동안 도착할 요청들이 측정 누락
- 측정 latency는 얼토당토 적게
- 실제 user latency는 훨씬 더 큼
해결책은 coordinated omission correction입니다. HdrHistogram에 내장 지원이 있습니다.
#Long Tail 원인 분류
| 원인 | 시그니처 |
|---|---|
| Cache miss | µs-단위 spike, 주기 X |
| GC pause (Java/Go) | 수십 ms 정기 |
| Context switch | µs-수십 µs, IRQ/scheduler |
| Bus contention | 시스템 부하 중 |
| TLB miss (Cortex-A) | process switch 시 |
| DMA contention | 데이터 전송 중 |
| Thermal throttle | 고온 도달 시 |
각 원인은 다른 분포 패턴을 보입니다. histogram으로 시그니처를 식별할 수 있습니다.
#Sample Size
N=10: 잡음 큼, 결론 XN=100: 대략적 분포N=1000: 신뢰할 만N=10000: 정밀N=100000+: production gradep99를 신뢰하려면 최소 N=1000 이상이 필요합니다(1% 케이스를 추정해야 하기 때문입니다).
#Box Plot
5-number summary를 시각화합니다. 여러 측정을 비교할 때 좋습니다.
#Latency vs Sustained Load
for (load = 10%; load <= 100%; load += 10%) { run_with_load(load); measure_p99(load);}Latency curve의 knee 지점이 capacity 한계입니다. 보통 80% 근처입니다.
#자주 하는 실수
⚠️ 평균만 보고 결정
위에서 본 것처럼 p99와 max가 필수입니다.
⚠️ N 너무 적음
10개 sample로 p99를 추정하면 noise만 남습니다. 최소 1000개가 필요합니다.
⚠️ Histogram bucket 너무 적거나 많음
10 bucket이면 정밀도가 부족하고, 1000 bucket이면 메모리가 과합니다. log2 기반 64-128이 sweet spot입니다.
⚠️ Stationarity 가정
시스템 부하가 변동하는 동안에는 전구간 평균이 의미가 없습니다. 시간대별로 분리해서 봅니다.
#정리
- 평균은 사용자 경험과 다릅니다. p99·p999·max가 진실에 가깝습니다.
- Histogram과 percentile이 분포 분석의 정석입니다.
- HdrHistogram은 web과 DB의 표준이며, 임베디드에서는 log2 64-bucket으로도 충분합니다.
- Coordinated omission이 흔한 측정 함정입니다.
- Long tail의 원인은 cache, context switch, bus contention, GC 등입니다.
다음 편은 실시간 성능 분석입니다. WCET와 jitter, deadline miss를 다룹니다.
#관련 항목
Embedded Performance Engineering · 5 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 처리량 회복
관련 글
실전 사례 — 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 통계.
CXL.mem 지연·대역폭 실측 — Direct·Switch·Pooled 토폴로지 비교
CXL.mem 토폴로지별 실측 — Direct attach·Single switch·Multi-host pool의 지연·대역폭 비용 측정.