Stage1 스크립트는 총 11개 블록(0~10)으로 구성되어 있습니다. 순서대로 자세히 설명드리고, 지금 겪고 계신 gpu_burn DIED 이슈와 어떻게 연결되는지도 같이 짚어드리겠습니다.
sudo nvidia-smi -pm 1
systemctl status nvidia-fabricmanager
-pm 1)하고, NVSwitch 8-GPU 구성이면 GPU 간 라우팅을 관리하는 nv-fabricmanager 서비스가 살아있는지 확인.nvidia-smi --query-gpu=index,name,uuid,driver_version,pstate,...
DIED가 전 GPU에서 동시에 뜬다면, 이 단계에서 드라이버 버전을 먼저 적어두세요. B300급이면 R570 이상 최신 드라이버가 필요한데, 구버전이면 gpu-burn 커널 자체가 못 돌아갑니다.lspci -vvv | grep -E "NVIDIA|LnkCap|LnkSta"
nvidia-smi --query-gpu=...pcie.link.gen.max,pcie.link.gen.current...
nvidia-smi topo -m
nvidia-smi nvlink -s
nvidia-smi nvlink -e
topo -m은 GPU 간 연결이 NVLink(NV#)인지 PCIe 경유(PHB/SYS)인지 매트릭스로 보여주고, nvlink -s는 각 링크의 Active 상태, nvlink -e는 CRC/Replay 에러 카운터를 봅니다.nvidia-smi --query-gpu=...ecc.errors.corrected...ecc.errors.uncorrected...
dmesg -T | grep -i xid
nvidia-smi -q -d ROW_REMAPPER
nvidia-smi -q | grep -A5 "Pending Page Retirement"
gpu_burn 실행 시점에 dmesg -T를 다시 떠서 여기(5번)와 비교하면 Xid가 새로 찍혔는지(하드웨어) vs Xid 없이 그냥 DIED만 뜨는지(소프트웨어/커널 미지원) 를 구분할 수 있는 핵심 체크포인트입니다.dcgmi diag -r 3
dcgmi diag -r 4 # 지원되면
--help 체크 후 폴백합니다.all_reduce_perf -b 8M -e 4G -f 2 -g 8
nvidia-smi nvlink -s는 "링크가 떠 있다"만 보여주지 "실제로 빠른지"는 안 보여줍니다. 이 단계가 진짜 성능 검증입니다.python3 fp8_fp4_stress.py 180
torch._scaled_mm(FP8 GEMM)을 각 GPU에서 반복 실행해 텐서코어 자체를 부하.nvidia-smi --query-gpu=...temperature.gpu,power.draw,clocks...,clocks_throttle_reasons.active --format=csv -l 1 & # 백그라운드 모니터링
gpu_burn ${SOAK_SECONDS}
DIED가 난다면, 앞서 안내드린 gpu-burn Makefile의 -gencode(compute capability) 문제일 가능성이 매우 높아집니다.grep -v "0x0000000000000000" 09_thermal_power_trace.csv # 쓰로틀 플래그 감지
dmesg -T | grep -i xid # XID 신규 발생 여부
nvidia-smi -q -d ROW_REMAPPER # Row-remap 신규 여부
diff 05_xid_before.txt 10_xid_after.txt # 테스트 전후 비교
정리하면: 지금 막히신 문제를 좁히려면 8번(FP8 스트레스)을 gpu_burn(9번)보다 먼저 단독 실행해보시는 게 가장 빠른 진단 경로입니다. 8번이 정상 동작하면 문제는 gpu-burn 빌드(gencode)로 좁혀지고, 8번도 실패하면 CUDA/드라이버 환경 문제로 좁혀집니다.
==
Stage2는 크게 4개 섹션(A: 네트워크, B: MinIO S3, C: 로컬 NVMe, D: 요약)으로 나뉩니다. 순서대로 설명드립니다.
A0. 로컬 NVMe 구성 확인
lsblk -d -o NAME,SIZE,MODEL
nvme list
LOCAL_CACHE_DIR이 실제로 몇 장짜리 어레이를 가리키는지 먼저 확인하는 단계입니다.A1. ConnectX-6 NIC 물리 링크 및 NUMA 매핑
ip route get ${STORAGE_NODE_IP} # 스토리지 노드로 가는 인터페이스 자동 탐지
ethtool <NIC> # Speed/Duplex/Link 상태
cat /sys/class/net/<NIC>/device/numa_node
lspci -tvnn | grep -E "Mellanox|NVIDIA"
A2. 단일 vs 멀티 스트림 iperf3
iperf3 -c <IP> -p 5201 -t 10 # 단일 스트림
iperf3 -c <IP> -p 5201 -P 8 -t 15 # 8개 동시 스트림
A3. 양방향(Bi-directional) 테스트
iperf3 -c <IP> -p 5201 --bidir -P 8 -t 15
A4. 광모듈 DDM / FEC / PHY 에러
ethtool -m <NIC> # 광모듈 수신광 파워, 온도 (DDM)
ethtool -S <NIC> | grep rx_crc_errors, fec_corrected/uncorrectable_blocks, rx_discards_phy 등
B1. Warp 벤치마크
warp mixed --obj.size=64MiB --concurrent=16 --duration=30s --get-distrib 80 --stat-distrib 10 --put-distrib 10
C1. SMART 상태 (테스트 전)
NVME_DEV=$(df ${LOCAL_CACHE_DIR} | ... | sed 's/p?[0-9]+$//') # 마운트 경로 → 실제 nvme 디바이스명 역추적
nvme smart-log <device>
C2. 200GB 연속 순차 쓰기 (백그라운드 온도 모니터링 포함)
( while true; do nvme smart-log ... | awk '/temperature/...'; sleep 1; done ) & # 1초 주기 온도 로깅
fio --rw=write --bs=2M --size=200G --numjobs=1 --runtime=180
C3. 고부하 순차 읽기
fio --rw=read --bs=2M --size=100G --numjobs=4 --runtime=60
C4. SMART 상태 (테스트 후) + Media Errors 판정
nvme smart-log <device>
awk '/media_errors/ {print $3}'
media_errors가 0이 아니게 바뀌었으면, 이 정도 부하만으로도 낸드 불량이 드러난 것 — 신품 디스크치고는 심각한 징후라 즉시 교체 대상입니다.모든 수치(NIC 속도/단일·멀티 스트림/S3 처리량/NVMe 쓰기·읽기/Media Errors)를 stage2_summary.txt 하나로 모아 tee — 이게 보고서에 바로 붙여넣을 수 있는 최종 산출물입니다.
참고: Stage2는 Stage1과 달리 gpu-burn 같은 GPU 커널 실행에 의존하지 않으므로, 지금 겪고 계신 gpu-burn 이슈와는 독립적으로 먼저 돌려보셔도 무방합니다. 다만 A2/B1은 스토리지 노드 쪽에 iperf3 -s -D가 미리 떠 있어야 하고, STORAGE_NODE_IP/MINIO_ENDPOINT 등 환경변수를 실제 값으로 바꿔야 동작합니다.
==
Stage3는 4개 스크립트로 구성됩니다 — 3a(vLLM), 3b(Triton+TRT-LLM)+보조러너, 3c(SGLang, 선택), 3d(AIPerf 통합, 신규). 각각 자세히 설명드립니다.
공통 함수 구조
start_vllm_server(model_id, quant_flag, prefix_cache): vLLM API 서버를 백그라운드로 띄우고, /v1/models 엔드포인트가 응답할 때까지 5초 간격으로 폴링. 서버 프로세스가 죽으면(kill -0 실패) 즉시 에러로 중단.stop_vllm_server(): SIGTERM으로 정상 종료 후 wait.run_serving_bench(tag, in_len, out_len, concurrency, num_prompts): vLLM 공식 benchmark_serving 모듈로 실제 트래픽을 흉내 낸 요청을 보내고 결과를 JSON으로 저장.이 구조를 5가지 시나리오에 반복 적용합니다.
시나리오 1) Dense 70B, BF16, Short(1k)/Long(32k) Context
TP_SIZE=8로 8장 전체를 텐서 병렬로 묶고, concurrency 1/16/64(단기)·1/8/16(장문)으로 스윕.시나리오 2) Dense 70B, FP8 양자화
--quantization fp8 플래그만 추가해 동일 시나리오 재실행.시나리오 3) Prefix Caching 검증
--enable-prefix-caching 켠 상태에서 --random-prefix-len 32000(32k 프리픽스 고정) + 짧은 출력(256) 요청을 8동시성으로 30개 반복.시나리오 4) DeepSeek-R1 (대형 MoE, FP8)
시나리오 5) 소형 8B 모델
결과 집계
${LOG_DIR} 안의 모든 결과 JSON을 훑어서 TTFT/ITL/Req·s/Tok·s를 표로 정리한 vllm_report.md를 생성합니다.이 스크립트는 엔진 빌드 전용이고, 실제 부하 측정은 별도 파일(stage3b_genai_perf_runner.sh)에서 합니다.
1) BF16 엔진 빌드
convert_checkpoint.py --dtype bfloat16 --tp_size 8 # HF 가중치 → TRT-LLM 체크포인트 변환
trtllm-build ... --use_paged_context_fmha enable # 실제 실행 가능한 엔진 바이너리로 컴파일
2) FP8 엔진 빌드 (신규)
quantize.py --qformat fp8 --kv_cache_dtype fp8 # 가중치뿐 아니라 KV캐시도 FP8로
trtllm-build ... --use_fp8_context_fmha enable
보조 스크립트 stage3b_genai_perf_runner.sh
./stage3b_genai_perf_runner.sh ensemble_bf16 # 또는 ensemble_fp8
genai-perf 도구로 Short(1k)/Long(32k) Context를 concurrency 1/16/64, 1/8/16으로 스윕.vLLM/Triton과 거의 동일한 골격(서버 기동 → 폴링 → 부하 → 종료)이지만 3가지 차이가 있습니다.
시나리오 1-2) Dense 70B + 프리픽스 재사용
시나리오 3) FP4 MoE (GPT-OSS-120B)
--quantization fp4로 기동. Blackwell의 FP4 텐서코어는 SGLang 커널이 vLLM보다 먼저/더 최적화되어 있다고 알려져 있어, 이 시나리오가 비교의 핵심입니다.주의: 이 단계는 "MoE/에이전트/RAG 서빙 계획이 실제로 있을 때만" 돌리는 선택 사항으로 설계했습니다. 순수 챗봇형 워크로드뿐이면 3a/3b만으로 충분합니다.
3a/3b/3c는 엔진마다 서로 다른 측정 도구(vLLM benchmark_serving, Triton genai-perf, SGLang bench_serving)를 써서, 메트릭 계산 방식이 미묘하게 다를 수 있다는 한계가 있습니다. 3d는 이미 기동된 세 엔진에 동일한 도구(NVIDIA AIPerf)로 동일 조건을 재적용해서 apples-to-apples 비교를 만드는 단계입니다.
run_aiperf_openai(): vLLM(8000)/SGLang(30000)처럼 OpenAI 호환 API를 쓰는 엔진 대상.run_aiperf_triton(): Triton은 OpenAI 호환이 아니라 네이티브 gRPC 프로토콜을 쓰므로 --service-kind triton --backend tensorrtllm으로 별도 처리.--public-dataset sharegpt로 실제 대화 데이터셋을 쓰고, --request-rate 8.0으로 균일 동시성이 아니라 푸아송 분포의 "실제 트래픽처럼 들쭉날쭉한" 요청 패턴을 흉내 냅니다. 3a~3c의 고정 concurrency 테스트가 "최대 성능 한계"를 본다면, 이 단계는 "운영 중 실제로 체감할 지연"에 더 가깝습니다.실행 순서 요약: 3a → 3b(빌드) → genai_perf_runner(bf16) → genai_perf_runner(fp8) → (선택) 3c → 3d. 3d는 3a/3b/3c 중 기동해둔 엔진이 있어야 의미가 있으므로 항상 가장 마지막에 돌리는 걸 권장합니다.