Merge pull request #577 from noonghunna/feat/phase2-big-card-envelopes

Phase 2: PRO 6000 + DGX Spark envelopes, fix Blackwell GPU detector
This commit is contained in:
noonghunna
2026-07-05 11:22:36 +05:00
committed by GitHub
5 changed files with 115 additions and 11 deletions

View File

@@ -63,6 +63,14 @@ envelopes:
target_ctx: 262144
date: 2026-07-05
note: "no-preemption ceiling (2x RTX 5090, 64 GB). Arithmetic, sm_120-calibrated (disc #571 paulp verify-stress PASS); awaiting a concurrency-soak to upgrade to validated."
rtx-6000-pro-blackwell:
max_num_seqs: 8 # 2 -> 8 on 2x96 GB (NVLink-bridged workstation)
compose_default: 2
computed:
basis: "kv-calc pool ceiling is ~16 (--compose dual --vram 96 --tp 2 --max-ctx 262144 --mem-util 0.96: N=16 PASS, N=20 caps), but capped to 8 — BANDWIDTH, not pool, binds. PRO 6000 GDDR7 (~1.8 TB/s) ≈ a 5090's, so useful concurrency sits near the 5090's 4, lifted to 8 by the 3x pool (less preemption); the rest of the pool is context headroom."
target_ctx: 262144
date: 2026-07-05
note: "operational cap, not the raw pool ceiling (see basis). 2x RTX PRO 6000 Blackwell, NVLink-bridged. No PRO 6000 on this rig — a concurrency-soak refines this and upgrades it to validated."
vllm/minimal:
rtx-5090:
@@ -73,15 +81,32 @@ envelopes:
target_ctx: 32768
date: 2026-07-05
note: "no-preemption ceiling (1x RTX 5090, 32 GB). Arithmetic, sm_120-calibrated (disc #571 paulp verify-stress PASS); awaiting a concurrency-soak to upgrade to validated."
rtx-6000-pro-blackwell:
max_num_seqs: 16 # 1 -> 16 on 1x96 GB
compose_default: 1
computed:
basis: "kv-calc pool ceiling is >56 (--compose minimal --vram 96 --tp 1 --max-ctx 32768 --mem-util 0.96: N=56 still PASS), but capped to 16 — bandwidth-bound. GDDR7 ≈ a 5090's, so 16 concurrent 32K streams (small per-stream KV) is a defensible operating point on the 3x pool; the raw >56 would over-batch into throughput collapse."
target_ctx: 32768
date: 2026-07-05
note: "operational cap, not the raw pool ceiling (see basis). 1x RTX PRO 6000 Blackwell. Spec-derived, no PRO 6000 on this rig — a soak refines + upgrades to validated."
dgx-spark:
max_num_seqs: 8 # 1 -> 8 on 1x128 GB unified (bandwidth-capped)
compose_default: 1
computed:
basis: "kv-calc pool ceiling is >80 (--compose minimal --vram 128 --tp 1 --max-ctx 32768 --mem-util 0.85: N=80 still PASS), but capped to 8 — Spark's ~273 GB/s LPDDR5X (≈1/7 of a 5090) HARD-binds concurrency. Useful streams sit near a 5090's (or below), NOT scaled by the 4x pool; the pool's value here is context headroom, not more streams."
target_ctx: 32768
date: 2026-07-05
note: "operational cap, bandwidth-bound (see basis). 1x DGX Spark (GB10), single-unit. TP=2 across two units is ConnectX/RDMA (network-bound) — NOT seeded for dual. No Spark on this rig — a soak refines + upgrades to validated."
# ON BIG CARDS, POOL != CONCURRENCY. The rtx-6000-pro-blackwell and dgx-spark
# rows above are OPERATIONAL CAPS, not raw kv-calc pool ceilings: past a point
# decode concurrency is bound by memory BANDWIDTH, not pool size. PRO 6000
# (~1.8 TB/s GDDR7 ≈ a 5090) lifts modestly above the 5090; Spark (~273 GB/s
# LPDDR5X, ~1/7 of a 5090) does NOT — its huge pool buys context headroom, not
# streams. Each row's `basis` cites the raw ceiling AND the bandwidth cap; a
# soak on real hardware refines the operating point and upgrades to validated.
#
# NOT SEEDED yet (computable, deferred on purpose):
# rtx-6000-pro-blackwell (96 GB): pool ceilings run very high (minimal ~40+,
# dual 16+) — those need a latency-aware cap (concurrency past a point
# trades single-stream TPS), not the raw pool ceiling. Seed once we pick
# the policy. Rare card; 5090 is the realistic target first.
# DGX Spark (GB10, sm_121, 128 GB): folds into the SAME framework, but has
# no hardware profile yet — add scripts/lib/profiles/hardware/dgx-spark.yml
# before a row can inject (the guard requires card ∈ hardware profiles).
# MULTI-GPU (TP>2, e.g. vllm/qwen-27b-multi-fast/max @ TP=4): the injection
# seam ALREADY handles homogeneous >2-card rigs — it collapses N identical
# cards to one class, so `vllm/dual` on 4x5090 injects the dual ceiling and

