1273 lines
43 KiB
HTML
1273 lines
43 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="color-scheme" content="light">
|
||
<title>6000D 双机 DeepSeek-V4-Pro 推理优化计划</title>
|
||
<style>
|
||
:root {
|
||
--paper: #ffffff;
|
||
--canvas: #f4f6f7;
|
||
--ink: #172126;
|
||
--muted: #5e6b72;
|
||
--line: #d9e0e3;
|
||
--strong-line: #aebbc1;
|
||
--teal: #087e75;
|
||
--teal-soft: #e7f4f2;
|
||
--orange: #b65318;
|
||
--orange-soft: #fff1e8;
|
||
--code-bg: #19262b;
|
||
--code-ink: #eaf2f3;
|
||
--max-content: 960px;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
color: var(--ink);
|
||
background: var(--canvas);
|
||
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC",
|
||
"Source Han Sans SC", Arial, sans-serif;
|
||
font-size: 16px;
|
||
line-height: 1.75;
|
||
}
|
||
|
||
a {
|
||
color: var(--teal);
|
||
text-decoration-thickness: 1px;
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
a:hover {
|
||
color: var(--orange);
|
||
}
|
||
|
||
.document-header {
|
||
color: #f7fbfb;
|
||
background: #17343a;
|
||
border-bottom: 5px solid #d76a2a;
|
||
}
|
||
|
||
.document-header__inner {
|
||
width: min(100% - 40px, 1260px);
|
||
margin: 0 auto;
|
||
padding: 38px 0 34px;
|
||
}
|
||
|
||
.document-header__eyebrow {
|
||
margin: 0 0 6px;
|
||
color: #9edbd5;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.document-header h1 {
|
||
max-width: 900px;
|
||
margin: 0;
|
||
font-size: clamp(28px, 4vw, 44px);
|
||
line-height: 1.24;
|
||
font-weight: 750;
|
||
}
|
||
|
||
.document-header__meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px 22px;
|
||
margin-top: 18px;
|
||
color: #d4e4e6;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.layout {
|
||
display: grid;
|
||
grid-template-columns: 260px minmax(0, var(--max-content));
|
||
gap: 34px;
|
||
width: min(100% - 40px, 1260px);
|
||
margin: 0 auto;
|
||
padding: 34px 0 72px;
|
||
align-items: start;
|
||
}
|
||
|
||
.toc {
|
||
position: sticky;
|
||
top: 18px;
|
||
max-height: calc(100vh - 36px);
|
||
overflow: auto;
|
||
padding: 16px 16px 18px;
|
||
background: var(--paper);
|
||
border: 1px solid var(--line);
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.toc__title {
|
||
margin: 0 0 10px;
|
||
color: var(--muted);
|
||
font-size: 13px;
|
||
font-weight: 750;
|
||
}
|
||
|
||
.toc a {
|
||
display: block;
|
||
padding: 5px 4px;
|
||
color: #365058;
|
||
font-size: 13px;
|
||
line-height: 1.45;
|
||
text-decoration: none;
|
||
border-left: 2px solid transparent;
|
||
}
|
||
|
||
.toc a:hover,
|
||
.toc a:focus-visible {
|
||
color: var(--teal);
|
||
border-left-color: var(--teal);
|
||
}
|
||
|
||
.toc a[data-level="3"] {
|
||
padding-left: 16px;
|
||
color: #607178;
|
||
font-size: 12px;
|
||
}
|
||
|
||
main {
|
||
min-width: 0;
|
||
}
|
||
|
||
article {
|
||
padding: 42px 52px 64px;
|
||
background: var(--paper);
|
||
border: 1px solid var(--line);
|
||
border-radius: 6px;
|
||
box-shadow: 0 12px 34px rgba(28, 43, 49, 0.07);
|
||
}
|
||
|
||
article > h1:first-child {
|
||
display: none;
|
||
}
|
||
|
||
h2,
|
||
h3,
|
||
h4 {
|
||
scroll-margin-top: 22px;
|
||
text-wrap: balance;
|
||
}
|
||
|
||
h2 {
|
||
margin: 52px 0 16px;
|
||
padding-bottom: 9px;
|
||
font-size: 26px;
|
||
line-height: 1.35;
|
||
border-bottom: 2px solid var(--strong-line);
|
||
}
|
||
|
||
h2:first-of-type {
|
||
margin-top: 12px;
|
||
}
|
||
|
||
h3 {
|
||
margin: 34px 0 10px;
|
||
color: #21434a;
|
||
font-size: 20px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
h4 {
|
||
margin: 24px 0 8px;
|
||
font-size: 17px;
|
||
}
|
||
|
||
p,
|
||
ul,
|
||
ol {
|
||
margin-top: 0;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
li + li {
|
||
margin-top: 5px;
|
||
}
|
||
|
||
blockquote {
|
||
margin: 22px 0;
|
||
padding: 14px 18px;
|
||
color: #33494f;
|
||
background: var(--teal-soft);
|
||
border-left: 4px solid var(--teal);
|
||
border-radius: 0 4px 4px 0;
|
||
}
|
||
|
||
blockquote p:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
table {
|
||
display: table;
|
||
width: 100%;
|
||
margin: 20px 0 28px;
|
||
border-collapse: collapse;
|
||
table-layout: auto;
|
||
font-size: 14px;
|
||
}
|
||
|
||
th,
|
||
td {
|
||
padding: 10px 12px;
|
||
vertical-align: top;
|
||
text-align: left;
|
||
border: 1px solid var(--line);
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
th {
|
||
color: #15393e;
|
||
background: #eaf2f2;
|
||
font-weight: 750;
|
||
}
|
||
|
||
tbody tr:nth-child(even) {
|
||
background: #fafcfc;
|
||
}
|
||
|
||
code {
|
||
padding: 2px 5px;
|
||
color: #85380d;
|
||
background: var(--orange-soft);
|
||
border-radius: 3px;
|
||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
|
||
font-size: 0.9em;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
pre {
|
||
margin: 18px 0 24px;
|
||
padding: 16px 18px;
|
||
overflow: auto;
|
||
color: var(--code-ink);
|
||
background: var(--code-bg);
|
||
border-radius: 6px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
pre code {
|
||
padding: 0;
|
||
color: inherit;
|
||
background: transparent;
|
||
border-radius: 0;
|
||
white-space: pre;
|
||
overflow-wrap: normal;
|
||
}
|
||
|
||
hr {
|
||
margin: 38px 0;
|
||
border: 0;
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.source-link {
|
||
display: inline-flex;
|
||
margin-top: 20px;
|
||
padding: 8px 12px;
|
||
color: #21434a;
|
||
background: #eef3f4;
|
||
border: 1px solid var(--line);
|
||
border-radius: 4px;
|
||
text-decoration: none;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
@media (max-width: 980px) {
|
||
.layout {
|
||
grid-template-columns: minmax(0, 1fr);
|
||
}
|
||
|
||
.toc {
|
||
position: static;
|
||
max-height: none;
|
||
}
|
||
|
||
article {
|
||
padding: 32px 28px 50px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 620px) {
|
||
body {
|
||
font-size: 15px;
|
||
}
|
||
|
||
.document-header__inner,
|
||
.layout {
|
||
width: min(100% - 24px, 1260px);
|
||
}
|
||
|
||
article {
|
||
padding: 26px 18px 42px;
|
||
}
|
||
|
||
h2 {
|
||
font-size: 22px;
|
||
}
|
||
|
||
h3 {
|
||
font-size: 18px;
|
||
}
|
||
|
||
table {
|
||
display: block;
|
||
overflow-x: auto;
|
||
white-space: normal;
|
||
}
|
||
}
|
||
|
||
@media print {
|
||
@page {
|
||
size: A4;
|
||
margin: 15mm 13mm 17mm;
|
||
}
|
||
|
||
body {
|
||
background: #fff;
|
||
font-size: 10.5pt;
|
||
}
|
||
|
||
.document-header {
|
||
color: #172126;
|
||
background: #fff;
|
||
border-bottom: 3px solid #17343a;
|
||
}
|
||
|
||
.document-header__inner {
|
||
width: 100%;
|
||
padding: 0 0 18px;
|
||
}
|
||
|
||
.document-header__eyebrow,
|
||
.document-header__meta {
|
||
color: #4e5e64;
|
||
}
|
||
|
||
.layout {
|
||
display: block;
|
||
width: 100%;
|
||
padding: 20px 0 0;
|
||
}
|
||
|
||
.toc,
|
||
.source-link {
|
||
display: none;
|
||
}
|
||
|
||
article {
|
||
padding: 0;
|
||
border: 0;
|
||
box-shadow: none;
|
||
}
|
||
|
||
h2,
|
||
h3,
|
||
h4 {
|
||
break-after: avoid-page;
|
||
}
|
||
|
||
table,
|
||
pre,
|
||
blockquote {
|
||
break-inside: avoid;
|
||
}
|
||
|
||
a {
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header class="document-header">
|
||
<div class="document-header__inner">
|
||
<p class="document-header__eyebrow">Inference Optimization Plan</p>
|
||
<h1>6000D 双机 DeepSeek-V4-Pro 推理优化计划</h1>
|
||
<div class="document-header__meta">
|
||
<span>节点:174.1.51.5 + 174.1.51.7</span>
|
||
<span>资源:16 × RTX PRO 6000 Blackwell</span>
|
||
<span>版本:2026-07-31 13:40:03 CST</span>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="layout">
|
||
<aside class="toc" aria-label="目录">
|
||
<p class="toc__title">目录</p>
|
||
<nav id="toc-list"></nav>
|
||
</aside>
|
||
|
||
<main>
|
||
<article id="document-content">
|
||
<h1>6000D 双机 DeepSeek-V4-Pro 推理优化计划</h1>
|
||
<blockquote>
|
||
<p>适用环境:<code>174.1.51.5 + 174.1.51.7</code>,每台 8 张 RTX PRO 6000 Blackwell Server Edition<br>当前部署:DeepSeek-V4-Pro,16 张 GPU 组成一个完整实例<br>当前约束:模型暂时只能使用全部 16 张 GPU,无法额外复制一套模型进行 PD 分离<br>计划版本:2026-07-31 15:25:00 CST</p>
|
||
</blockquote>
|
||
<h2>当前执行状态与阶段档案</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>工作项</th>
|
||
<th>状态</th>
|
||
<th>实现与结果档案</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>6000D 双机通信与 NCCL 基础</td>
|
||
<td>已建立;覆盖计算网、RDMA、Bootstrap、NCCL 参数和日志判读</td>
|
||
<td><a href="./6000D双机通信与NCCL术语入门.html">打开通信术语入门</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td>DeepSeek-V4-Pro / 双机 Pro6000D / SGLang TP16 快速性能地图</td>
|
||
<td>已完成;双 Rail NET/IB + GDRDMA,固定点 9/9、混合 A/B 3/3,总用时 28 分 36 秒</td>
|
||
<td><a href="./phase1_dsv4pro_pro6000d_2node_sglang_quick_map.html">打开实施记录</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td>DeepSeek-V4-Pro / 双机 Pro6000D / SGLang 硬件与资源竞争归因</td>
|
||
<td>最终采集代码已完成;首轮 8/8 成功,精确窗口、双节点 DCGM、PCIe/NCCL 基线和逐指标报告等待最终复跑</td>
|
||
<td>
|
||
<a href="./phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html">打开 Phase 2 档案</a><br>
|
||
<a href="./phase2_code.html">打开 Phase 2 代码详解</a>
|
||
</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<p>
|
||
<strong>阶段档案规范:</strong>正文只保留最终成功实验、有效结果和结论;
|
||
失败尝试压缩到末尾的经验教训。阶段完成时删除“暂不能下结论”等过渡内容。
|
||
</p>
|
||
<h2>0. 先看懂双机通信</h2>
|
||
<p>
|
||
在分析 TP16 性能前,先区分设备、传输后端与 NCCL 参数。
|
||
完整解释和本次网络误配置复盘见
|
||
<a href="./6000D双机通信与NCCL术语入门.html">《6000D 双机通信与 NCCL 术语入门》</a>。
|
||
</p>
|
||
<table>
|
||
<thead>
|
||
<tr><th>术语</th><th>一句话解释</th><th>本项目实例</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>NCCL</td><td>NVIDIA 多 GPU 通信库,执行 collective 和点对点通信</td><td>SGLang TP16 的跨 GPU 通信层</td></tr>
|
||
<tr><td>RDMA</td><td>网卡绕过常规 TCP/内核拷贝直接访问远端内存</td><td>双机高速数据面的目标路径</td></tr>
|
||
<tr><td>IB / RoCE</td><td>IB 是高速网络/Verbs 体系;RoCE 在以太网上承载 RDMA</td><td>NCCL 日志统一显示为 <code>NET/IB</code></td></tr>
|
||
<tr><td><code>eth0/eth3</code></td><td>400G 物理端口的 Linux netdev/IP 入口</td><td>仅这两个接口用于节点间部署通信</td></tr>
|
||
<tr><td><code>mlx5_0/mlx5_3</code></td><td>映射到上述物理端口的 RDMA Verbs/HCA 入口</td><td>与 <code>eth0/eth3</code> 有映射关系,但不是同一个软件设备</td></tr>
|
||
<tr><td>NCCL bootstrap</td><td>rank 启动时交换身份、地址、拓扑和连接信息的阶段</td><td>先建连,再选择真正的数据后端</td></tr>
|
||
<tr><td><code>NCCL_SOCKET_IFNAME</code></td><td>选择 NCCL 可用的 IP 接口</td><td>RDMA 失败时也决定 Socket 数据走哪张网卡</td></tr>
|
||
<tr><td><code>NCCL_IB_HCA</code></td><td>选择 NCCL 可用的 RDMA HCA</td><td><code>mlx5_0,mlx5_3</code></td></tr>
|
||
<tr><td><code>NCCL_CROSS_NIC</code></td><td>控制同一 ring/tree 能否在节点间跨不同 HCA</td><td>只有真正使用多 HCA <code>NET/IB</code> 时才有意义</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p>
|
||
<strong>400G 是每条物理 Ethernet 链路的标称线速,不是“TCP 速度”或“RDMA
|
||
速度”。</strong>同一条链路可以承载 TCP,也可以承载 RoCE/RDMA;
|
||
<code>400 Gbit/s ≈ 50 GB/s</code> 只是单向理论上限,NCCL 的
|
||
<code>algbw/busbw</code> 与端到端模型吞吐都不能直接等同于该数字。
|
||
</p>
|
||
<p>
|
||
<strong>当前 6000D 机内没有 NVLink。</strong>单机 8 卡由 PCIe 连接:
|
||
GPU0–3 与 GPU4–7 各自在本地 PCIe Switch 内通信,两组之间还要经过 Host Bridge
|
||
和 CPU/NUMA 互联。NCCL 机内日志中的 <code>P2P/IPC</code> 是 CUDA P2P over PCIe;
|
||
两机之间则使用 <code>mlx5_0/mlx5_3</code> 双 Rail
|
||
<code>NET/IB + GDRDMA</code>。Phase 2 最终代码已加入机内 PCIe P2P 全矩阵、
|
||
单机 8-rank 和双机 16-rank NCCL 微基准;正式数值在最终复跑后写入阶段档案。
|
||
</p>
|
||
<h2>1. 目标与原则</h2>
|
||
<h3>1.1 最终目标</h3>
|
||
<p>在不做 PD 分离的前提下,定位 DeepSeek-V4-Pro 在双机 6000D 上的端到端瓶颈,并提高:</p>
|
||
<ul>
|
||
<li>满足 TTFT、TPOT 等 SLO 时的最大吞吐。</li>
|
||
<li>长上下文 Prefill 性能。</li>
|
||
<li>Decode 输出吞吐和单请求 TPOT。</li>
|
||
<li>混合流量下的稳定性与 P95/P99 时延。</li>
|
||
<li>16 张 GPU、PCIe 和双 Rail 计算网的有效利用率。</li>
|
||
</ul>
|
||
<h3>1.2 核心原则</h3>
|
||
<ol>
|
||
<li>先找关键路径,再调参数。</li>
|
||
<li>先用端到端指标确认问题,再用 Timeline 找到阶段,最后才用 Kernel Profiler。</li>
|
||
<li>Prefill、Decode 和混合干扰必须分别测试。</li>
|
||
<li>一次只改变一个变量,每项优化都要保留可复现的 A/B 结果。</li>
|
||
<li>单算子更快不代表服务吞吐更高,最终结论必须回到真实请求和 SLO。</li>
|
||
<li>Profiling Run 只用于定位,不能与无 Profiler 的正式性能结果直接比较。</li>
|
||
</ol>
|
||
<h2>2. 当前最值得验证的瓶颈假设</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>编号</th>
|
||
<th>假设</th>
|
||
<th>为什么值得优先检查</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody><tr>
|
||
<td>H1</td>
|
||
<td>TP16 每层跨机通信暴露过多</td>
|
||
<td>两台机器没有跨机 NVLink;应先确保 Collective 真正经过计算网/RDMA,而不是 Socket 回退</td>
|
||
</tr>
|
||
<tr>
|
||
<td>H2</td>
|
||
<td>NSA Indexer 或 Sparse Attention Kernel 效率不足</td>
|
||
<td>DSV4-Pro 的稀疏注意力路径复杂,Indexer 可能抵消稀疏收益</td>
|
||
</tr>
|
||
<tr>
|
||
<td>H3</td>
|
||
<td>MoE Grouped GEMM 或路由负载不均</td>
|
||
<td>Decode 小 Batch 容易 Memory-bound,热门专家可能制造慢 Rank</td>
|
||
</tr>
|
||
<tr>
|
||
<td>H4</td>
|
||
<td>长 Prefill 干扰在线 Decode</td>
|
||
<td>统一实例中 Prefill 与 Decode 竞争计算、显存带宽和调度预算</td>
|
||
</tr>
|
||
<tr>
|
||
<td>H5</td>
|
||
<td>CPU Scheduler、Metadata 或 Kernel Launch 产生 GPU 空洞</td>
|
||
<td>小 Batch Decode 对 CPU 和 Launch 开销特别敏感</td>
|
||
</tr>
|
||
<tr>
|
||
<td>H6</td>
|
||
<td>KV Cache 容量、碎片或 Preemption 限制并发</td>
|
||
<td>大模型权重占用高,剩余设备显存决定上下文与并发容量</td>
|
||
</tr>
|
||
<tr>
|
||
<td>H7</td>
|
||
<td>当前并行拓扑并非最优</td>
|
||
<td>使用 16 张卡不等于只能采用单一 TP16 拓扑</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<h2>3. Profiling 总体流程</h2>
|
||
<pre><code class="language-text">端到端性能地图
|
||
↓
|
||
服务内部指标与硬件计数器
|
||
↓
|
||
Nsight Systems 时间线
|
||
↓
|
||
确定 1-3 个主要瓶颈
|
||
↓
|
||
Nsight Compute 或专项 Microbenchmark
|
||
↓
|
||
提出优化并做单变量 A/B
|
||
↓
|
||
回到完整 Benchmark 和 SLO 验证
|
||
</code></pre>
|
||
<p>不要直接对完整服务运行长时间 Nsight Compute。它的开销很高,也会生成巨大的报告。应先用 Nsight Systems 找到占关键路径的 Kernel,再构造小型复现。</p>
|
||
<h2>4. Phase 0:冻结可复现环境</h2>
|
||
<p>正式测试前,每个 Run 必须保存以下信息:</p>
|
||
<ul>
|
||
<li>两台机器的 GPU、Driver、CUDA、NCCL 版本。</li>
|
||
<li>vLLM 或 SGLang 的镜像名、镜像 ID、Git Commit 和 Python 包版本。</li>
|
||
<li>模型目录、权重文件校验信息和模型配置。</li>
|
||
<li>完整 Docker Run 与服务启动命令。</li>
|
||
<li>完整 Benchmark 命令。</li>
|
||
<li>TP、DP、PP、EP 拓扑。</li>
|
||
<li>Attention、NSA、Indexer、MoE、GEMM 和通信 Backend。</li>
|
||
<li><code>NCCL_SOCKET_IFNAME</code>、<code>NCCL_IB_HCA</code>、<code>NCCL_CROSS_NIC</code> 等通信变量。</li>
|
||
<li>GPU Memory Fraction、Context Limit、Active Request Limit、KV Cache Dtype。</li>
|
||
<li>CUDA Graph、Chunked Prefill、Prefix Cache 和投机解码状态。</li>
|
||
<li>运行前后的 <code>nvidia-smi</code>、容器列表和网络状态。</li>
|
||
</ul>
|
||
<p>建议每次运行生成:</p>
|
||
<pre><code class="language-text">results/<RUN_ID>/
|
||
run_manifest.json
|
||
run.log
|
||
summary.csv
|
||
summary.jsonl
|
||
aggregate.csv
|
||
report.md
|
||
cases/
|
||
server/
|
||
</code></pre>
|
||
<h3>基线约束</h3>
|
||
<ul>
|
||
<li>初始基线不启用 MTP、EAGLE、DSpark 等投机解码。</li>
|
||
<li>初始基线使用唯一随机 Prompt,避免 Prefix Cache 影响。</li>
|
||
<li>短 Prefill 与 Decode 点执行一个 Warm-up;昂贵的 32K/128K Prefill 不做同形状 Warm-up。</li>
|
||
<li>隔离测试点在 Warm-up 后、正式计时前清空 Prefix Cache,避免首条测量请求复用 Warm-up 前缀。</li>
|
||
<li>快速定位 Run 先执行 1 次;只有进入里程碑基线后才执行 3 次并计算变异系数。</li>
|
||
<li>正式结果使用无 Profiler 运行。</li>
|
||
<li>Profiling 只捕获预热后的少量 Engine Step。</li>
|
||
</ul>
|
||
<h2>5. Phase 1:建立阶段化性能地图</h2>
|
||
<p>本阶段当前实现与结果维护在
|
||
<a href="./phase1_dsv4pro_pro6000d_2node_sglang_quick_map.html">Phase 1:双机 SGLang TP16 快速性能地图实施记录</a>。
|
||
代码采用单一 Shell 入口 <code>run_quick_map.sh</code>,不修改或调用旧的全天全量脚本。</p>
|
||
<p>
|
||
最终 Run <code>dsv4pro-phase1-full-20260730-220916</code> 已完成:
|
||
Head 与 Worker 均通过双 Rail <code>NET/IB + GDRDMA</code> 门禁,
|
||
9 个固定点和 3 个混合 A/B 结果共 12/12 成功,总用时 28 分 36 秒。
|
||
单请求 32K/128K Prefill 输入吞吐为 2,652.76/2,710.16 token/s;
|
||
1K → 1K Decode 的 Output TPS 从 C=1 的 31.41 提升到 C=64 的 647.42。
|
||
</p>
|
||
<p>
|
||
最值得继续归因的现象有两个:32K Prefill 从 C=1 增至 C=16 时,
|
||
聚合输入吞吐只提高 17.3%,TTFT P95 却从 12.335 秒增至 162.087 秒;
|
||
在 C=32 Decode 中注入一个 128K Prefill 后,Output TPS 下降 24.08%,
|
||
TPOT P95 增加 66.55%。Phase 2 将围绕这两个现象采集硬件时间序列。
|
||
</p>
|
||
<h3>5.1 当前固定快速矩阵</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Case ID</th>
|
||
<th align="right">ISL</th>
|
||
<th align="right">OSL</th>
|
||
<th align="right">并发</th>
|
||
<th>主要目标</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody><tr>
|
||
<td><code>short_prefill_latency_1k_c1</code></td>
|
||
<td align="right">1K</td>
|
||
<td align="right">1</td>
|
||
<td align="right">1</td>
|
||
<td>固定开销与最小 TTFT</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>mid_prefill_latency_32k_c1</code></td>
|
||
<td align="right">32K</td>
|
||
<td align="right">1</td>
|
||
<td align="right">1</td>
|
||
<td>NSA、Indexer、Attention</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>long_prefill_latency_128k_c1</code></td>
|
||
<td align="right">128K</td>
|
||
<td align="right">1</td>
|
||
<td align="right">1</td>
|
||
<td>长上下文计算和显存压力</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>mid_prefill_throughput_32k_c16</code></td>
|
||
<td align="right">32K</td>
|
||
<td align="right">1</td>
|
||
<td align="right">16</td>
|
||
<td>Chunked Prefill 与输入 TPS</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>decode_latency_1k_to_1k_c1</code></td>
|
||
<td align="right">1K</td>
|
||
<td align="right">1K</td>
|
||
<td align="right">1</td>
|
||
<td>单请求 TPOT</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>decode_throughput_1k_to_1k_c16</code></td>
|
||
<td align="right">1K</td>
|
||
<td align="right">1K</td>
|
||
<td align="right">16</td>
|
||
<td>MoE、Batch 与通信</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>decode_throughput_1k_to_1k_c32</code></td>
|
||
<td align="right">1K</td>
|
||
<td align="right">1K</td>
|
||
<td align="right">32</td>
|
||
<td>Decode 吞吐</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>decode_throughput_1k_to_1k_c64</code></td>
|
||
<td align="right">1K</td>
|
||
<td align="right">1K</td>
|
||
<td align="right">64</td>
|
||
<td>Decode 高并发吞吐</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>balanced_32k_to_1k_c8</code></td>
|
||
<td align="right">32K</td>
|
||
<td align="right">1K</td>
|
||
<td align="right">8</td>
|
||
<td>Prefill 与 Decode 综合压力</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<p>长度应以当前已验证的服务容量为上限。如果 128K 不可用,先降到 64K,但必须在 Manifest 中记录原因。</p>
|
||
<h3>5.2 混合干扰 A/B</h3>
|
||
<ol>
|
||
<li>先运行有限的 <code>1K → 1K, C=32</code> Decode 对照流量。</li>
|
||
<li>再次运行相同 Decode 基准流量,并等待 Benchmark 确认进入正式测量。</li>
|
||
<li>正式测量开始 10 秒后注入一个 <code>128K → 1, C=1</code> 长 Prefill;不额外执行 128K Warm-up。</li>
|
||
<li>比较 Output TPS、P95 TTFT、P95 TPOT 与 P95 E2E 的变化。</li>
|
||
</ol>
|
||
<p>
|
||
该 A/B 已完成:注入 128K Prefill 后,Decode Output TPS 从 455.68 降至
|
||
345.95 token/s,TPOT P95 从 65.88 ms 增至 109.73 ms。它证明存在聚合级干扰,
|
||
但逐请求调度时间线仍由后续阶段补齐。
|
||
</p>
|
||
<h3>5.3 本轮运行与停止策略</h3>
|
||
<ul>
|
||
<li>固定矩阵不做 Add-16 搜索,也不按 SLO 提前终止。</li>
|
||
<li>快速 Run 每个 Case 只执行一波请求,即 <code>num_prompts=C</code>,默认重复 1 次。</li>
|
||
<li>单个 Case 失败会记录错误并继续;服务失去健康状态则中止,避免连锁无效结果。</li>
|
||
<li>断点续跑只有在 <code>meta.json</code> 为成功且原始 Benchmark JSON 可重新解析时才跳过。</li>
|
||
<li>进入里程碑基线后使用 3 次重复;自适应并发搜索仍由后续完整容量实验负责。</li>
|
||
<li>如果少量 Case 已稳定暴露足以改变调查方向的异常,可由用户决定提前结束并进入归因阶段;必须在 Manifest 和报告中记录未执行项。</li>
|
||
</ul>
|
||
<p>不能把“最大成功并发”“最高 TPS 并发”和“满足 SLO 的最大并发”混为同一个值。</p>
|
||
<h3>5.4 当前采集范围</h3>
|
||
<h4>本轮已实现的请求层指标</h4>
|
||
<ul>
|
||
<li>实际成功、失败和超时请求数。</li>
|
||
<li>实际输入、输出和总 token 数。</li>
|
||
<li>Request Throughput。</li>
|
||
<li>Input、Output 和 Total TPS。</li>
|
||
<li>P50/P95/P99 TTFT。</li>
|
||
<li>P50/P95/P99 TPOT。</li>
|
||
<li>P50/P95/P99 ITL。</li>
|
||
<li>P50/P95/P99 E2E。</li>
|
||
</ul>
|
||
<h4>本轮明确不采集</h4>
|
||
<p>Scheduler Step、逐请求 Queue Time、显存分解、GPU/CPU/网络时间序列和 Kernel Timeline
|
||
不伪装成当前已有能力;它们分别由后续硬件指标与 Profiling 阶段补齐。</p>
|
||
<h2>6. Phase 2:同步采集轻量硬件指标</h2>
|
||
<p>
|
||
本阶段的设计、代码改动与结果同步维护在
|
||
<a href="./phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html">
|
||
Phase 2:硬件与资源竞争归因档案</a>。本阶段重放长 Prefill、并发 Prefill、
|
||
普通 Decode、长输出 Decode、长上下文 Decode,以及
|
||
<code>1K → 1K, C=32</code> 的混合 A/B。首轮 Run
|
||
<code>dsv4pro-phase2-20260731-130125</code> 在 26 分 26 秒内完成 8/8 个结果;
|
||
最终采集代码固定到提交 <code>30664faa41f8</code>,完成最终复跑和汇报后才进入 Phase 3。
|
||
</p>
|
||
<h3>6.1 首轮归因结果</h3>
|
||
<ul>
|
||
<li>混合负载再次稳定复现:Decode Output TPS 下降 24.03%,TPOT P95 增加 66.79%,E2E P95 增加 63.30%。</li>
|
||
<li>128K Prefill 注入窗口两节点 GPU 平均利用率约 99%,功耗约 274 W,频率稳定;显存每卡约 83.2–83.4 GiB,只剩约 2.3 GiB 余量。</li>
|
||
<li>整机 CPU 平均约 8%–11%,没有全机 CPU 或 I/O Wait 饱和,但少量 CPU 核持续高负载,Scheduler/Affinity/NUMA 热点仍需关注。</li>
|
||
<li>双 Rail 流量对称且错误增量为 0;最高平均总发送约 140 Gbit/s,即每条 400G Rail 约 70 Gbit/s,原始 RoCE 带宽未饱和。</li>
|
||
</ul>
|
||
<p>
|
||
最终代码已经把首轮的采集限制变成强制门禁:两节点
|
||
<code>dcgmi discovery -l</code> 必须成功;每个 Case 使用
|
||
<code>Starting main benchmark run</code> 加 SGLang duration 形成正式测量窗口;
|
||
必需采集器提前退出会让 Run 失败。
|
||
</p>
|
||
<h3>6.2 最终采集范围</h3>
|
||
<ul>
|
||
<li><code>nvidia-smi</code>:GPU/显存利用率、显存、功耗、温度、SM/Memory Clock 和 P-state,每秒一次。</li>
|
||
<li>DCGM:SM Active/Occupancy、Tensor Active、设备显存接口 Active、PCIe TX/RX,每秒一次。</li>
|
||
<li><code>mpstat/pidstat/perf/numastat</code>:整机、热点核、服务进程、CPU 计数器和 NUMA 内存,每 5 秒一次。</li>
|
||
<li><code>sar</code> 与 HCA Counter:<code>eth0/eth3</code> 和 <code>mlx5_0/mlx5_3</code> 的吞吐、均衡、错误与重试。</li>
|
||
<li>通信基线:两节点 CUDA P2P 全矩阵、两组 8-rank AllReduce、三组 16-rank <code>NCCL_CROSS_NIC=0/1/2</code>。</li>
|
||
</ul>
|
||
<h3>6.3 数据与报告规则</h3>
|
||
<p>
|
||
每种指标都生成独立的 <code>case_*_summary.csv</code>。最终
|
||
<code>report.md</code> 必须逐项列出原始文件、有效样本数、Head/Worker 数值、
|
||
Mean/P95/Max、Case 间变化和解释,不能只写抽象结论。缺失数据写
|
||
<code>-</code> 并报告采集器状态,不能当成 0。
|
||
</p>
|
||
<h3>6.4 与 Phase 3 的边界</h3>
|
||
<p>
|
||
Phase 2 回答“哪个硬件/Host/通信资源在什么 Case 中升高,以及硬件基线是多少”。
|
||
Phase 3 只捕获短 TP16 Timeline,回答具体 Kernel、Scheduler gap、Collective、
|
||
Rank 同步及计算/通信重叠,不重复 Phase 2 的长时间轻量采样。
|
||
</p>
|
||
<h2>7. Phase 3:时间线 Profiling(Nsight Systems 为主)</h2>
|
||
<p>
|
||
Nsight Systems、PyTorch Profiler 和 NVTX 是三件不同的东西:Nsight Systems
|
||
记录系统级 CUDA/NCCL/CPU 时间线;PyTorch Profiler 由框架接口触发;
|
||
NVTX 只是在时间线上添加可读标记。启用 NVTX 不等于已经启动 Nsight。
|
||
</p>
|
||
<h3>7.1 与 Phase 2 的分工</h3>
|
||
<table>
|
||
<thead>
|
||
<tr><th>问题</th><th>负责阶段或工具</th><th>是否在 Phase 3 重复</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>GPU/CPU 平均利用率、功耗、频率、显存</td><td>Phase 2 轻量采样</td><td>否;Phase 3 只保留最低限度健康检查</td></tr>
|
||
<tr><td>双 Rail 流量、均衡与错误计数</td><td>Phase 2 HCA Counter</td><td>否</td></tr>
|
||
<tr><td>机内 PCIe P2P 与 8/16 卡 Collective 峰值能力</td><td>一次性通信微基准:<code>p2pBandwidthLatencyTest</code> 与 <code>all_reduce_perf</code></td><td>只建立一次硬件基线,不随每个 Phase 重跑</td></tr>
|
||
<tr><td>真实请求中 NCCL Kernel 在何时发生、耗时多久</td><td>Phase 3 Nsight Systems Timeline</td><td>是,Phase 3 的核心</td></tr>
|
||
<tr><td>通信是否与 Attention/MoE Kernel 重叠、GPU 是否在等待 Rank</td><td>Phase 3 Nsight Systems Timeline</td><td>是,Phase 2 无法回答</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p>
|
||
因此 Phase 3 可以分析卡间通信,但分析的是<strong>真实请求里的时间与依赖关系</strong>,
|
||
不是再次统计平均网络带宽。通信微基准负责给出硬件上限,Phase 3 负责解释 SGLang
|
||
距离该上限有多远,以及通信是否落在关键路径上。
|
||
</p>
|
||
<h3>7.2 捕获策略</h3>
|
||
<ul>
|
||
<li>只捕获预热后的 5 到 10 个 Engine Step。</li>
|
||
<li>Prefill、Decode 和混合干扰分别生成报告。</li>
|
||
<li>两台机器分别保存原始报告。</li>
|
||
<li>优先保留所有 Rank;文件过大时至少保留代表 Rank 和跨机通信相关 Rank。</li>
|
||
<li>报告必须和对应 Benchmark Case ID 绑定。</li>
|
||
<li>不重复运行 Phase 2 的五点硬件采集矩阵,不同时开启高频 <code>pidstat</code>、<code>mpstat</code>、<code>sar</code> 或 DCGM 全量采样。</li>
|
||
</ul>
|
||
<h3>7.3 vLLM</h3>
|
||
<p>当前版本支持时,使用 CUDA Profiler 动态 Capture:</p>
|
||
<pre><code class="language-bash">export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||
|
||
nsys profile \
|
||
--trace=cuda,nvtx,nccl \
|
||
--trace-fork-before-exec=true \
|
||
--cuda-graph-trace=node \
|
||
--capture-range=cudaProfilerApi \
|
||
--capture-range-end=repeat \
|
||
-o /data/profile/dsv4_tp16 \
|
||
vllm serve ... \
|
||
--profiler-config.profiler cuda
|
||
</code></pre>
|
||
<p>压测端使用支持 Profile Trigger 的 Bench:</p>
|
||
<pre><code class="language-bash">vllm bench serve ... --profile
|
||
</code></pre>
|
||
<h3>7.4 SGLang</h3>
|
||
<p>
|
||
以下 <code>SGLANG_TORCH_PROFILER_DIR</code> 与 <code>/start_profile</code>
|
||
属于 SGLang 的 PyTorch Profiler 路径,可用于框架级时间线,但不能把生成物
|
||
称为 Nsight Systems 报告。
|
||
</p>
|
||
<p>服务启动前设置:</p>
|
||
<pre><code class="language-bash">export SGLANG_TORCH_PROFILER_DIR=/data/profile/sglang
|
||
</code></pre>
|
||
<p>Profiling 专用 Run 可增加:</p>
|
||
<pre><code class="language-text">--enable-layerwise-nvtx-marker
|
||
</code></pre>
|
||
<p>捕获预热后的 10 个 Step:</p>
|
||
<pre><code class="language-bash">curl -X POST http://127.0.0.1:30000/start_profile \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{
|
||
"output_dir": "/data/profile/sglang",
|
||
"start_step": 5,
|
||
"num_steps": 10,
|
||
"activities": ["CPU", "GPU"]
|
||
}'
|
||
</code></pre>
|
||
<p>多机 Trace 自动合并要求两台机器能访问同一个共享输出目录。没有共享目录时分别保存,再在本地汇总。</p>
|
||
<p>
|
||
真正的 Nsight Systems Run 需要在两台节点分别由 <code>nsys</code> 捕获对应
|
||
SGLang 进程,并绑定相同 Case ID 和时间窗口。正式执行前先验证容器内外的
|
||
<code>nsys</code> 版本、子进程跟踪方式及动态 Capture 机制,再固化命令;
|
||
不直接对整轮 Benchmark 做长时间全量捕获。
|
||
</p>
|
||
<h3>7.4 时间线必须回答的问题</h3>
|
||
<ol>
|
||
<li>Prefill 和 Decode 各自的 Top Kernel 是什么?</li>
|
||
<li>NCCL 在关键路径上的暴露时间是多少?</li>
|
||
<li>通信与计算重叠了多少?</li>
|
||
<li>每层之间是否存在 CPU 或同步空洞?</li>
|
||
<li>CUDA Graph 是否覆盖常见 Decode Batch?</li>
|
||
<li>16 个 Rank 是否同时结束?</li>
|
||
<li>是否存在固定慢 Rank?</li>
|
||
<li>MoE Expert Token 是否严重不均衡?</li>
|
||
<li>NSA Indexer 的成本占 Sparse Attention 总成本多少?</li>
|
||
<li>长 Prefill 到来时,Decode Kernel 为什么被延迟?</li>
|
||
</ol>
|
||
<h3>7.5 报告分析</h3>
|
||
<pre><code class="language-bash">nsys stats <REPORT>.nsys-rep
|
||
</code></pre>
|
||
<p>重点查看:</p>
|
||
<ul>
|
||
<li>CUDA GPU Kernel Summary。</li>
|
||
<li>NCCL Summary。</li>
|
||
<li>NCCL GPU Time Utilization。</li>
|
||
<li>Communication/Compute Overlap。</li>
|
||
<li>NCCL Straggler。</li>
|
||
<li>CUDA API Summary。</li>
|
||
<li>OS Runtime 和 CPU Thread Timeline。</li>
|
||
</ul>
|
||
<h2>8. 证据到优化方向的映射</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>观察到的证据</th>
|
||
<th>更可能的根因</th>
|
||
<th>下一项 A/B</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody><tr>
|
||
<td>Decode 中 NCCL 占比高,且通信未被计算覆盖</td>
|
||
<td>TP16 通信受限</td>
|
||
<td>TP8+PP2、NCCL 拓扑与算法</td>
|
||
</tr>
|
||
<tr>
|
||
<td>C=1 很慢,并发增加后 TPS 明显改善</td>
|
||
<td>MoE/权重读取 Memory-bound</td>
|
||
<td>Batch、MoE Backend、MTP</td>
|
||
</tr>
|
||
<tr>
|
||
<td>GPU 利用率呈锯齿,Kernel 间有明显空洞</td>
|
||
<td>CPU Scheduler 或 Launch 开销</td>
|
||
<td>CUDA Graph、异步调度</td>
|
||
</tr>
|
||
<tr>
|
||
<td>一个或少数 Rank 长期最慢</td>
|
||
<td>Expert、NIC 或 NUMA 不均衡</td>
|
||
<td>EPLB、Affinity、Rank Mapping</td>
|
||
</tr>
|
||
<tr>
|
||
<td>NSA Indexer 时间接近或超过 Attention</td>
|
||
<td>稀疏索引收益不足</td>
|
||
<td>Indexer Backend、Top-K、融合</td>
|
||
</tr>
|
||
<tr>
|
||
<td>长 ISL 的 Attention 时间异常增长</td>
|
||
<td>Prefill Kernel 或 Chunking 问题</td>
|
||
<td>Prefill Backend、Chunk Size</td>
|
||
</tr>
|
||
<tr>
|
||
<td>KV Cache 长期接近满并发生重算</td>
|
||
<td>设备显存容量不足</td>
|
||
<td>FP8 KV、并发和 Context 上限</td>
|
||
</tr>
|
||
<tr>
|
||
<td>注入长 Prefill 后 Decode TPOT 暴涨</td>
|
||
<td>Prefill/Decode 相互干扰</td>
|
||
<td>Chunked Prefill 与 Scheduler</td>
|
||
</tr>
|
||
<tr>
|
||
<td>GPU 利用率低但 CPU 单核满载</td>
|
||
<td>Host 端瓶颈</td>
|
||
<td>Frontend、Tokenizer、Scheduler</td>
|
||
</tr>
|
||
<tr>
|
||
<td>两条 Rail 流量明显不均</td>
|
||
<td>NIC Mapping 或 NCCL 拓扑</td>
|
||
<td>HCA、CROSS_NIC、NUMA Affinity</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<h2>9. Phase 4:优先级最高的拓扑实验</h2>
|
||
<h3>9.1 A:TP16 基线</h3>
|
||
<p>当前方案用于建立所有后续实验的对照。</p>
|
||
<p>风险是每层 TP Collective 都可能跨越两台机器,Decode 小消息通信尤其容易被延迟支配。</p>
|
||
<h3>9.2 B:TP8 + PP2</h3>
|
||
<p>逻辑上:</p>
|
||
<pre><code class="language-text">Node 5: Pipeline Stage 0, TP8
|
||
Node 7: Pipeline Stage 1, TP8
|
||
</code></pre>
|
||
<p>理想情况下,每卡权重占用与 TP16 接近:</p>
|
||
<pre><code class="language-text">TP16:
|
||
每卡权重约为 W / 16
|
||
|
||
TP8 + PP2:
|
||
每个 Stage 保存 W / 2
|
||
Stage 内由 8 卡切分
|
||
每卡权重约为 (W / 2) / 8 = W / 16
|
||
</code></pre>
|
||
<p>潜在收益:</p>
|
||
<ul>
|
||
<li>每层 TP Collective 留在单机。</li>
|
||
<li>跨机主要传输 Pipeline Stage 边界激活。</li>
|
||
<li>避免每层都进行跨机 AllReduce。</li>
|
||
</ul>
|
||
<p>潜在代价:</p>
|
||
<ul>
|
||
<li>Pipeline Bubble。</li>
|
||
<li>低并发延迟可能变差。</li>
|
||
<li>KV Cache、Hybrid Cache 和 DSV4-Pro 模型实现可能暂不支持 PP。</li>
|
||
<li>两个 Stage 的计算量可能不均衡。</li>
|
||
</ul>
|
||
<p>测试顺序:</p>
|
||
<ol>
|
||
<li>先做加载与单请求 Smoke Test。</li>
|
||
<li>对比 C=1 Decode 延迟。</li>
|
||
<li>对比 C=16/32/64 吞吐。</li>
|
||
<li>观察跨机网络流量是否显著下降。</li>
|
||
<li>观察两个 Pipeline Stage 是否负载均衡。</li>
|
||
</ol>
|
||
<h3>9.3 C:Attention TP8/DP2 + MoE EP16</h3>
|
||
<p>目标是:</p>
|
||
<ul>
|
||
<li>Attention 在节点内使用 TP8。</li>
|
||
<li>两个 Attention DP Group 并行处理请求。</li>
|
||
<li>MoE Expert 在 16 张卡上分布。</li>
|
||
</ul>
|
||
<p>这接近“Attention DP + MoE EP”的思路。Expert 权重通常占模型大头,因此即使 Attention 权重复制两份,也有机会放入显存。</p>
|
||
<p>必须先验证:</p>
|
||
<ul>
|
||
<li>当前 vLLM/SGLang 版本是否支持 DSV4-Pro 的该拓扑。</li>
|
||
<li>Expert 权重、非 Expert 权重和 KV Cache 的实际显存占用。</li>
|
||
<li>All-to-All 是否比当前 TP16 AllReduce 更划算。</li>
|
||
<li>Expert 负载是否均衡。</li>
|
||
</ul>
|
||
<h2>10. Phase 5:通信专项</h2>
|
||
<h3>10.1 不只测 1 GiB 大消息</h3>
|
||
<p>之前的 1 GiB <code>all_reduce_perf</code> 主要说明大消息带宽。Decode 中的 Collective 往往更小,可能由延迟主导。</p>
|
||
<p>需要覆盖真实消息尺度:</p>
|
||
<pre><code class="language-bash">all_reduce_perf -b 8K -e 64M -f 2 -g 8
|
||
all_gather_perf -b 8K -e 64M -f 2 -g 8
|
||
reduce_scatter_perf -b 8K -e 64M -f 2 -g 8
|
||
</code></pre>
|
||
<p>若启用 EP,还要测试 All-to-All。</p>
|
||
<h3>10.2 通信优化顺序</h3>
|
||
<ol>
|
||
<li>确认两条 Rail 都在工作。</li>
|
||
<li>确认 Rank、GPU、NIC 和 NUMA Affinity。</li>
|
||
<li>对照实际模型消息大小。</li>
|
||
<li>查看 NCCL 自动选择的 Algorithm、Protocol 和 Channel。</li>
|
||
<li>只有自动选择明显不合理时,才 A/B <code>Ring/Tree</code>、<code>Simple/LL128</code> 等设置。</li>
|
||
<li>观察模型端到端结果,而不只看 nccl-tests 峰值。</li>
|
||
</ol>
|
||
<h2>11. Phase 6:Kernel 专项</h2>
|
||
<p>从 Nsight Systems 中选累计占关键路径最高的 1 到 3 个 Kernel,再使用 Nsight Compute。</p>
|
||
<p>DSV4-Pro 的优先怀疑对象:</p>
|
||
<ul>
|
||
<li>NSA Indexer/Top-K。</li>
|
||
<li>Sparse MLA/Attention Prefill。</li>
|
||
<li>Sparse MLA/Attention Decode。</li>
|
||
<li>MoE Gate、Dispatch、Grouped GEMM、Combine。</li>
|
||
<li>FP8 Quant/Dequant 与 Scale Packing。</li>
|
||
<li>RMSNorm、Rope、KV Cache Store 等碎片化小算子。</li>
|
||
<li>NCCL Collective Kernel。</li>
|
||
</ul>
|
||
<p>需要分析:</p>
|
||
<ul>
|
||
<li>SM 和 Tensor Core 利用率。</li>
|
||
<li>DRAM 吞吐与 L2 Hit Rate。</li>
|
||
<li>Occupancy。</li>
|
||
<li>Register 与 Shared Memory 压力。</li>
|
||
<li>Warp Stall 原因。</li>
|
||
<li>Kernel Shape 与 Batch/Token 数。</li>
|
||
<li>小 Kernel Launch 次数。</li>
|
||
</ul>
|
||
<p>优化优先顺序:</p>
|
||
<ol>
|
||
<li>切换已有高性能 Backend。</li>
|
||
<li>调整 Backend 的 Shape/Workspace/Tile 配置。</li>
|
||
<li>消除无用 Copy、Cast 和临时 Tensor。</li>
|
||
<li>融合相邻的 Memory-bound 小算子。</li>
|
||
<li>现有 Backend 不覆盖关键 Shape 时,再开发新 Kernel 或提交 PR。</li>
|
||
</ol>
|
||
<h2>12. Phase 7:Scheduler 与统一实例干扰</h2>
|
||
<h3>12.1 混合干扰实验</h3>
|
||
<p>先建立稳定 Decode 背景流量:</p>
|
||
<pre><code class="language-text">ISL=1K
|
||
OSL=1K
|
||
C=32
|
||
</code></pre>
|
||
<p>运行稳定后,周期性注入一个长 Prefill:</p>
|
||
<pre><code class="language-text">ISL=128K
|
||
OSL=1
|
||
C=1
|
||
</code></pre>
|
||
<p>比较注入前后:</p>
|
||
<ul>
|
||
<li>Decode P50/P95/P99 TPOT。</li>
|
||
<li>Decode Output TPS。</li>
|
||
<li>长请求 TTFT。</li>
|
||
<li>每轮 Prefill Chunk。</li>
|
||
<li>Scheduler Queue。</li>
|
||
<li>GPU Timeline。</li>
|
||
</ul>
|
||
<h3>12.2 可调方向</h3>
|
||
<ul>
|
||
<li>Chunked Prefill Size。</li>
|
||
<li>Max Prefill Tokens。</li>
|
||
<li>Max Batched Tokens。</li>
|
||
<li>Max Running Requests/Max Num Seqs。</li>
|
||
<li>Prefill 与 Decode 调度优先级。</li>
|
||
<li>CUDA Graph Batch Coverage。</li>
|
||
<li>双 Batch Overlap 或框架已有的通算重叠能力。</li>
|
||
</ul>
|
||
<p>调优目标不是单独最大化 Prefill TPS,而是减少长 Prefill 对 Decode SLO 的破坏。</p>
|
||
<h2>13. Phase 8:显存与缓存</h2>
|
||
<p>当前初始值应保持固定,只在发现明确证据后调整:</p>
|
||
<ul>
|
||
<li>GPU Memory Fraction。</li>
|
||
<li>Max Context Length。</li>
|
||
<li>Active Request Limit。</li>
|
||
<li>KV Cache Dtype。</li>
|
||
<li>Page/Block Size。</li>
|
||
<li>CUDA Graph Capture Size。</li>
|
||
</ul>
|
||
<p>若 KV Cache 是瓶颈,优先顺序:</p>
|
||
<ol>
|
||
<li>确认权重和 Workspace 的真实占用。</li>
|
||
<li>检查 Allocated/Reserved 差值与碎片。</li>
|
||
<li>使用 FP8 KV Cache,前提是当前 Kernel 支持且精度可接受。</li>
|
||
<li>根据业务上限设置 Context Length,不为不会出现的极端长度预留容量。</li>
|
||
<li>设置合理的 Active Request Limit,避免运行时 OOM。</li>
|
||
<li>再考虑 CPU/L3 KV Offload。</li>
|
||
</ol>
|
||
<p>Prefix Cache 单独做第二阶段测试:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th align="right">命中率</th>
|
||
<th>用途</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody><tr>
|
||
<td align="right">0%</td>
|
||
<td>纯计算基线</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="right">20%</td>
|
||
<td>低复用业务</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="right">50%</td>
|
||
<td>中等公共前缀</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="right">80%</td>
|
||
<td>Agent/Coding 高复用</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<p>Mooncake 或三级缓存只有在 Prefix 可复用时才有明显价值。随机独立 Prompt 不适合评价它。</p>
|
||
<h2>14. Phase 9:MTP 与模型级优化</h2>
|
||
<p>当 TP16 Baseline、并行拓扑、通信、Backend 和 Scheduler 已稳定后,再测试:</p>
|
||
<ul>
|
||
<li>原生 MTP。</li>
|
||
<li>DSpark。</li>
|
||
<li>EAGLE。</li>
|
||
<li>KV Cache 量化。</li>
|
||
<li>更低比特权重量化。</li>
|
||
<li>Sparse Attention 算法或 Indexer 优化。</li>
|
||
</ul>
|
||
<p>投机解码至少记录:</p>
|
||
<ul>
|
||
<li>Accept Rate。</li>
|
||
<li>Mean Accept Length。</li>
|
||
<li>Target Forward TPS。</li>
|
||
<li>Draft/MTP 开销。</li>
|
||
<li>CPU 调度气泡。</li>
|
||
<li>不同并发下的净收益。</li>
|
||
</ul>
|
||
<p>不能只看 Accept Length,也不能只看 C=1。</p>
|
||
<h2>15. 里程碑与交付物</h2>
|
||
<h3>M1:可信 Baseline</h3>
|
||
<p>完成条件:</p>
|
||
<ul>
|
||
<li>九个固定快速地图点与混合干扰 A/B 均完成;里程碑版本各有 3 次重复。</li>
|
||
<li>同一 Case 的关键 TPS 变异系数尽量不超过 3%。</li>
|
||
<li>所有环境、命令和日志可追溯。</li>
|
||
</ul>
|
||
<p>交付:</p>
|
||
<ul>
|
||
<li>Baseline Summary。</li>
|
||
<li>SLO Frontier。</li>
|
||
<li>GPU/CPU/Network Timeline。</li>
|
||
</ul>
|
||
<h3>M2:瓶颈报告</h3>
|
||
<p>完成条件:</p>
|
||
<ul>
|
||
<li>Prefill、Decode、混合三类 Profile 完成。</li>
|
||
<li>找出累计贡献最高的 1 到 3 个瓶颈。</li>
|
||
<li>每个判断都有 Trace、计数器或日志证据。</li>
|
||
</ul>
|
||
<p>交付:</p>
|
||
<ul>
|
||
<li><code>.nsys-rep</code> 或 Torch Trace。</li>
|
||
<li>Kernel/NCCL Summary。</li>
|
||
<li>Bottleneck Evidence Table。</li>
|
||
</ul>
|
||
<h3>M3:并行拓扑 A/B</h3>
|
||
<p>完成条件:</p>
|
||
<ul>
|
||
<li>TP16 保留基线。</li>
|
||
<li>TP8+PP2 完成可行性与性能验证。</li>
|
||
<li>Attention DP + MoE EP 完成支持性和显存评估。</li>
|
||
</ul>
|
||
<p>交付:</p>
|
||
<ul>
|
||
<li>每种拓扑的显存、通信、TTFT、TPOT 和 TPS 对比。</li>
|
||
<li>推荐拓扑与不推荐拓扑的证据。</li>
|
||
</ul>
|
||
<h3>M4:首轮优化闭环</h3>
|
||
<p>完成条件:</p>
|
||
<ul>
|
||
<li>至少一项优化通过完整 Benchmark。</li>
|
||
<li>结果在无 Profiler 环境下可复现。</li>
|
||
<li>正确性无回归。</li>
|
||
<li>满足 SLO 的吞吐有明确改善。</li>
|
||
</ul>
|
||
<p>期望目标:</p>
|
||
<ul>
|
||
<li>首轮争取获得至少 10% 的 SLO 内吞吐提升,或显著降低 P95/P99 长尾。</li>
|
||
<li>若无法提升,也必须形成排除结论,说明瓶颈为什么不在该方向。</li>
|
||
</ul>
|
||
<h2>16. 实验纪律</h2>
|
||
<p>每次实验都必须回答:</p>
|
||
<ol>
|
||
<li>改了什么?</li>
|
||
<li>为什么认为它会影响当前瓶颈?</li>
|
||
<li>除该变量外,还有什么发生了变化?</li>
|
||
<li>端到端指标如何变化?</li>
|
||
<li>Profile 证据如何变化?</li>
|
||
<li>是否引入精度、稳定性或显存风险?</li>
|
||
<li>是否值得保留?</li>
|
||
</ol>
|
||
<p>禁止以下做法:</p>
|
||
<ul>
|
||
<li>同时修改多个参数后只报告最终 TPS。</li>
|
||
<li>用 Profiling Run 和普通 Run 直接比较性能。</li>
|
||
<li>只看平均值,不看 P95/P99。</li>
|
||
<li>用配置 ISL/OSL 估算 TPS,而不核对实际 token 数。</li>
|
||
<li>用 1 GiB NCCL 带宽代表 Decode 小消息性能。</li>
|
||
<li>因单个 Kernel 更快就宣称端到端优化成功。</li>
|
||
<li>OOM 后不重启服务继续测试。</li>
|
||
</ul>
|
||
<h2>17. 首轮执行建议</h2>
|
||
<p>建议直接按以下顺序推进:</p>
|
||
<ol>
|
||
<li>固化当前 TP16 服务命令和 Manifest。</li>
|
||
<li>先跑九个固定快速地图点,再跑 Decode 背景中注入 128K Prefill 的混合干扰 A/B。</li>
|
||
<li>同步采集 GPU、CPU 和双 Rail 数据。</li>
|
||
<li>对 P3、D2、M1 各捕获 5 到 10 个 Engine Step。</li>
|
||
<li>输出 NCCL、NSA/Attention、MoE、CPU Gap 四项时间占比。</li>
|
||
<li>根据最大暴露时间选择第一个优化方向。</li>
|
||
<li>优先做 TP16 与 TP8+PP2 的可行性和性能对比。</li>
|
||
<li>回到完整 Benchmark 验证 SLO 内吞吐。</li>
|
||
</ol>
|
||
<p>最重要的判定标准是:</p>
|
||
<blockquote>
|
||
<p>优化暴露在关键路径上的时间,而不是只优化看起来最慢的单个算子。</p>
|
||
</blockquote>
|
||
<h2>18. 参考资料</h2>
|
||
<ul>
|
||
<li><a href="https://docs.vllm.ai/en/stable/contributing/profiling/">vLLM Profiling</a></li>
|
||
<li><a href="https://github.com/sgl-project/sglang/blob/main/docs/developer_guide/benchmark_and_profiling.md">SGLang Benchmark and Profiling</a></li>
|
||
<li><a href="https://github.com/sgl-project/sglang/blob/main/docs/advanced_features/server_arguments.md">SGLang Server Arguments</a></li>
|
||
<li><a href="https://docs.nvidia.com/nsight-systems/UserGuide/index.html">NVIDIA Nsight Systems User Guide</a></li>
|
||
<li><a href="https://docs.nvidia.com/nsight-systems/AnalysisGuide/index.html">NVIDIA Nsight Systems Analysis Guide</a></li>
|
||
<li><a href="../hy3_infra_article/Hy3_Preview_AI_Infra_%E7%B2%BE%E8%AF%BB%E7%AC%94%E8%AE%B0.md">腾讯混元 Hy3 Preview AI Infra 精读笔记</a></li>
|
||
</ul>
|
||
|
||
<a class="source-link" href="./推理优化计划.md">打开 Markdown 源文件</a>
|
||
</article>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
const slugCounts = new Map();
|
||
const headings = document.querySelectorAll(
|
||
"#document-content h2, #document-content h3"
|
||
);
|
||
const toc = document.getElementById("toc-list");
|
||
|
||
headings.forEach((heading) => {
|
||
const base = heading.textContent
|
||
.trim()
|
||
.toLowerCase()
|
||
.replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-")
|
||
.replace(/^-|-$/g, "") || "section";
|
||
const count = slugCounts.get(base) || 0;
|
||
slugCounts.set(base, count + 1);
|
||
heading.id = count === 0 ? base : `${base}-${count + 1}`;
|
||
|
||
const link = document.createElement("a");
|
||
link.href = `#${heading.id}`;
|
||
link.textContent = heading.textContent;
|
||
link.dataset.level = heading.tagName.slice(1);
|
||
toc.appendChild(link);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|