수정했습니다. 기존 소스 구조는 최대한 유지하면서 warm-up을 측정 구간과 분리했고, bash -n 구문 검사도 전체 통과했습니다.
핵심 변경은 stage3a_warmup_lib.sh를 공통 helper로 추가해 기본값을 engine warm-up 20건 + workload별 실제 concurrency warm-up + 3초 안정화 후 본 측정으로 통일한 것입니다. 3a2에는 없던 warm-up을 추가했고, 3a3는 isolated/mixed 각각 workload warm-up, 3a7은 TP=1/2/4/8 서버 재기동마다 다시 warm-up, 3a6은 concurrency 단계별 warm-up을 적용했습니다.
특수 케이스도 따로 처리했습니다. 3a4 Soak은 최초 10분(SOAK_WARMUP_SEC=600)을 기록은 하되 drift 계산에서 제외하도록 했고, 3a8 Prefix Cache A/B와 기본 3a의 prefix-cache 시나리오는 동일 32K prefix로 workload warm-up하지 않도록 했습니다. 즉 짧은 랜덤 요청으로 엔진만 데운 뒤 첫 32K prefix 요청은 cold 상태를 유지합니다.
이번에 수정한 것은 현재 범위에 해당하는 stage3a, 3a2, 3a3, 3a4, 3a6, 3a7, 3a8, 3a9입니다. 앞서 제외하기로 한 품질평가 3a5와 KV-tier 3a10은 수정하지 않았습니다.
stage3a_warmup_v2.tar.gz수정본 전체 다운로드 (tar.gz)
stage3a_warmup_lib.sh공통 warm-up helper · stage3a_vllm_benchmark.shStage3a 기본 · stage3a2_vllm_config_sweep.shStage3a2 · stage3a3_vllm_mixed_workload.shStage3a3 · stage3a4_vllm_soak_test.shStage3a4 · stage3a6_vllm_saturation_test.shStage3a6 · stage3a7_vllm_tp_scaling.shStage3a7 · stage3a8_vllm_prefix_cache_ab.shStage3a8 · stage3a9_vllm_rag_realistic.shStage3a9
실행할 때는 같은 디렉터리에 stage3a_warmup_lib.sh가 있어야 합니다. 기본값은 환경변수로 조정할 수 있게 해두었습니다: ENGINE_WARMUP_REQUESTS=20, LOAD_WARMUP_MIN_REQUESTS=20, LOAD_WARMUP_MULTIPLIER=2, POST_WARMUP_SLEEP_SEC=3, 그리고 Soak은 SOAK_WARMUP_SEC=600입니다.
다음으로는 Stage6a NCCL과 K8s vLLM 검증에도 동일한 “readiness ≠ performance-ready” 규칙을 적용해서, bare-metal Stage3 결과와 K8s 결과를 공정하게 비교할 수 있도록 수정하는 게 좋습니다.
네. stage3a_summary_report.py도 수정하는 편이 맞아서, 앞서 정한 warm-up 분리 + 인수검증 중심 리포트에 맞춰 수정했습니다.
:chatgpt-content-reference{index="0"}수정된 stage3a_summary_report.py
주요 변경점은 다음과 같습니다.
5x 이상 정상, 20% 이하면 양호 같은 휴리스틱 자동 판정을 줄이고 측정값/관찰값 중심으로 바꿨습니다.70B BF16 short c64, 70B BF16 long c8의 TTFT / ITL / Output TPS를 보여줍니다.isolated → mixed TTFT 변화량을 그대로 표시합니다.none 기준 saturation 결과를 읽을 수 있게 했습니다.TPS/GPU를 같이 표시합니다.Acceptance review를 만들어 기능/안정성 확인과 성능 characterization을 분리했습니다.리포트 상단에는 이번에 적용한 warm-up protocol도 자동 기록됩니다.
Readiness
↓
Engine warm-up (default 20)
↓
Workload-specific load warm-up
max(20, concurrency × 2)
↓
3 sec stabilization
↓
========================
Steady-state measurement
========================
따라서 몇 달 뒤 결과만 보더라도 “이 수치가 cold-start가 포함된 값인지 steady-state 값인지” 헷갈리지 않게 했습니다.
실행은 기존과 거의 같습니다.
python3 stage3a_summary_report.py \
--base-dir /var/log/b300_validation
간략 보고서는:
python3 stage3a_summary_report.py \
--base-dir /var/log/b300_validation \
--brief
각 Stage의 원본 Markdown 리포트까지 하나의 파일에 포함하려면:
python3 stage3a_summary_report.py \
--base-dir /var/log/b300_validation \
--include-raw-reports
구문 검사(py_compile)와 결과가 없는 디렉터리를 대상으로 한 실행 테스트도 통과시켰습니다.
한 가지 더 개선하면 좋을 부분이 있습니다. 현재 warm-up helper는 warm-up을 측정에서 제외하는 데 초점이 있고, 실제로 cold TTFT → warm-up #1 → #5 → #10 → steady-state가 어떻게 수렴했는지는 파일에 남기지 않습니다. 앞서 이야기했던 최종 리포트 수준까지 가려면 다음 버전에서는 warmup_trace.csv를 남겨 warm-up 안정화 곡선까지 summary가 자동으로 그려주는 구조로 만드는 게 좋습니다. 그러면 B300 드라이버/CUDA/vLLM 버전 변경 전후의 cold-start 특성까지 회귀 비교할 수 있습니다.
좋습니다. 요청하신 구조로 수정했습니다. 실제 vLLM 없이 만든 샘플 warmup_trace.csv로 CSV 파싱 → 수렴 분석 → SVG 곡선 생성 → Markdown 삽입까지 테스트했습니다.
stage3a_warmup_trace_v3.tar.gz전체 수정본 다운로드
개별 파일은 stage3a_warmup_lib.shwarm-up 공통 helper와 stage3a_summary_report.py수정된 summary report입니다.
warmup_trace.csv각 Stage 실행 디렉터리에 자동 생성됩니다.
timestamp
phase # engine / load
tag # 어떤 workload인지
batch_index
batch_requests
cumulative_requests
input_len
output_len
concurrency
prefix_len
range_ratio
median_ttft_ms
p99_ttft_ms
median_itl_ms
output_throughput
request_throughput
completed
success
예를 들어 engine warm-up 20건은 기본적으로 5건씩 나눠:
5 requests → median TTFT 900 ms
10 requests → median TTFT 500 ms
15 requests → median TTFT 320 ms
20 requests → median TTFT 310 ms
처럼 수렴 과정이 남습니다.
자동으로 ## Warm-up convergence 섹션이 생기고:
server:
900.0 → 310.0 ms (-65.6%)
last-step<5%: 1/1
같은 진단 결과와 함께 그래프가 생성됩니다.
stage3a_ACCEPTANCE_SUMMARY_....md
stage3a_ACCEPTANCE_SUMMARY_...._assets/
├─ warmup_3a.svg
├─ warmup_3a2.svg
├─ warmup_3a3.svg
├─ warmup_3a4.svg
├─ warmup_3a6.svg
├─ warmup_3a7.svg
├─ warmup_3a8.svg
└─ warmup_3a9.svg
SVG 생성은 matplotlib 같은 추가 패키지에 의존하지 않아서 air-gap 환경에서도 Python 표준 라이브러리만 있으면 됩니다.
그리고 last-step<5%는 의도적으로 PASS/FAIL gate로 사용하지 않았습니다. 예를 들어 마지막 두 warm-up batch가 320 → 310 ms라면 안정화됐을 가능성이 높다는 진단 표시일 뿐입니다.
이 구조가 생겼기 때문에 다음 단계에서는 한 단계 더 발전시켜 고정 20회 warm-up 대신 “최소 10회 수행 후 최근 batch가 안정화되면 조기 종료, 안정화되지 않으면 최대 40~50회까지 자동 연장”하는 adaptive warm-up으로 바꿀 수 있습니다. B300/vLLM 조합에서는 이 방식이 고정 횟수보다 장기적으로 더 재현성 있는 baseline을 만드는 데 유리합니다.
수정했습니다. 이번 버전에서는 Stage6에서도 Stage3와 동일하게 Ready ≠ Performance Ready를 명시적으로 적용했습니다.
stage6_warmup_v1.tar.gzStage6 warm-up 수정본 전체
핵심은 두 스크립트입니다.
all_reduce_perf를 먼저 warm-up run으로 수행하고 그 결과는 버립니다. 이후 동일 명령으로 measured run을 수행해 Stage1 baseline과 비교합니다.Pod Ready → API readiness → engine warm-up → workload-specific warm-up → steady-state benchmark 순서로 검증합니다.Stage6a에서 특히 중요한 부분은 현재 Stage1이 NCCL을 단일 all_reduce_perf 실행으로 측정한다는 점입니다. 따라서 Stage6만 warm-up을 분리하면 Stage1 baseline과 측정 조건이 완전히 같지는 않습니다. 기존 Stage6 목적 자체가 Stage1 NCCL 결과를 K8s에서 재검증하는 것이므로 stage2_net_storage_validation.sh, 최종 인수용 baseline은 Stage1도 warm-up run → measured run으로 다시 생성하는 것을 권장합니다. 이 점은 Stage6a 결과 메타데이터에도 표시하도록 했습니다.
K8s vLLM은 기본적으로 Stage3와 같은 대표 workload를 사용합니다.
Pod Running
↓
Pod Ready
↓
/v1/models OK
↓
Engine warm-up
20 requests
↓
Short workload warm-up
1K in / 512 out / c64
↓
Short steady-state measurement
↓
Long workload warm-up
32K in / 512 out / c8
↓
Long steady-state measurement
따라서 Stage3 bare-metal의 70B BF16 short c64, long c8와 직접 비교하기 쉽게 맞췄습니다. Stage6 가이드의 A/B/C가 bare-metal 결과를 K8s에서 재검증한다는 원래 설계와도 일치합니다. stage2_net_storage_validation.sh
K8s 쪽도 warmup_trace.csv를 남깁니다. 그래서 이후에는 다음처럼 비교할 수 있습니다.
Bare-metal Stage3
Cold → Warm-up → Steady
│
├── TTFT
├── ITL
└── TPS
K8s Stage6
Pod Ready
↓
Cold → Warm-up → Steady
│
├── TTFT
├── ITL
└── TPS
즉 Stage3 cold와 Stage6 warm을 비교하거나, Stage3 warm과 K8s Pod 최초 요청을 비교하는 오류를 방지합니다.
문서도 함께 수정했습니다.
:chatgpt-content-reference{index="6"}Stage6 가이드
:chatgpt-content-reference{index="7"}환경변수 Reference
Stage6 가이드에는 stage6k_k8s_vllm_validation.sh를 별도 acceptance 항목으로 추가했습니다. 기존 가이드에서 Stage6는 6a~6j로 구성되어 있었으므로 stage2_net_storage_validation.sh 기존 번호를 깨지 않기 위해 6k로 추가했습니다.
실행 형태는 대략 다음과 같습니다.
export NAMESPACE=gpu-validation
export GPU_NODE_SELECTOR_VALUE=b300-node-01
# NCCL
export STAGE1_NCCL_BASELINE=/var/log/b300_validation/stage1_hw_xxx/07_nccl_allreduce.txt
./stage6a_k8s_nccl_revalidation.sh
# K8s vLLM
export VLLM_SERVICE=vllm-server
export MODEL_NAME=llama-3.1-70b
./stage6k_k8s_vllm_validation.sh
두 스크립트와 수정한 shell 파일은 bash -n 구문 검사를 통과하도록 구성했습니다.
다음으로 같이 손보면 가장 효과적인 부분은 Stage1의 NCCL 자체를 warm-up → measured 방식으로 변경하고, Stage3 summary와 Stage6 결과를 합쳐 Bare-metal vs K8s TTFT/ITL/TPS/NCCL 차이를 한 표와 그래프로 보여주는 최종 acceptance summary를 만드는 것입니다. 그러면 지금까지 만든 warm-up 체계가 인수검증 리포트까지 완전히 연결됩니다.
원본 Stage6 소스를 기준으로 다시 수정했습니다. 기존 6a의 목적은 그대로 유지하면서, 원래는 Pod가 뜨자마자 NCCL이 실행되고 Ready 후 60초 대기해 결과를 수집하던 구조였습니다. stage6a_k8s_nccl_revalidation stage6a_k8s_nccl_revalidation 이 부분을 명확히 분리했습니다.
수정 결과는 Pod Ready → NCCL warm-up → performance-ready → NCCL measured run → Stage1 비교입니다. Warm-up 결과는 warmup_trace.csv에 남지만 baseline 비교에서는 제외됩니다. 측정 명령은 기존과 동일한 all_reduce_perf -b 8M -e 4G -f 2 -g 8을 유지했습니다.
K8s vLLM은 기존 Stage6 원본에 Stage3와 직접 성능을 재비교하는 단계가 없어서 stage6k_k8s_vllm_performance_revalidation.sh를 신규 추가했습니다. 여기서는 Deployment Ready나 /v1/models=200을 성능 준비 완료로 간주하지 않습니다.
K8s Deployment Ready
↓
/v1/models OK
↓
API/Engine warm-up
↓
performance-ready 안정화 확인
↓
Stage3와 동일 benchmark command
↓
Bare-metal Stage3 ↔ K8s Stage6 비교
특히 stage6k는 Stage3와 다른 임의 workload로 숫자를 만들어내지 않도록 했습니다. STAGE3_BENCH_CMD에 Stage3에서 실제 사용한 동일 benchmark 명령을 넣어야 measured phase가 실행됩니다. 지정하지 않으면 performance-ready까지만 검증하고 측정을 보류합니다. 이렇게 해야 input/output length, concurrency 등의 차이 때문에 K8s overhead로 잘못 판단하는 것을 막을 수 있습니다.
6f도 원본의 PDB/readiness/drain 목적은 그대로 유지했습니다. 원래 6f는 Readiness/Startup Probe와 node drain을 검증하는 회복탄력성 테스트입니다. stage6f_k8s_resilience_test 여기에 “6f의 Ready는 트래픽 수용/회복탄력성 신호이지 performance-ready가 아니다. 성능 판정은 6k에서 한다”는 로그만 추가했습니다.
나머지 6b~6e, 6g~6j는 원본 그대로 보존했습니다. 예를 들어 6c는 TP=8 Pod가 실제 NVLink/NVSwitch topology를 보존하는지 보는 별도 검증이므로 warm-up 개념을 억지로 적용하지 않았습니다. stage6c_k8s_gpu_topology_check
전체 .sh에 대해 bash -n 구문 검사도 통과했습니다.
전체 수정본: stage6_warmup_from_original.tar.gzStage6 원본 기반 수정 패키지
핵심 파일: stage6a_k8s_nccl_revalidation.sh수정된 Stage6a NCCL · stage6k_k8s_vllm_performance_revalidation.sh신규 Stage6k K8s vLLM · stage6f_k8s_resilience_test.sh수정된 Stage6f · README_WARMUP_CHANGES.md변경사항 README
다만 완전히 공정한 NCCL 비교를 위해서는 Stage1 NCCL도 같은 warm-up → measured 방식으로 바꾸는 게 맞습니다. 지금 Stage6a만 바꾸면 K8s 측은 warmed measurement인데 기존 Stage1 baseline은 그렇지 않을 수 있기 때문입니다. 다음 단계에서는 Stage1 원본까지 연결해서 이 부분을 맞추면 bare-metal↔K8s 비교 기준이 완전히 동일해집니다.
네. 정리하면 6b~6j를 전부 그대로 실행하는 방식보다는 현재 인수검증 범위에 맞춰 선택 실행하는 게 좋습니다.
원본을 기준으로 보면 6b는 실제 Pod-to-Pod 및 선택적으로 ClusterMesh iperf3를 측정하므로 바로 실행해도 좋습니다. 다만 현재는 단일 측정이라 추후 3회 측정 + median으로 개선할 여지는 있습니다. stage6b_k8s_network_revalidation 6e도 실제 운영에서 ClusterMesh Global Service를 통해 MinIO 모델을 가져온다면 유효합니다. stage6e_clustermesh_minio_coldl…
제가 권하는 현재 실행 범위는 아래입니다.
| Stage | 현재 권장 | 이유 |
|---|---|---|
| 6a NCCL | 실행 | bare-metal NCCL 재검증 |
| 6b Network | 실행 | Cilium/Pod/ClusterMesh network 확인 |
| 6c GPU Topology | 실행 | TP8 GPU/NVLink topology 확인 |
| 6d Spark Burst | SKIP | 현재 제외한 burst 성능시험 |
| 6e MinIO | 조건부 실행 | 운영 모델 로딩 경로가 MinIO/ClusterMesh이면 실행 |
| 6f Resilience | 부분 실행 | Probe/PDB/restart 확인. 단일 B300에서 drain continuity는 N/A |
| 6g Partition | SKIP | 실제 ClusterMesh 연결을 끊음 stage6g_clustermesh_partition_t… |
| 6h NetworkPolicy | 실행 권장 | 운영 전 access-control 확인 |
| 6i Hubble | 실행 권장 | flow/drop 관측성 확인 stage6i_hubble_observability_ch… |
| 6j Contention | SKIP | 현재 제외한 noisy-neighbor/QoS 부하시험 |
| 6k K8s vLLM | 실행 | Stage3 bare-metal ↔ K8s 성능 재검증 |
그래서 실제 초기 인수 순서는 6c → 6a → 6b → 6k → 6e(해당 시) → 6h → 6i → 6f 일부 정도가 가장 깔끔합니다.
그리고 요청하신 stage6_summary_report.py도 만드는 방향이 맞습니다. Stage3a summary와 달리 Stage6는 모든 테스트가 같은 종류의 성능시험이 아니므로 다음처럼 묶는 게 좋습니다.
Stage6 Acceptance Summary
A. Core Acceptance
6c GPU Topology
6a NCCL
6b Network
6k K8s vLLM
B. Operational Validation
6e MinIO
6h NetworkPolicy
6i Hubble
6f Resilience
C. Deferred
6d Spark Burst
6g ClusterMesh Partition
6j Bandwidth Contention
Summary에서는 특히 다음 결과를 한눈에 비교하도록 만드는 게 좋습니다.
Bare-metal K8s Delta
------------------------------------------------------
NCCL busbw → NCCL busbw %
Stage2 iperf → Pod/ClusterMesh %
Stage3 TTFT → Stage6k TTFT %
Stage3 ITL → Stage6k ITL %
Stage3 TPS → Stage6k TPS %
GPU topology PASS / REVIEW
NetworkPolicy PASS / FAIL
Hubble PASS / REVIEW
MinIO PASS / REVIEW / N/A
Resilience PASS / REVIEW / N/A
그리고 최종 결과는 PASS / FAIL / REVIEW / N/A / SKIP으로 구분하는 게 적절합니다. 특히 성능 delta를 무조건 FAIL로 만들기보다는 REVIEW로 표시해 원인 분석 대상으로 두는 게 좋습니다. 현재 6b 원본에 있는 “5~10% 이내면 정상 CNI overhead” 같은 문구도 측정 참고값으로는 보여주되 자동 PASS/FAIL의 절대 기준으로 쓰지는 않는 방향이 안전합니다. stage6b_k8s_network_revalidation
현재 업로드된 Stage6 원본들과 우리가 수정한 6a/6f/6k 결과 형식을 기준으로 stage6_summary_report.py를 실제 생성하고, Stage3a summary까지 읽어서 bare-metal ↔ K8s 비교를 자동화하는 것까지 이어서 만들 수 있습니다.
만들었습니다. 기존 Stage6 원본들의 실제 출력 형식과 수정한 6a/6k 구조에 맞춰 작성했고, 샘플 결과로 parser 검증도 완료했습니다.
:chatgpt-content-reference{index="3"}stage6_summary_report.py
stage6_warmup_from_original_v2.tar.gzStage6 전체 최신 패키지
실행은 다음처럼 하면 됩니다.
python3 stage6_summary_report.py \
--base-dir /var/log/b300_validation \
--print
자동으로 최신 stage6*_timestamp 디렉터리를 찾아 다음처럼 분류합니다.
판정도 PASS / FAIL / REVIEW / N/A / NOT_RUN / SKIP으로 구분했습니다. 특히 성능 차이 자체는 함부로 FAIL 처리하지 않고 REVIEW 대상으로 남깁니다.
6a에서는 수정된 comparison_metrics.json을 읽어 다음 비교를 자동 표시합니다.
NCCL
Bare-metal Stage1 : 100.00 GB/s
K8s Stage6a : 97.00 GB/s
Delta : -3.00%
6b는 원본이 생성하는 pod_single.json, pod_multi.json, ClusterMesh JSON을 직접 파싱합니다. 원래 6b가 이 JSON에서 sum_received.bits_per_second를 읽도록 되어 있으므로 같은 데이터를 사용합니다. stage6b_k8s_network_revalidation
6c는 topology 결과에서 PHB/SYS가 나타나는지를 확인합니다. 이는 기존 6c의 판정 방식과 동일합니다. stage6c_k8s_gpu_topology_check
6h는 기존 리포트의 authorized=200 / unauthorized≠200을 읽어 기능 PASS/FAIL을 판단합니다. stage6h_network_policy_validati… 6i의 Hubble FORWARDED/DROPPED도 집계하지만, DROP이 있다는 이유만으로 FAIL시키지는 않고 원인 검토 대상으로 남깁니다.
6k는 performance_ready_at.txt, measured_command.txt, measured_benchmark.log, warmup_trace.csv를 읽습니다. 따라서 summary에 warm-up도:
Stage6k warm-up latency:
900.0 ms → 300.0 ms
처럼 나타납니다.
최종 Markdown은 자동으로:
/var/log/b300_validation/
└─ stage6_ACCEPTANCE_SUMMARY_YYYYMMDD_HHMMSS.md
에 생성됩니다.
현재 한 가지 남은 개선점은 6k의 TTFT / ITL / TPS를 Stage3a와 자동으로 숫자 비교하는 부분입니다. 지금 6k는 STAGE3_BENCH_CMD로 임의 명령을 실행하므로 출력 포맷이 보장되지 않아 summary가 숫자를 억지로 파싱하지 않게 했습니다. 다음 단계에서 6k를 Stage3a와 동일한 vllm bench serve --save-result --result-dir ... 형식으로 고정하면,
Metric Bare-metal Stage3a K8s Stage6k Delta
TTFT P50 82 ms 86 ms +4.9%
TTFT P99 145 ms 153 ms +5.5%
ITL P50 11 ms 12 ms +9.1%
Output TPS 8,420 8,105 -3.7%
까지 stage6_summary_report.py가 완전히 자동 생성하도록 연결할 수 있습니다. 이 부분까지 맞추는 게 지금 구조의 다음 적절한 수정입니다.