View File

@@ -0,0 +1,44 @@
schema_version: 1
id: dgx-spark
display_name: NVIDIA DGX Spark (GB10)
sm: 12.1
vram_gb: 128
arch: blackwell-gb10
# Unified LPDDR5X shared with the Grace CPU, so usable device memory is well
# below the 128 GB spec — mem_util_safe is deliberately conservative (OS + CPU
# reservation) rather than the 0.96 the discrete Blackwell SKUs carry.
mem_util_safe: 0.85
# NOTE: nvfp4 KV is DELIBERATELY NOT listed — like consumer Blackwell (sm_120),
# GB10 (sm_121) has no trtllm-gen FP4 FMHA build (that kernel is datacenter
# Blackwell sm_100/103 only). FP4 weights work; nvfp4 KV crashes. fp8_e4m3 is
# the FP4-era KV here. The #574 nvfp4 gate already excludes sm_121.
supported_kv_formats:
- bf16
- fp16
- fp8_e5m2
- fp8_e4m3
- turboquant_3bit_nc
- int8_per_token_head
- q4_0
- q5_0
- q8_0
- k8v4
kv_format_default:
long_context: fp8_e4m3
multi_stream: fp8_e4m3
balanced: fp8_e4m3
cudagraph: full
driver_pin_recommended:
min: "580.0"
notes: "GB10 ships on DGX OS with a 580.x-class (CUDA 13) driver."
nvlink_capable: false
power_cap_w_optimal: 120
power_cap_w_max: 140
# CRITICAL for concurrency envelopes: the 128 GB pool is huge but the ~273 GB/s
# LPDDR5X bandwidth (~1/7 of a 5090's GDDR7) is the binding constraint on decode
# concurrency — useful streams saturate near a 5090's, NOT scaled by the 4x pool
# (the extra pool buys context headroom, not more streams). Two units cluster
# over ConnectX (RDMA, not NVLink), so TP=2 across units is network-bound and
# NOT recommended — single-unit serving is the realistic mode. Specs are from
# public sheets; no DGX Spark on this rig (values not rig-measured).
notes: "GB10 Grace-Blackwell superchip, 128 GB unified LPDDR5X (~273 GB/s). Bandwidth-bound for concurrency. Single-unit serving; ConnectX clustering is not low-latency TP. Spec-derived, not rig-measured."

View File

