sskj/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html

1337 lines
46 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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-08-01 02:45:00 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-Pro16 张 GPU 组成一个完整实例<br>当前约束:模型暂时只能使用全部 16 张 GPU无法额外复制一套模型进行 PD 分离<br>计划版本2026-08-01 02:45: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固定点 11/11、混合 A/B 3/3阶段结果 14/14</td>
<td>
<a href="./phase1_exp.html">打开 Phase 1 实验档案</a><br>
<a href="./phase1_code.html">打开 Phase 1 代码详解</a>
</td>
</tr>
<tr>
<td>DeepSeek-V4-Pro / 双机 Pro6000D / SGLang 硬件与资源竞争归因</td>
<td>Phase 2 已完成;最终 Run 8/8、精确窗口 8/8、采集器 18/18双节点资源已清理</td>
<td>
<a href="./phase2_exp.html">打开 Phase 2 实验档案</a><br>
<a href="./phase2_code.html">打开 Phase 2 代码详解</a>
</td>
</tr>
<tr>
<td>DeepSeek-V4-Pro / 双机 Pro6000D / SGLang RDMA 需求建模与并发拐点</td>
<td>Phase 2.5 已完成Scout 5/5、Confirm 6/6C=16 进入平台,拟合上限 80.32 Gbit/s/rail</td>
<td>
<a href="./phase2_5_exp.html">打开 Phase 2.5 实验档案</a><br>
<a href="./phase2_5_code.html">打开 Phase 2.5 代码详解</a>
</td>
</tr>
</tbody></table>
<p>
<strong>阶段档案生成门禁:</strong>Phase 尚未产出正式阶段结果、完成汇总和汇报确认前,
不创建或维护 <code>phaseN_exp.html</code><code>phaseN_code.html</code>
此时只维护代码、原始结果和本页状态。已有正式阶段结果的 Phase 保留档案,
并在补测后更新;首次达到完成门槛时再一次性生成两份最终 HTML
正文只保留成功实验、有效结果和结论,失败尝试压缩到末尾的经验教训。
</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 连接:
GPU03 与 GPU47 各自在本地 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 微基准;正式数值已写入 Phase 2 实验档案。
</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/&lt;RUN_ID&gt;/
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_exp.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/sTPOT 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>
本阶段已有正式 Run 结果,实验与代码说明见
<a href="./phase2_exp.html">Phase 2 实验档案</a>
<a href="./phase2_code.html">Phase 2 代码详解</a>。本阶段重放长 Prefill、并发 Prefill、
普通 Decode、长输出 Decode、长上下文 Decode以及
<code>1K → 1K, C=32</code> 的混合 A/B。最终 Run
<code>dsv4pro-phase2-20260731-163620</code> 在 28 分 44 秒内完成 8/8 个结果,
正式测量窗口 8/8 精确18/18 个采集器正常启停Head/Worker 的 DCGM、
CPU、NUMA、RDMA 和通信微基准数据均有效。实验后两节点容器、端口和
16 张 GPU 已清理,下一步进入 Phase 3。
</p>
<h3>6.1 最终归因结果</h3>
<ul>
<li>混合负载稳定复现Decode Output TPS 下降 23.96%TPOT P95 增加 66.75%E2E P95 增加 63.38%。</li>
<li>GPU Util 多数为 94%99%,频率稳定在 2.392.42 GHz整机 CPU Active 约 9.6%10.4%,没有全机 CPU 饱和或 GPU 降频。</li>
<li>双 Rail 流量对称且错误增量为 0最高约 83.5 Gbit/s/rail仅约占单条 400G Rail 的 20.9%。</li>
<li>PCIe 跨 NUMA P2P 损失约 2.3%16-GPU AllReduce busbw 约 39.339.7 GB/s。</li>
<li><code>NCCL_CROSS_NIC=0/1/2</code> 差异小于 1%,不再作为主要调优方向。</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>DCGMSM 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>6.5 Phase 2.5RDMA 需求建模与并发拐点</h2>
<p>
Phase 2 已证明当前代表负载最高约 83.5 Gbit/s/rail但单个固定 Case 不能回答
“提高并发后是否还能继续逼近 400G”。Phase 2.5 保持 TP16/EP2 和服务参数不变,
先用 <code>64K → 1</code> 的 C=1/4/16/32/64 隔离 Prefill拟合
<code>rail_gbps ≈ input_tps × bytes_per_input_token_per_rail × 8</code>
再自动选择平台前、拐点和最大稳定并发,对 <code>64K → 1K</code> 重复两次确认。
</p>
<p>
正式 Run <code>dsv4pro-phase2_5-20260801-130007</code> 已完成。64K→1 Scout 在 C=16
达到约 2,984 input tok/s 与 79.90 Gbit/s/railC=32/64 均不再显著增长,拟合
单 Rail 渐近上限为 80.32 Gbit/s。通信强度约为 3.332 MB/input-token/rail
要达到单 Rail 400G 需约 15,006 input tok/s约为当前平台的 5 倍。64K→1K
两轮确认同样在 C=16 后进入平台,说明当前是模型计算/实现吞吐先饱和,而非 RDMA 链路先饱和。
完整方法、逐点结果和证据路径见
<a href="./phase2_5_exp.html">Phase 2.5 实验档案</a>
<a href="./phase2_5_code.html">Phase 2.5 代码详解</a>
</p>
<h2>7. Phase 3时间线 ProfilingNsight 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>只捕获预热后的 10 到 32 个 Engine Step混合场景窗口略长用于覆盖 Prefill 注入前后。</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 &#39;Content-Type: application/json&#39; \
-d &#39;{
&quot;output_dir&quot;: &quot;/data/profile/sglang&quot;,
&quot;start_step&quot;: 5,
&quot;num_steps&quot;: 10,
&quot;activities&quot;: [&quot;CPU&quot;, &quot;GPU&quot;]
}&#39;
</code></pre>
<p>多机 Trace 自动合并要求两台机器能访问同一个共享输出目录。没有共享目录时分别保存,再在本地汇总。</p>
<p>
真正的 Nsight Systems Run 需要在两台节点分别由 <code>nsys</code> 捕获对应
SGLang 进程,并绑定相同 Case ID 和时间窗口。正式执行前先验证容器内外的
<code>nsys</code> 版本、子进程跟踪方式及动态 Capture 机制,再固化命令;
不直接对整轮 Benchmark 做长时间全量捕获。
</p>
<h3>7.4.1 当前实现与正式入口</h3>
<p>
代码已集中在
<code>experiments/pro6000/dsv4pro_pro6000d_2node_sglang_timeline_profiling</code>
仍只有 <code>run_timeline_profiling.sh</code> 一个入口。双节点 PyTorch Profiler
和 Nsight smoke 已通过;正式 Run 尚未执行,因此暂不生成 Phase 3 的
<code>exp/code</code> HTML 档案。
</p>
<table>
<thead><tr><th>Case</th><th>负载</th><th>动态窗口</th></tr></thead>
<tbody>
<tr><td>Decode Control</td><td>1K → 1KC=32</td><td>确认 Decode 活跃后跳过 2 Step捕获 16 Step</td></tr>
<tr><td>Mixed Treatment</td><td>1K → 1KC=32 背景 + 128K → 1 注入</td><td>先保留 2 个纯 Decode Step再注入 Prefill总计捕获 32 Step</td></tr>
<tr><td>Long Prefill</td><td>128K → 1C=1</td><td>从首个 Chunk 开始捕获 16 Step</td></tr>
</tbody>
</table>
<p>
三段正式范围复用一次模型加载,因此 Nsight 使用
<code>--capture-range-end=repeat:3:defer</code>。它与官方单段示例中的
<code>stop</code> 目的相同,但允许同一个服务依次产出三段独立报告。
</p>
<pre><code class="language-bash"># 只在 Head 174.1.51.5 执行
cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_timeline_profiling
RUN_ID=dsv4pro-phase3-$(date +%Y%m%d-%H%M%S)
tmux new-session -d -s dsv4pro-phase3 \
"RUN_ID=${RUN_ID} bash run_timeline_profiling.sh all \
2&gt;&amp;1 | tee /data/hzy/${RUN_ID}.log"
tmux attach -t dsv4pro-phase3
</code></pre>
<h3>7.5 时间线必须回答的问题</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.6 报告分析</h3>
<pre><code class="language-bash">nsys stats &lt;REPORT&gt;.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 ATP16 基线</h3>
<p>当前方案用于建立所有后续实验的对照。</p>
<p>风险是每层 TP Collective 都可能跨越两台机器Decode 小消息通信尤其容易被延迟支配。</p>
<h3>9.2 BTP8 + 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 CAttention 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 6Kernel 专项</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 7Scheduler 与统一实例干扰</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 9MTP 与模型级优化</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>