성능 데이터 통계적 분석 — 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
- 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 처리량 회복
관련 글
실전 사례 — 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의 지연·대역폭 비용 측정.
같은 시리즈에서 이어 읽기