@@ -54,8 +54,14 @@ def _hardware_id_from_gpu(name: str, mem_mib: int, sm: float) -> str:
vram_gb = round(mem_mib / 1024)
aliases = (
("rtx 6000 pro blackwell", "rtx-6000-pro-blackwell"),
("6000 pro blackwell", "rtx-6000-pro-blackwell"),
# RTX PRO 6000 Blackwell reports as "RTX PRO 6000 Blackwell" -> normalizes
# to "rtx pro 6000 blackwell" (PRO before 6000), so match "pro 6000".
# ("6000" alone is avoided — it would swallow the sm_89 "RTX 6000 Ada".)
("rtx pro 6000", "rtx-6000-pro-blackwell"),
("pro 6000", "rtx-6000-pro-blackwell"),
# DGX Spark's GB10 superchip reports as "GB10" / "NVIDIA GB10".
("dgx spark", "dgx-spark"),
("gb10", "dgx-spark"),
("rtx 3090 ti", "rtx-3090-ti"),
("3090 ti", "rtx-3090-ti"),
("rtx 3090", "rtx-3090"),
@@ -75,7 +81,16 @@ def _hardware_id_from_gpu(name: str, mem_mib: int, sm: float) -> str:
if needle in normalized:
return hardware_id
if sm >= 12 and vram_gb >= 32:
# sm >= 12 Blackwell family, split by SM then VRAM (name aliases above are
# the primary signal; these are the fallback when the name string is odd):
# GB10 / DGX Spark = sm_121 (unified 128 GB)
# RTX PRO 6000 Blackwell = sm_120, 96 GB
# RTX 5090 = sm_120, 32 GB
if 12.05 <= sm <= 12.2:
return "dgx-spark"
if sm >= 12 and vram_gb >= 64:
return "rtx-6000-pro-blackwell"
if sm >= 12 and vram_gb >= 24:
return "rtx-5090"
if sm >= 9 and vram_gb >= 80:
return "h100-80gb"

View File

@@ -122,6 +122,26 @@ assert_contains "$out" "VLLM_IMAGE=vllm/vllm-openai:v0.24.0"
assert_not_contains "$out" "KV_CACHE_DTYPE"
echo " ok: #246 arch-aware KV injection matrix (8 cases)"
# --- detector: Blackwell family must not collapse to rtx-5090 (#576 wrinkle) --
# The sm>=12 bucket used to map every Blackwell to rtx-5090, so a 96 GB PRO 6000
# and a 128 GB GB10 both mis-detected as a 32 GB 5090. Lock the split.
det="$(python3 - <<'PY'
import sys; sys.path.insert(0, "scripts/lib/profiles")
from launch_compat import _hardware_id_from_gpu as m
cases = [
("NVIDIA RTX PRO 6000 Blackwell", 98304, 12.0, "rtx-6000-pro-blackwell"),
("Unnamed Blackwell 96GB", 98304, 12.0, "rtx-6000-pro-blackwell"), # alias-miss fallback
("NVIDIA GB10", 131072, 12.1, "dgx-spark"),
("NVIDIA GeForce RTX 5090", 32607, 12.0, "rtx-5090"),
("NVIDIA RTX 6000 Ada Generation",49140, 8.9, "rtx-4090"), # 'pro 6000' must NOT catch Ada
]
bad = [f"{n}->{m(n,v,s)} want {e}" for n, v, s, e in cases if m(n, v, s) != e]
print("FAIL: " + " | ".join(bad) if bad else "OK")
PY
)"
[[ "$det" == "OK" ]] || { echo " FAIL: detector: $det"; exit 1; }
echo " ok: Blackwell detector split (PRO 6000 / GB10 / 5090 / Ada — 5 cases)"
if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
out="$(VLLM_NIGHTLY_SHA="$CLEAN_SHA" docker compose -f "$ROOT_DIR/models/qwen3.6-27b/vllm/compose/dual/autoround-int4/fp8-mtp.yml" config 2>/dev/null)"
assert_contains "$out" "image: vllm/vllm-openai:v0.24.0"

View File

@@ -23,7 +23,7 @@ run_test() {
run_test "load_profiles parses all profile groups" <<'PY'
from scripts.lib.profiles.compat import load_profiles
p = load_profiles()
assert len(p.hardware) == 9
assert len(p.hardware) == 10 # +dgx-spark (#576 follow-up)
assert len(p.models) == 11
assert len(p.workloads) == 5
assert len(p.engines) == 13