실전 사례 — CXL.mem 추가로 LLM inference KV cache 처리량 회복
#한 줄 요약
“H100 96 GB 5장(총 HBM 480 GB)으로 LLaMA 70B inference를 돌리던 노드가 batch 96 이상에서 throughput이 무너졌습니다.” — 원인은 KV cache가 HBM 용량을 초과해 PCIe DMA swap thrashing. 해결은 Astera Leo 계열 CXL.mem pool 추가 + cold KV block을 CXL.mem에 자동 배치. 결과는 batch 96에서 throughput ~92% 회복, batch 128 확장 가능. 본 사례의 수치는 현장 관측을 일반화한 시나리오입니다.
#배경
운영 환경 (현장 일반화):
| 항목 | 값 |
|---|---|
| GPU | 5x NVIDIA H100 96 GB SXM5 |
| HBM 총량 | 480 GB (96 GB × 5) |
| CPU | 2 socket Xeon SPR/EMR 세대 |
| 호스트 RAM | 1 TB DDR5 |
| 모델 | LLaMA 70B (FP16) |
| 추론 엔진 | vLLM 계열 (tiered KV 지원 빌드) |
| 정상 동작 | batch 64, throughput ~240 tokens/sec/server |
#증상
운영 중 batch 96 이상으로 부하 증가 시:
| Batch | Throughput | 변화 |
|---|---|---|
| 32 | 130 tokens/sec | baseline |
| 64 | 240 tokens/sec | 정상 |
| 96 | 80 tokens/sec | 추락 |
| 128 | OOM | 못 돌림 |
batch 96에서 throughput이 1/3로 떨어짐. 비정상.
#진단
#1. GPU 메모리 사용량 확인
$ watch -n 1 nvidia-smi# batch 96 동안
| GPU Name | Mem Used / Total || 0 H100 | 92450 MiB / 96000 MiB || 1 H100 | 92312 MiB / 96000 MiB || 2 H100 | 92478 MiB / 96000 MiB || 3 H100 | 92501 MiB / 96000 MiB || 4 H100 | 92388 MiB / 96000 MiB |총 462 GB / 480 GB 사용 — HBM 거의 가득.
#2. CUDA profiler 분석
$ nsys profile --gpu-metrics-device=all ./vllm-serverNsight Systems에서 본 프레임당 시간 분해:
| 단계 | 정상 (batch 64) | 비정상 (batch 96) |
|---|---|---|
| Attention compute | 8 ms | 9 ms |
| FFN compute | 12 ms | 13 ms |
| KV cache load/swap | 2 ms | 180 ms |
| Token generation | 1 ms | 1 ms |
KV cache load가 90배 증가. 원인: HBM 부족분을 PCIe DMA로 Host RAM과 swap.
#3. Roofline 분석
Ch 16(메모리 대역폭 분석) Roofline plot 결과:
- 정상: memory-bound 영역의 상한선 근처 (HBM 8 TB/s 활용)
- 비정상: memory-bound 영역의 훨씬 아래 (PCIe 64 GB/s에 발목 잡힘)
- Compute 활용률 23% — GPU가 놀고 있는 상태
#원인
HBM·GDDR 심화 Ch 8에서 본 LLaMA 70B 메모리 분해:
| 항목 | batch 64 | batch 96 | batch 128 |
|---|---|---|---|
| Weight (정적) | 140 GB | 140 GB | 140 GB |
| Activation | 12 GB | 18 GB | 24 GB |
| KV cache | 320 GB | 480 GB | 640 GB |
| 총 | 472 GB | 638 GB | 804 GB |
HBM 총용량 480 GB. batch 64는 간신히 들어가고, batch 96은 158 GB 초과. 초과분이 PCIe로 host RAM과 swap.
PCIe 5.0 x16 양방향 64 GB/s로 수백 GB 데이터를 매 프레임 swap하니 throughput이 무너집니다.
#해결
#1. 하드웨어 추가
서버에 Astera Labs Leo CXL.mem 카드 2장 추가:
| 항목 | 값 |
|---|---|
| 카드 | Astera Labs Leo CXL Memory |
| 용량 | 2 TB DRAM (DDR5 기반) |
| 인터페이스 | PCIe 5.0 x16, CXL 2.0 |
| 카드 수 | 2장 |
| 총 CXL.mem | 4 TB |
| 측정 지연 | 215 ns (Direct attach) |
| 측정 대역폭 | 56 GB/s/카드 (sequential) |
#2. 추론 엔진 측 설정 (개념적)
vLLM 계열 추론 엔진에서 KV cache를 HBM·CXL.mem에 분산 배치하는 설정 (실제 schema는 fork·버전에 따라 다름, 아래는 개념 표현):
# 개념적 예시 — 실 schema는 사용 엔진의 docs 참조kv_cache: storage_tiers: - device: cuda # HBM (hot tier) capacity: "70%" role: hot - device: numa:2,3 # CXL.mem nodes (warm tier) capacity: "100%" role: warm promotion_policy: type: lru window_size: 128 # 최근 128 token 이내 hot block_size: 16 # token 단위핵심 아이디어: recent token KV는 HBM, old token KV는 CXL.mem. LRU 기반 promotion·demotion. 어느 vLLM fork·patch가 이를 native 지원하는지는 해당 프로젝트의 release note를 확인.
#3. Linux Tiered Memory 설정
# DAMON 활성화 (자동 promotion/demotion 보조)$ echo on > /sys/kernel/mm/damon/admin/kdamonds/0/state
# NUMA balancing 활성$ echo 1 > /proc/sys/kernel/numa_balancing
# CXL 노드를 movable zone으로 노출$ daxctl reconfigure-device dax2.0 -m system-ram$ daxctl reconfigure-device dax3.0 -m system-ram#결과
해결 후 측정:
| Batch | Throughput | p99 latency | HBM 사용 | CXL 사용 |
|---|---|---|---|---|
| 32 | 130 tok/s | 45 ms | 220 GB | 0 GB |
| 64 | 240 tok/s | 52 ms | 380 GB | 80 GB |
| 96 | 220 tok/s | 68 ms | 420 GB | 240 GB |
| 128 | 280 tok/s | 94 ms | 440 GB | 400 GB |
- batch 96에서 throughput 220 tok/s 회복 (해결 전 80 → 220, 275% 향상)
- batch 128까지 확장 가능 (해결 전 OOM)
- p99 latency 25% 증가하지만 throughput 우선 워크로드에는 OK
#DAMON로 본 access 분포
Ch 55에서 본 DAMON 출력:
| Region | Access % | 위치 | 의미 |
|---|---|---|---|
| recent 128 token KV | 92% | HBM | hot |
| 128~512 token KV | 18% | HBM → CXL 점진 demotion | warm |
| 512+ token KV | 2% | CXL | cold |
| Weight | 100% | HBM (절대 안 옮김) | static |
recent token이 HBM에 머무름과 old token이 CXL로 demotion의 패턴이 자동으로 형성됨.
#재발 방지
운영에 추가한 모니터링:
| 지표 | 임계 | 대응 |
|---|---|---|
| HBM 사용률 | >90% 5분 지속 | 자동 batch size 감소 |
| KV cache PCIe swap rate | >10 GB/s 1분 | alert + investigation |
| CXL.mem 사용률 | >80% | 카드 추가 검토 |
| DAMON false promotion rate | >20% | window_size 튜닝 |
| CXL p99 latency | >400 ns | 디바이스 health 확인 |
이 5가지 지표를 Prometheus에 노출해 Grafana 대시보드로 본부 운영팀이 추적.
#자주 보는 함정과 안티패턴
⚠️ “GPU만 빠르면 LLM inference 빨라진다”
틀렸습니다. KV cache가 memory-bound 작업의 핵심. GPU compute가 남아돌아도 메모리가 병목이면 throughput이 안 올라갑니다. 메모리 용량·대역폭이 GPU compute만큼 중요.
⚠️ “CXL.mem 추가 = throughput 무조건 향상”
조건부입니다. memory-bound 워크로드에만 효과. compute-bound 워크로드는 CXL이 영향 없음. Roofline 분석으로 어느 영역인지 먼저 확인.
⚠️ Manual KV cache placement에 집착
DAMON 같은 자동 tiering이 manual placement보다 일반적으로 우수. application이 모든 KV block의 hotness를 정확히 알기 어렵습니다. 자동 메커니즘에 맡기고 monitoring이 권장.
⚠️ Tier 추가 후 batch size 같은 그대로
확장의 여지가 생겼는데 batch 64 그대로 두면 추가 비용만 발생. CXL 도입 후에는 workload 재튜닝이 반드시 필요합니다.
#정리
- LLaMA 70B inference가 batch 96 이상에서 throughput이 무너진 사례. 원인은 KV cache의 HBM 초과 + PCIe swap thrashing.
- 해결은 Astera Leo CXL.mem 4 TB 추가 + vLLM의 tiered KV cache + Linux DAMON 자동 promotion.
- 결과: batch 96 throughput 92% 회복, batch 128까지 확장 가능, p99 latency 25% 증가는 throughput 우선 워크로드 수용 가능.
- 핵심 lesson: HBM은 대역폭 우위, CXL.mem은 용량 우위. 상보적 활용이 memory-bound 워크로드의 정답.
- 재발 방지는 5가지 지표(HBM 사용률, PCIe swap rate, CXL 사용률, false promotion, CXL latency) 상시 모니터링.
다음 편은 Embedded Performance Engineering 시리즈의 마무리 영역으로 들어갑니다. CXL 관련 다음 깊이는 Embedded Security Ch 11~13의 보안 측면, Memory Diagnostics Ch 6~7의 진단 측면으로 이어집니다.
#관련 항목
Embedded Performance Engineering · 57 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 성능 프로파일링 도구 — 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의 지연·대역폭 비용 측정.
실전 사례 — 카메라 1080p 60fps가 30fps로 떨어지는 이유
Cortex-A 보드의 카메라 캡처가 frame drop. CPU는 한가했고 진짜 범인은 DMA burst size와 AXI bus 효율이었다.