硬件适配:GB10 统一内存 128GB 不是"显存",是"总预算"
T AGENT 开发纪实 · EP32 · MiniMax-H3 六期原理课 ③
上一期 FP8 把 134GB 压到 67GB,可 67GB 还是装不进任何"显存"——因为它根本没住在显存里。这一期讲硬件:SM121 的四个"不支持",和那块没有独立显存的统一内存。
Compute Capability
12.1
统一内存实测
127.6GB
nvidia-smi 显存
N/A
个"不支持"
4
💡 本节要点:EP32:硬件适配——GB10 的 SM121 上,128GB 不是'显存'是'统一内存总预算';nvidia-smi 显存查询返回 N/A;四个'不支持'(INT8/Triton FP8/FA4 变长注意力/独立大显存)决定了量化与内核的选型
起点问题
四个问题:这台机器的"内存"为什么特殊?
- Q1 · GB10 是什么芯片? · DGX Spark 的单芯片,Blackwell 架构,算力等级 SM121,CPU 是 ARM 核——不是 x86 服务器。
- Q2 · 传统 GPU 装不下 134GB? · A100/H100 显存 80GB,物理上限。134GB 单卡装不下,只能多卡切或量化后走 PCIe 搬运。
- Q3 · 128GB 是"显存"吗? · 不是。nvidia-smi 查显存直接返回 N/A——GPU 和 CPU 共享同一块物理内存,没有独立 VRAM。
- Q4 · 四个"不支持"是哪四个? · INT8 指令、Triton FP8 编译、FA4 变长注意力、独立大显存——本期逐个拆,它们决定了选型。
核心矛盾: 装下 134GB 靠的不是"显存容量",而是一套和传统 GPU 完全不同的内存模型
💡 本节要点:起点问题:GB10 是什么芯片?为什么传统 GPU 装不下 134GB?128GB 是'显存'吗?四个'不支持'是哪四个?——四个问题指向同一个答案:这台机器的内存模型和传统 GPU 根本不一样
硬件画像
这台机器的实测身份:没有显存数字的 GPU
| 维度 | 实测值 | 说明 |
|---|---|---|
| GPU | NVIDIA GB10 | DGX Spark 单芯片,Blackwell 架构 |
| 算力等级 | Compute Capability 12.1 | SM121 :有 FP8、无 INT8 指令 |
| 显存查询 | nvidia-smi → N/A | 没有独立 VRAM——传统"显存"概念在这里失效 |
| 物理内存 | MemTotal 127.6GB | 128GB 统一内存(CPU/GPU 共享) |
| CPU | Cortex-X925 + A725 | ARM 大小核 ×20,aarch64,非 x86 |
| CUDA | 13.0 | 驱动与运行时版本 |
| 第一个信号: 一台 nvidia-smi 查不到显存 的 GPU——它申请内存的方式、驻留权重的方式,都和传统 GPU 不一样。后面所有"装不下"和"装得下"都从这里开始。 | ||
| > 💡 本节要点:硬件画像(本机实测):GPU NVIDIA GB10 / compute cap 12.1(SM121)/ 显存查询 N/A / 物理内存 127.6GB / CPU ARM 大小核 20 核 / CUDA 13.0 |
核心机制
统一内存:GPU 和 CPU 住在同一块内存里
GPU SM121 FP8 矩阵乘 计算单元 → 统一内存 128GB LPDDR5x GPU 与 CPU 共享 无独立 VRAM → CPU ARM ×20 aarch64 宿主进程
- 🧱 · 没有"显存"这个概念 · GPU 缺页时从统一内存按需换入,不是从独立 VRAM 里取——所以 nvidia-smi 报 N/A。
- 🗂️ · 128GB 是"总预算" · 不是"一次能装下的量",而是"能寻址 + 按需驻留的池子"。常驻 ~102GB、留 18-19GB 余量。
- ⚡ · C2C 高带宽互联 · GPU 与 CPU 直连共享内存,页粒度换入换出,比 PCIe 搬运高一个量级——这是能"住下"的前提。
💡 本节要点:统一内存架构:GB10 的 GPU 与 CPU 通过 NVLink-C2C 共享同一块物理内存(LPDDR5x,128GB),没有显存/内存之分;128GB 是'总预算'不是'显存上限'
对比视角
传统 GPU 的 134GB:显存是一堵"墙"
| 传统 GPU(A100 / H100) | GB10(DGX Spark) | |
|---|---|---|
| 内存模型 | 显存(VRAM)与系统内存 物理分离 | 统一内存,CPU/GPU 共享 |
| 容量上限 | 80GB VRAM 硬墙 | 127.6GB 总预算 |
| 装 134GB 权重 | 单卡不可能 → 2 卡张量并行 / 量化 + PCIe offload | FP8 减半 + 统一内存按需换页 |
| 搬运路径 | PCIe 搬运(带宽瓶颈) | NVLink-C2C 共享内存(页粒度驻留) |
| 结论 | "塞进显存才算数" | "页表能寻址 + 带宽跟得上,就能跑" |
| 关键反转: 传统 GPU 上"装得下"= 权重必须整体进 VRAM;GB10 上"装得下"= 内存能寻址、用到哪页换入哪页。 装 134GB 的物理载体不是显存容量,是内存寻址与换页。 | ||
| > 💡 本节要点:为什么传统 GPU 装不下:A100/H100 显存 80GB 物理上限,134GB 单卡不可能;多卡张量并行或量化+PCIe offload;而 GB10 的内存是'池子'不是'墙' |
核心机制 2
Demand Paging:权重"用到哪页,换入哪页"
67GB FP8 权重 (页表可寻址) 13 个 shard 不整体进 GPU → 按需换页 demand paging 前向用到哪层 就换入哪页 → 常驻 ~102GB 留 18-19GB 余量 峰值不超红线 系统不 OOM
- 🗜️ · 加载并发受控 · --num-weight-load-threads 2:两个线程慢慢换入,避免一次性把内存打满。
- 📦 · 分配段可扩展 · PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True:显存分配按段伸缩,不一次性预留。
- 🛟 · 余量是生命线 · 18-19GB 是给激活、KV、宿主进程留的呼吸空间——统一内存是共享池,抢完就 OOM。
💡 本节要点:demand paging 按需驻留:67GB FP8 权重按页换入 GPU,用到才进;常驻红线 ~102GB,留 18-19GB 余量;配合 --num-weight-load-threads 2 控制加载并发、expandable_segments 管理分配
踩坑 1 · 监控失效
坑 1:显存查不到,怎么盯内存水位?
$ nvidia-smi --query-gpu=memory.total
N/A ← 传统显存监控直接失效
$ cat /proc/meminfo | grep MemAvailable
MemAvailable: 19896696 kB ← 换这个
现象: 没有独立显存, nvidia-smi 的显存读数全是 N/A ——用显存监控 GPU 内存的思路在这台机器上不存在。
- 统一内存的水位计 · · /proc/meminfo :MemTotal 127.6GB / MemAvailable(宿主可用) · vLLM 内部分配 :worker 报告 92,957 MiB · swap 用量 :2.8GB / 15GB(换出但没崩) · 结论:盯"总池子"的水位,而不是"显存"
理解: 统一内存把"显存/内存"两个水位计合并成一个。 监控对象从 GPU 显存换成整个内存池 ,余量就是 MemAvailable。
💡 本节要点:踩坑 1:nvidia-smi 显存 N/A——监控方式失效;改用 /proc/meminfo(MemTotal 127.6GB / MemAvailable)+ vLLM 内部分配 + swap 用量来盯内存水位
踩坑 2 · 不支持清单
坑 2:SM121 没有 INT8 指令——量化只能走 FP8
# 请求到达 INT8 量化路径时,后端直接拒绝
File "vllm/_core/execution", line ...
RuntimeError: dispatch_scaled_mm: INT8 not supported on SM121
- ❌ · INT8 矩阵指令 · SM121 没有 INT8 的缩放矩阵乘指令——量化到 8 位整数这条路,硬件层面就不存在。
- ✅ · FP8 原生支持 · FP8 矩阵乘是 SM121 的原生能力,Cutlass FP8 内核直接跑——这是硬件给的唯一低精度路线。
- 🧭 · 选型被硬件决定 · 不是"FP8 比 INT8 好",而是"这台机器只有 FP8 能跑"。量化路线的决策空间由 SM121 划定。
启示: EP31 的 FP8 不是最优选择,而是 唯一选择 ——先查硬件支持什么,再决定量化成什么。💡 本节要点:踩坑 2:INT8 不支持——SM121 没有 INT8 矩阵指令,dispatch_scaled_mm 直接报 unsupported;FP8 是这台硬件上唯一原生的低精度路线
踩坑 3 · 不支持清单
坑 3:Triton 编不出 FP8——量化器改绑原生 CUDA
# Triton 编译激活量化器 → SM121 上无法 lower
TritonError: codegen for FP8 scalar
not supported on SM121
# 兼容层:把量化器绑定到原生 CUDA op
for module in model.modules():
if isinstance(module, QuantFP8):
module.activation_quantizer.forward_cuda # 原生路径
现象: vLLM 自带的 QuantFP8 量化器走 Triton 编译, SM121 的 Triton 后端编不出 FP8 标量 ——编译期就失败。
修复: 同一份代码里有个原生 CUDA 的 scaled_fp8_quant 能跑。兼容层在构建期发现量化器,把它们全部绑定到 forward_cuda (Cutlass 内核)——实测绑了 260 个。
- 同一操作,两条路 · Triton(编译型)在 SM121 失败;原生 CUDA(预编译)可用。 结论:FP8 内核必须走原生 CUDA,不碰 Triton。
💡 本节要点:踩坑 3:Triton FP8 编译失败——QuantFP8 的 Triton 后端在 SM121 无法 lower FP8 scalar;量化器必须绑原生 CUDA(forward_cuda / CutlassFP8ScaledMMLinearKernel)
踩坑 4 · 不支持清单
坑 4:FA4 编不出变长注意力——退 PyTorch SDPA
| # | "不支持" | 现象 / 证据 | 实际走的路 |
|---|---|---|---|
| 1 | INT8 矩阵指令 | dispatch_scaled_mm: INT8 not supported on SM121 | FP8(原生) |
| 2 | Triton FP8 编译 | codegen for FP8 scalar not supported | 原生 CUDA forward_cuda |
| 3 | FA4 变长注意力 | CuTe variable-length kernel compile failed | PyTorch SDPA(逐段) |
| 4 | "独立大显存" | nvidia-smi memory.total = N/A | 统一内存 demand paging |
| 共同规律: 四个"不支持"来自同一个架构事实—— SM121 是 Blackwell 的统一内存 SoC,不是传统独立显存的 GPU 。每个"不支持"都对应一次选型修正:FP8、原生 CUDA、SDPA、按需驻留。 | |||
| > 💡 本节要点:踩坑 4:FA4 变长注意力编译失败(CuTe 内核对 H3 packed sequence 编不出来)→ 退 PyTorch SDPA;四个'不支持'汇总:INT8 指令 / Triton FP8 / FA4 变长内核 / 独立大显存 |
验证
内存账本:数字全部落在红线内
▌ 总预算 MemTotal · 127.6 GB
▌ 常驻红线 · ~102 GB(留 18-19GB 余量)
▌ 实测加载占用 · 89.17 GiB / 532s
▌ 请求后分配 · 92,957 MiB(低于红线 ✅)
- 🧠 · 宿主可用内存 · 请求后 21 GiB——系统没被模型挤死
- 💾 · swap 用量 · 2.8GB / 15GB——有换出,但没崩
- 🎯 · 结论 · 102GB 红线守住了,账本对得上
💡 本节要点:验证:内存账本——MemTotal 127.6GB 总预算 / 常驻红线 ~102GB / 实测加载 89.17GB / 请求后 92,957 MiB / 宿主可用 21GB / swap 2.8GB——全在红线内
总结
硬件决定决策边界:128GB 是池子,不是墙
—— 没有独立显存,128GB 是 CPU/GPU 共享的总预算,nvidia-smi 显存查询返回 N/A
统一内存
—— 权重"用到哪页换入哪页",常驻 ~102GB,留 18-19GB 余量,峰值 92,957 MiB 不越线
按需驻留
—— INT8 指令、Triton FP8、FA4 变长注意力、独立大显存:每个都逼出一个替代方案
四个"不支持"
—— FP8 / Cutlass / SDPA / demand paging,全是 SM121 这台硬件给出的"唯一可行解"
选型被硬件划定
硬件把路划好了,可每条路都是"先失败、再换路"试出来的—— 那串失败链和兼容补丁怎么写的?
- 🧮 · EP31 · 量化原理 · 在线动态 FP8 ✅
- 🖥️ · EP32 · 硬件适配 · 本期:GB10 统一内存 ✅
- 🧩 · EP33 · 失败链与补丁 · 下期:六连坑 + 兼容补丁
本期证据:本机实测(lscpu / nvidia-smi / /proc/meminfo)· docs/PATCH.md 失败链 · docs/RESULTS.md 内存账本
💡 本节要点:总结:GB10 不是一台'显存很大的 GPU',而是一台'内存共享的 SoC'——128GB 是总预算,四个'不支持'划定选型边界(FP8/Cutlass/SDPA/按需驻留);下期 EP33:失败链与兼容补丁