2026-07-31 18:43:30 +08:00

812 lines
43 KiB
HTML
Raw 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">
<title>Phase 2DeepSeek-V4-Pro 双机 Pro6000D SGLang 硬件与资源竞争归因</title>
<style>
:root {
color-scheme: light;
--ink: #18202a;
--muted: #5b6570;
--line: #d8dde3;
--paper: #ffffff;
--page: #f3f5f7;
--blue: #1769aa;
--green: #16734a;
--amber: #9a5a00;
--red: #a13232;
--code: #f0f3f6;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--page);
color: var(--ink);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-size: 16px;
line-height: 1.65;
}
header {
background: #202a34;
color: #fff;
border-bottom: 5px solid #34a17a;
}
.header-inner, main {
width: min(1120px, calc(100% - 32px));
margin: 0 auto;
}
.header-inner { padding: 38px 0 32px; }
h1, h2, h3 { letter-spacing: 0; }
h1 {
margin: 4px 0 12px;
font-size: clamp(26px, 4vw, 42px);
line-height: 1.2;
}
h2 {
margin: 38px 0 12px;
padding-bottom: 7px;
border-bottom: 2px solid var(--line);
font-size: 24px;
}
h3 { margin: 26px 0 8px; font-size: 19px; }
.eyebrow {
margin: 0;
color: #8fd8bd;
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
}
.meta {
display: flex;
flex-wrap: wrap;
gap: 8px 22px;
color: #d7dee5;
font-size: 14px;
}
main {
margin-top: 24px;
margin-bottom: 48px;
padding: 30px 38px 42px;
background: var(--paper);
border: 1px solid var(--line);
border-radius: 6px;
}
.status {
padding: 14px 16px;
border-left: 4px solid var(--amber);
background: #fff7e7;
}
.decision {
padding: 14px 16px;
border-left: 4px solid var(--green);
background: #eef8f3;
}
a { color: var(--blue); }
.back {
display: inline-block;
margin-bottom: 10px;
font-weight: 650;
}
code {
padding: 1px 5px;
background: var(--code);
border-radius: 3px;
font-family: "SFMono-Regular", Consolas, monospace;
font-size: 0.92em;
}
pre {
overflow-x: auto;
padding: 14px 16px;
background: #202a34;
color: #f4f7fa;
border-radius: 5px;
line-height: 1.5;
}
pre code { padding: 0; background: transparent; color: inherit; }
table {
width: 100%;
margin: 14px 0 22px;
border-collapse: collapse;
font-size: 14px;
}
th, td {
padding: 10px 11px;
border: 1px solid var(--line);
text-align: left;
vertical-align: top;
}
th { background: #edf1f4; }
.pass { color: var(--green); font-weight: 700; }
.pending { color: var(--amber); font-weight: 700; }
.fail { color: var(--red); font-weight: 700; }
li + li { margin-top: 5px; }
@media (max-width: 720px) {
main { padding: 22px 18px 30px; }
table { display: block; overflow-x: auto; white-space: nowrap; }
}
</style>
</head>
<body>
<header>
<div class="header-inner">
<p class="eyebrow">Design, Implementation &amp; Result Record</p>
<h1>Phase 2DeepSeek-V4-Pro 双机 Pro6000D SGLang 硬件与资源竞争归因</h1>
<div class="meta">
<span>节点174.1.51.5 + 174.1.51.7</span>
<span>拓扑SGLang TP16 / EP2</span>
<span>更新2026-07-31 17:22:20 CST</span>
</div>
</div>
</header>
<main>
<a class="back" href="./推理优化计划.html">返回推理优化主计划</a>
<a class="back" href="./phase2_code.html">打开 Phase 2 代码详解</a>
<p class="status">
<strong>当前状态Phase 2 已完成。</strong>
最终 Run <code>dsv4pro-phase2-20260731-163620</code> 在 28 分 44 秒内完成
8/8 个 benchmark正式测量窗口 8/8 精确18/18 个采集器正常启停。
Head/Worker 的 DCGM、CPU、NUMA、双 Rail RDMA 和通信微基准证据均有效;
实验结束后两节点容器、服务端口和 16 张 GPU 已清理。
</p>
<h2>1. Phase 1 交接结果</h2>
<table>
<thead>
<tr><th>代表负载</th><th>关键结果</th><th>Phase 2 用途</th></tr>
</thead>
<tbody>
<tr><td>128K → 1C=1</td><td>Input TPS 2,710.16TTFT P95 48.344 s</td><td>纯长 Prefill 的计算、显存与通信归因</td></tr>
<tr><td>32K → 1C=16</td><td>Input TPS 3,112.77TTFT P95 162.087 s</td><td>并发 Prefill 的排队、Chunk 调度与节点均衡</td></tr>
<tr><td>1K → 1KC=32</td><td>Output TPS 461.68TPOT P95 63.31 ms</td><td>普通 Decode 的 GPU、CPU 与通信基线</td></tr>
<tr><td>1K → 4KC=16</td><td>Output TPS 310.02TPOT P95 50.33 ms</td><td>持续 Decode、KV 增长和稳态资源占用</td></tr>
<tr><td>128K → 1KC=1</td><td>TTFT P95 49.326 sTPOT P95 32.24 ms</td><td>分离长 Prefill 与长上下文 Decode 成本</td></tr>
<tr><td>1K → 1KC=32 + 128K 注入</td><td>Output TPS -24.08%TPOT P95 +66.55%</td><td>Prefill 干扰 Decode 时的硬件资源竞争</td></tr>
</tbody>
</table>
<p>
最终基线已由 Head 与 Worker 日志证明使用
<code>mlx5_0/mlx5_3</code> 双 Rail <code>NET/IB + GDRDMA</code>
正式测量请求为冷 Prefix。正式矩阵 12/12、长 Decode 补测 2/2 均成功。
Phase 2 保持相同服务配置和请求口径。
</p>
<h2>2. 本阶段的边界</h2>
<ul>
<li>只测试 SGLang不测试 vLLM。</li>
<li>保留模型、镜像、TP16、EP2、显存比例和已验证的双 Rail NCCL 配置。</li>
<li>模型端到端 Case 不启用 Nsight Systems、PyTorch Profiler、NCCL DEBUG 或投机解码;独立通信基线临时启用 NCCL INFO 以保存实际路径证据。</li>
<li>不调参,不尝试优化;先获得足以区分瓶颈类别的硬件证据。</li>
<li>只重放五个固定代表负载和一组混合 A/B不重复 Phase 1 全矩阵。</li>
<li>采集器从请求开始前启动,到请求结束后停止,不能中途补采后声称完整。</li>
</ul>
<h2>3. 待验证假设</h2>
<table>
<thead>
<tr><th>假设</th><th>预期硬件表现</th><th>后续方向</th></tr>
</thead>
<tbody>
<tr><td>DSV4/NSA Prefill Kernel 计算受限</td><td>GPU 持续忙、高功耗和稳定频率;双 Rail 流量不高</td><td>Phase 3 捕获 Kernel 与 Attention/Indexer 时间线</td></tr>
<tr><td>权重或激活显存带宽受限</td><td>GPU Memory Utilization 高SM 指标未必饱和;功耗可能低于纯计算</td><td>补 DCGM/Profiler 的 DRAM Active再看 Kernel</td></tr>
<tr><td>TP16 跨机通信受限</td><td>RoCE 吞吐高或两条 Rail 明显失衡GPU 出现等待</td><td>NCCL_CROSS_NIC 0/1/2 快速 A/B随后看 NCCL Timeline</td></tr>
<tr><td>CPU Scheduler 或 Kernel Launch 受限</td><td>GPU 利用率锯齿或有空洞,单 CPU 核持续满载</td><td>定位 Scheduler/Tokenizer 线程与 launch gap</td></tr>
<tr><td>频率、功耗或温度限制</td><td>P-state、SM Clock 或 Power 持续异常,可能出现节流原因</td><td>修正电源、散热或 Clock Policy 后复测</td></tr>
<tr><td>节点或 Rank 不均衡</td><td>两节点或不同 GPU 的利用率、功耗、网络流量存在固定偏差</td><td>检查 NUMA、GPU-NIC 亲和与慢 Rank</td></tr>
</tbody>
</table>
<h2>4. 诊断 Run</h2>
<ol>
<li>确认 16 张 GPU 空闲,先跑两节点 PCIe P2P、单机 8 rank AllReduce 和双机 16 rank AllReduce双机分别测试 <code>NCCL_CROSS_NIC=0/1/2</code></li>
<li>保存两节点静态快照GPU/NIC/NUMA 拓扑、驱动、CUDA、镜像与服务命令。</li>
<li>复用 Phase 1 已验证的 <code>run_quick_map.sh start</code> 启动同配置双机服务。</li>
<li>在 Head 和 Worker 同时启动 GPU、CPU、网卡与 RDMA 采样,先记录 15 秒空闲基线。</li>
<li>依次重放 <code>128K → 1, C=1</code><code>32K → 1, C=16</code><code>1K → 1K, C=32</code></li>
<li>重放 <code>1K → 4K, C=16</code><code>128K → 1K, C=1</code>,观察持续与长上下文 Decode。</li>
<li>重放 <code>1K → 1K, C=32</code> Control 与 128K Prefill 注入 Treatment保留相同注入时序。</li>
<li>请求结束后继续采样 15 秒,再停止采集器和服务。</li>
<li>按时间戳将请求、GPU、CPU 和双 Rail 指标对齐,生成摘要与判定。</li>
</ol>
<pre><code>idle 15s
│ 128K→1 C1 │ 32K→1 C16 │ 1K→1K C32
│ 1K→4K C16 │ 128K→1K C1
│ Decode Control │ Decode + Prefill
cooldown 15s
Head 与 Worker 的所有采集器覆盖完整诊断窗口。</code></pre>
<p>
Phase 1 中服务加载约 5 分 30 秒;通信基线、五个固定负载、混合 A/B、
静态快照、采样和清理组成一次完整 Phase 2 Run。
</p>
<h3>4.1 你只需要运行的入口</h3>
<p class="decision">
<strong>操作规则:先在 Worker <code>.7</code> 做一次 DCGM 准备,再只在
Head <code>.5</code> 执行 Phase 2 的 <code>all</code></strong>
不要手工执行 Phase 1 的 <code>start</code><code>stop</code>
Phase 2 会在内部复用它们并负责异常退出时的采集器、Head、Worker 清理。
</p>
<pre><code class="language-bash"># [仅在 Worker 174.1.51.7 执行一次]
# 不需要 source、conda activate也不要在 .7 运行 Phase 2 的 all
systemctl start nvidia-dcgm
systemctl is-active nvidia-dcgm
dcgmi discovery -l
# 预期:第二条输出 active第三条列出本机 8 张 GPU
# [以下仅在 Head 174.1.51.5 执行]
cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution
# 第一次先展开全部命令,不启动服务、不占用 GPU、不发送请求
DRY_RUN=1 RUN_ID=dsv4pro-phase2-dryrun-$(date +%Y%m%d-%H%M%S) \
bash run_hardware_contention_attribution.sh all
# 正式实验:仍然只有同一个 all 入口tmux 只负责断线后继续运行
RUN_ID=dsv4pro-phase2-$(date +%Y%m%d-%H%M%S)
tmux new-session -d -s dsv4pro-phase2 \
"RUN_ID=${RUN_ID} bash run_hardware_contention_attribution.sh all \
2&gt;&amp;1 | tee /data/hzy/${RUN_ID}.log"
tmux attach -t dsv4pro-phase2</code></pre>
<p>
<code>.7</code> 的三条命令只负责让 Worker DCGM Host Engine 可用;
SGLang Worker、其余采集器和结果回收仍由 <code>.5</code> 的唯一入口通过 SSH 管理。
若需要机器重启后自动启动 DCGM应由运维另行决定是否执行
<code>systemctl enable nvidia-dcgm</code>
</p>
<p><strong><code>all</code> 内部执行顺序:</strong></p>
<pre><code>配置、工具、DCGM 与 GPU 空闲门禁
→ 通信基线:两节点 P2P、两组单机 8-rank AllReduce、
三组双机 16-rank NCCL_CROSS_NIC A/B
→ Phase 1 start启动同配置 TP16 服务
→ 两节点静态快照
→ 启动两节点采集器并记录 15 秒 idle
→ 五个固定 Case
→ 混合 Prefill/Decode A/B
→ 15 秒 cooldown
→ 停止采集器并保存后快照
→ Phase 1 stop停止 Head/Worker
→ 生成按第 5 节逐项对应的 CSV、JSON 与 report.md</code></pre>
<p>
Phase 1 的作用是提供已经验证过的双机 Docker 服务和 Benchmark 实现,
不是第二个用户入口。实际展开的服务、Benchmark 和采集命令都会写入
<code>results/&lt;RUN_ID&gt;/service/</code><code>commands/</code>
<code>head|worker/collector_commands/</code>,不依赖跨文档猜测。
</p>
<h2>5. 采集指标</h2>
<p>
本节记录正式实现使用的命令,而不是建议性伪代码。命令由
<code>run_hardware_contention_attribution.sh</code> 在 Head 和 Worker 同时启动;
每条展开后的命令会另外保存在
<code>results/&lt;RUN_ID&gt;/head|worker/collector_commands/</code>
</p>
<table>
<thead>
<tr><th>层级</th><th>连续采样</th><th>静态或前后快照</th></tr>
</thead>
<tbody>
<tr><td>GPU</td><td>利用率、Memory Utilization、显存、功耗、SM/Memory Clock、温度、P-state</td><td><code>nvidia-smi topo -m</code>、Compute Process</td></tr>
<tr><td>CPU</td><td>每核利用率、上下文切换、服务进程 CPU/内存</td><td>NUMA 拓扑、容器 PID 与 CPU Affinity</td></tr>
<tr><td>Network</td><td><code>eth0/eth3</code> RX/TX</td><td><code>ethtool -S</code> 错误计数前后差</td></tr>
<tr><td>RDMA</td><td><code>mlx5_0/mlx5_3</code> port_xmit/recv_data 差分</td><td>Port State、GID 与错误计数</td></tr>
<tr><td>DCGM</td><td>SM Active、DRAM Active、Tensor Active、PCIe</td><td>工具版本与可用 Field</td></tr>
</tbody>
</table>
<h3>5.1 时间对齐与 Case Marker</h3>
<pre><code class="language-bash"># 每条 GPU/RDMA 样本写入相同格式的宿主机墙钟时间
date +%s%N
# 实验前检查两节点秒级时钟差
date +%s
# Case 开始、结束和服务状态由 Python 写入 markers.csv
python3 hardware_contention_attribution.py marker \
--path markers.csv \
--node head \
--event case_start \
--case-id long_prefill_latency_128k_c1</code></pre>
<table>
<thead><tr><th>数据</th><th>含义</th><th>为什么需要</th></tr></thead>
<tbody>
<tr><td><code>wall_time_ns</code></td><td>Unix Epoch 纳秒时间</td><td>把 GPU、CPU、RDMA 与 Benchmark 放到同一时间轴</td></tr>
<tr><td><code>case_start/case_end</code></td><td>一个 Case 的编排边界</td><td>从整段连续采样中切出对应负载</td></tr>
<tr><td><code>CLOCK_SKEW_TOLERANCE_S=2</code></td><td>两节点允许的最大秒级时钟差</td><td>避免 Head/Worker 的同一时刻被错位比较</td></tr>
</tbody>
</table>
<p>
最终实现由 Phase 1 监听 <code>bench.log</code> 中的
<code>Starting main benchmark run</code>,立刻写入
<code>measurement_start.json</code>;再使用 SGLang <code>bench.json</code>
的正式 benchmark duration 计算结束时间。Phase 2 优先读取
<code>measurement_started_at/measurement_ended_at</code>,不会把数据生成和
Warm-up 混入硬件均值。<code>REQUIRE_PRECISE_WINDOWS=1</code> 时,任何 Case
缺少精确窗口都会让汇总失败,而不是悄悄回退。
</p>
<h3>5.2 GPU 基础状态:<code>nvidia-smi</code></h3>
<pre><code class="language-bash">nvidia-smi \
--query-gpu=index,timestamp,utilization.gpu,utilization.memory,\
memory.used,memory.total,power.draw,temperature.gpu,\
clocks.sm,clocks.mem,pstate \
--format=csv,noheader,nounits</code></pre>
<p>脚本每秒运行一次,并在每行前加入 <code>wall_time_ns</code> 和节点角色。</p>
<table>
<thead><tr><th>字段</th><th>代表什么</th></tr></thead>
<tbody>
<tr><td><code>utilization.gpu</code></td><td>采样周期内至少有一个 Kernel 在执行的时间比例</td></tr>
<tr><td><code>utilization.memory</code></td><td>采样周期内显存控制器处于忙碌状态的时间比例</td></tr>
<tr><td><code>memory.used/total</code></td><td>当前总显存分配量与设备显存容量</td></tr>
<tr><td><code>power.draw</code></td><td>GPU 当前功耗,用于比较不同负载的能耗状态</td></tr>
<tr><td><code>clocks.sm/clocks.mem</code></td><td>SM 与显存当前工作频率</td></tr>
<tr><td><code>pstate</code></td><td>GPU 性能状态P0 通常是最高性能态</td></tr>
</tbody>
</table>
<p>
原始输出为 <code>head|worker/gpu_samples.csv</code>
<code>gpu_summary.csv</code> 汇总整段运行,
<code>case_gpu_summary.csv</code> 按节点、Case 和 GPU 汇总平均值与峰值。
</p>
<h3>5.3 GPU Profiling CounterDCGM</h3>
<pre><code class="language-bash">DCGM_FIELD_IDS=1001,1002,1003,1004,1005,1009,1010
dcgmi dmon \
-e 1001,1002,1003,1004,1005,1009,1010 \
-d 1000</code></pre>
<table>
<thead><tr><th>Field ID</th><th>Field Tag</th><th>含义</th></tr></thead>
<tbody>
<tr><td>1001</td><td><code>gr_engine_active</code></td><td>Graphics/Compute Engine 活跃比例,接近整体 GPU 执行忙碌度</td></tr>
<tr><td>1002</td><td><code>sm_active</code></td><td>SM 至少有一个 Warp 活跃的比例</td></tr>
<tr><td>1003</td><td><code>sm_occupancy</code></td><td>活跃 Warp 相对硬件可容纳 Warp 的比例</td></tr>
<tr><td>1004</td><td><code>tensor_active</code></td><td>Tensor Core 指令活跃比例</td></tr>
<tr><td>1005</td><td><code>dram_active</code></td><td>设备显存接口活跃比例Pro6000D 为 GDDR7用于判断设备显存带宽压力</td></tr>
<tr><td>1009</td><td><code>pcie_tx_bytes</code></td><td>GPU 经 PCIe 发出的字节速率</td></tr>
<tr><td>1010</td><td><code>pcie_rx_bytes</code></td><td>GPU 经 PCIe 接收的字节速率</td></tr>
</tbody>
</table>
<p>
<code>sm_active</code> 高而 <code>sm_occupancy</code> 低,表示 SM 经常有工作,
但同时驻留的 Warp 不多;后续通过 Kernel Timeline 区分小 Kernel、
寄存器/共享内存约束和同步。DCGM 是 NVIDIA Data Center GPU Manager
<code>nvidia-dcgm</code>/<code>nv-hostengine</code> 是后台 Host Engine
<code>dcgmi</code> 是客户端Field ID 是指标编号。最终代码在两节点预检
<code>dcgmi discovery -l</code>,任一 Host Engine 不可用即 fail-fast
正式结果必须同时包含 Head 和 Worker 的 <code>case_dcgm_summary.csv</code>
</p>
<h3>5.4 CPU、进程与 Kernel Launch 侧证据</h3>
<pre><code class="language-bash"># 全部逻辑 CPU每 5 秒输出一次
mpstat -P ALL 5
# 找到容器内进程对应的宿主 PID
docker top &lt;container&gt; -eo pid,ppid,psr,pcpu,pmem,stat,comm,args
# 最终命令:进程级 CPU、I/O、缺页、上下文切换不展开全部线程
pidstat -durw -p "&lt;comma-separated-host-pids&gt;" 5
# 每 5 秒输出一次硬件/软件计数器增量
perf stat -p "&lt;comma-separated-host-pids&gt;" -I 5000 \
-e cycles,instructions,cache-misses,context-switches,\
cpu-migrations,page-faults
# mpstat/pidstat/perf 每行都由包装器增加:
# wall_time_ns TAB node TAB 原始输出</code></pre>
<table>
<thead><tr><th>命令/字段</th><th>回答的问题</th></tr></thead>
<tbody>
<tr><td><code>mpstat -P ALL</code></td><td>整机是否 CPU 饱和,是否只有少量核心接近 100%,是否存在 I/O Wait</td></tr>
<tr><td><code>docker top</code></td><td>把容器进程映射为宿主 PID、CPU 核 <code>PSR</code> 和进程状态</td></tr>
<tr><td><code>pidstat -u</code></td><td>服务进程的用户态、内核态 CPU 时间</td></tr>
<tr><td><code>pidstat -d</code></td><td>进程块设备 I/O</td></tr>
<tr><td><code>pidstat -r</code></td><td>内存和 Page Fault 行为</td></tr>
<tr><td><code>pidstat -w</code></td><td>主动/被动上下文切换,辅助发现线程阻塞或调度抖动</td></tr>
<tr><td><code>perf cycles/instructions</code></td><td>CPU 周期与指令执行量,可计算近似 IPC</td></tr>
<tr><td><code>cache-misses/migrations</code></td><td>CPU Cache 压力和线程跨核迁移</td></tr>
</tbody>
</table>
<p>
最终实现使用进程级 5 秒采样,避免首轮线程级 1 秒采样产生数百 MB 日志。
<code>case_cpu_summary.csv</code><code>case_process_summary.csv</code>
<code>case_perf_summary.csv</code> 都按正式测量窗口切片;只有先发现异常进程,
才在后续短窗口单独开启线程级采样。
</p>
<h3>5.5 NUMA 与 CPU/内存亲和</h3>
<pre><code class="language-bash"># 静态 NUMA 节点、CPU 和内存布局
numactl --hardware
numastat -m
# 每 5 秒按容器宿主 PID 查看本地/远端 NUMA 内存
numastat -p &lt;host-pid&gt;
# 解析为:
# wall_time_ns,node,node0_mib,node1_mib,total_mib,process_count
# 同时保存 GPU、CPU、NIC 的拓扑关系
nvidia-smi topo -m</code></pre>
<p>
NUMA 是多路 CPU 机器的“本地内存”结构。进程长期从远端 NUMA Node 取内存,
或 GPU/NIC 对应的 CPU 线程被调度到另一侧,可能增加 Host 侧延迟。
最终采集器把 <code>numastat -p</code> 解析为
<code>numa_samples.csv</code>,再按正式测量窗口生成
<code>case_numa_summary.csv</code>。这样可以直接比较 Node0/Node1 MiB
而不是依靠人工阅读不断刷新的文本。
</p>
<h3>5.6 普通网卡统计与 RDMA 数据面</h3>
<pre><code class="language-bash"># Linux netdev 层,每 5 秒采样吞吐与错误
sar -n DEV,EDEV 5
# Case 前后保存物理端口状态和驱动计数器
ethtool eth0
ethtool eth3
ethtool -S eth0
ethtool -S eth3
# RDMA 设备与端口状态
ibdev2netdev
ibstat
rdma link show</code></pre>
<p>
<code>sar</code> 记录 Linux 普通网络栈中的 <code>eth0/eth3</code> 流量;
GDRDMA 数据量由 <code>mlx5_0/mlx5_3</code> HCA 的 sysfs Counter 记录:
</p>
<pre><code class="language-bash">for hca in mlx5_0 mlx5_3; do
base="/sys/class/infiniband/${hca}/ports/1"
cat "${base}/counters/port_xmit_data"
cat "${base}/counters/port_rcv_data"
cat "${base}/counters/port_xmit_wait"
cat "${base}/counters/port_xmit_discards"
cat "${base}/counters/port_rcv_errors"
cat "${base}/hw_counters/req_transport_retries_exceeded"
cat "${base}/hw_counters/req_rnr_retries_exceeded"
done</code></pre>
<table>
<thead><tr><th>Counter</th><th>含义</th></tr></thead>
<tbody>
<tr><td><code>port_xmit_data/port_rcv_data</code></td><td>HCA 发送/接收数据累计量IB Counter 单位是 4 Octets脚本用 <code>delta × 4 × 8 / seconds</code> 换算 Gbit/s</td></tr>
<tr><td><code>port_xmit_wait</code></td><td>端口因缺少发送 Credit 等原因等待的时间,持续增长可能指向拥塞</td></tr>
<tr><td><code>port_xmit_discards/port_rcv_errors</code></td><td>发送丢弃和接收错误增量</td></tr>
<tr><td><code>req_transport_retries_exceeded</code></td><td>RDMA Transport 重试耗尽</td></tr>
<tr><td><code>req_rnr_retries_exceeded</code></td><td>Receiver Not Ready 重试耗尽</td></tr>
<tr><td><code>roce_adp_retrans*</code></td><td>RoCE 自适应重传及超时相关计数</td></tr>
<tr><td><code>np_ecn_marked* / *cnp*</code></td><td>ECN 标记和拥塞通知包,用于辅助判断 RoCE 拥塞</td></tr>
</tbody>
</table>
<p>
原始数据为 <code>head|worker/rdma.csv</code>
<code>case_rdma_summary.csv</code> 按 Case、节点和 HCA 计算吞吐及错误增量。
它说明双 Rail 的实际流量、均衡性和错误增量;
<code>case_netdev_summary.csv</code> 同时保留 Linux netdev 层的
<code>eth0/eth3</code> RX/TX 与错误。Phase 3 再把 NCCL Collective
放到请求 Timeline 中分析持续时间和计算重叠。
</p>
<h3>5.7 机内 PCIe 与 NCCL 通信基线</h3>
<pre><code class="language-bash"># 由 all 入口自动执行;不需要用户手工运行 torchrun
# 每个节点:所有 GPU 源/目标对FP16 256 MiB CUDA P2P copy
python3 communication_baseline.py p2p \
--size 256M --warmup 3 --iterations 10
# 每个节点8 rank NCCL AllReduce
torchrun --standalone --nproc-per-node=8 \
communication_baseline.py all-reduce \
--sizes 1M,64M,1G --repetitions 3 --warmup 5 --iterations 10
# 双节点16 rank分别设置 NCCL_CROSS_NIC=0、1、2
torchrun --nnodes=2 --nproc-per-node=8 \
--master-addr 10.101.0.11 --node-rank &lt;0-or-1&gt; \
communication_baseline.py all-reduce \
--sizes 1M,64M,1G --repetitions 3 --warmup 5 --iterations 10</code></pre>
<p>
P2P 结果按 <code>same_pcie_switch</code>PIX
<code>cross_numa_sys</code>SYS分别汇总不用一个平均值掩盖跨 CPU 路径。
AllReduce 同时报告 P50/P95 latency、<code>algbw</code>
<code>busbw</code>、正确性错误数和实际 NCCL 路径。1 MiB、64 MiB、1 GiB
分别覆盖小消息延迟、中等消息和大消息带宽;双机 A/B 直接给出
<code>NCCL_CROSS_NIC=0/1/2</code> 的数值比较。
</p>
<h3>5.8 静态快照与结果关系</h3>
<pre><code class="language-bash">nvidia-smi
nvidia-smi topo -m
lscpu
numactl --hardware
ip -details link show eth0
ip -details link show eth3
docker inspect &lt;container&gt;
docker top &lt;container&gt; -eo pid,ppid,psr,pcpu,pmem,stat,comm,args</code></pre>
<table>
<thead><tr><th>结果文件</th><th>内容</th><th>主要用途</th></tr></thead>
<tbody>
<tr><td><code>static_before.log / static_after.log</code></td><td>GPU、CPU、NUMA、NIC、RDMA、容器前后快照</td><td>证明运行环境,并比较错误计数和清理状态</td></tr>
<tr><td><code>collector_status.csv</code></td><td>每个采集器的启动、停止或提前退出状态</td><td>防止把缺失采集器当作 0 值</td></tr>
<tr><td><code>case_windows.csv</code></td><td>每个 Benchmark Case 的起止时间</td><td>从连续硬件日志中切片</td></tr>
<tr><td><code>bench_summary.csv</code></td><td>TPS、TTFT、TPOT、ITL、E2E</td><td>把硬件现象与用户侧性能对应</td></tr>
<tr><td><code>case_gpu_summary.csv</code></td><td>每 Case、节点、GPU 的利用率、显存、功耗、频率</td><td>比较负载与节点/GPU 不均衡</td></tr>
<tr><td><code>case_dcgm_summary.csv</code></td><td>每 Case、节点、GPU 的 SM/Tensor/显存接口/PCIe 指标</td><td>区分计算、设备显存和 PCIe 活跃度</td></tr>
<tr><td><code>case_cpu_summary.csv</code></td><td>整机与逐核 CPU 利用率、I/O Wait</td><td>识别整机饱和和少数热点核</td></tr>
<tr><td><code>case_process_summary.csv</code></td><td>服务进程 CPU、I/O、缺页、内存与上下文切换</td><td>定位 Host 进程开销与阻塞</td></tr>
<tr><td><code>case_perf_summary.csv</code></td><td>cycles、instructions、cache miss、迁移与缺页</td><td>计算 IPC 并判断 Cache/调度压力</td></tr>
<tr><td><code>case_numa_summary.csv</code></td><td>Node0/Node1 进程内存分布</td><td>识别跨 NUMA 放置</td></tr>
<tr><td><code>case_netdev_summary.csv</code></td><td><code>eth0/eth3</code> 吞吐与错误</td><td>与 RDMA HCA Counter 做分层核对</td></tr>
<tr><td><code>case_rdma_summary.csv</code></td><td>每 Case、节点、Rail 的吞吐和错误增量</td><td>判断双 Rail 使用、均衡和数据面错误</td></tr>
<tr><td><code>communication_summary.csv</code></td><td>每次 P2P/AllReduce 原始测量</td><td>保留每条 GPU 对、消息尺寸、CROSS_NIC 和重复实验</td></tr>
<tr><td><code>communication_aggregate.csv</code></td><td>PIX/SYS P2P 与单/双机 AllReduce 聚合</td><td>提供 P50/P95、algbw、busbw 和正确性比较</td></tr>
</tbody>
</table>
<h3>5.9 最终结果如何逐项汇报</h3>
<p class="decision">
最终 <code>report.md</code> 的章节顺序与本节一一对应。每一项必须同时给出
<strong>原始文件、有效样本数、Head/Worker 数值、Case 间变化和解释</strong>
不能只写“GPU 较忙”“网络未饱和”这类抽象结论。
</p>
<table>
<thead><tr><th>第 5 节指标</th><th>报告中的数值</th><th>最小分析动作</th></tr></thead>
<tbody>
<tr><td>5.1 时间窗</td><td>窗口来源、开始/结束、duration、采样数</td><td>确认全部为 <code>bench_main_marker_plus_duration</code></td></tr>
<tr><td>5.2 GPU</td><td>利用率/显存/功耗/频率的 Mean、P95、Max</td><td>比较两节点、8 卡离散度和不同 Case</td></tr>
<tr><td>5.3 DCGM</td><td>SM Active/Occupancy、Tensor/DRAM Active、PCIe TX/RX</td><td>比较计算、设备显存和 PCIe 哪一侧随负载上升</td></tr>
<tr><td>5.4 CPU/进程/perf</td><td>整机/热点核、进程 CPU/I/O/缺页/切换、IPC/Cache miss</td><td>区分整机容量、单线程热点和 Host 调度开销</td></tr>
<tr><td>5.5 NUMA</td><td>Node0/Node1 MiB 与比例</td><td>比较服务内存是否偏离 GPU/NIC 所在 NUMA</td></tr>
<tr><td>5.6 Network/RDMA</td><td>eth0/eth3、mlx5_0/mlx5_3 Gbit/s 与错误增量</td><td>计算双 Rail 均衡比例并核对丢弃/重试</td></tr>
<tr><td>5.7 Communication</td><td>PIX/SYS P2P、8/16 rank AllReduce P50/P95、algbw/busbw</td><td>比较跨 NUMA 损失与 CROSS_NIC 0/1/2</td></tr>
</tbody>
</table>
<p>
某个采集器无数据时报告显示 <code>-</code> 并附失败状态,不会把缺失值写成
<code>0</code>。正式 Run 默认 <code>ALLOW_PARTIAL_COLLECTORS=0</code>
因此必需采集器提前退出会让 Run 失败。
</p>
<h2>6. 精简代码设计</h2>
<p>已新增目录:</p>
<pre><code>/data/hzy/sskj/experiments/pro6000/
dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/</code></pre>
<table>
<thead>
<tr><th>文件</th><th>职责</th><th>当前状态</th></tr>
</thead>
<tbody>
<tr><td><code>run_hardware_contention_attribution.sh</code></td><td>唯一 Shell 入口;按 Run 分发通信代码、通信基线、服务启停、双节点采集器、Case 编排、门禁和 Trap 清理</td><td class="pass">已实现</td></tr>
<tr><td><code>config.env</code></td><td>Phase 1 相对路径、节点、代表 Case、分层采样周期、通信基线与 fail-closed 策略</td><td class="pass">已实现</td></tr>
<tr><td><code>communication_baseline.py</code></td><td>CUDA P2P 全矩阵与 PyTorch/NCCL 8/16-rank AllReduce 微基准</td><td class="pass">已实现</td></tr>
<tr><td><code>hardware_contention_attribution.py</code></td><td>精确窗口、全部采集器解析、逐 Case 汇总、通信聚合和逐指标报告</td><td class="pass">已实现</td></tr>
<tr><td><code>tests/test_hardware_contention_attribution.py</code></td><td>Worker 无仓库依赖、GPU/RDMA、精确窗口、DCGM/CPU 解析、通信聚合和结果生成测试</td><td class="pass">9/9 通过</td></tr>
<tr><td><code>README.md</code></td><td>唯一入口、范围和结果目录说明</td><td class="pass">已实现</td></tr>
</tbody>
</table>
<p class="decision">
Phase 2 不复制双机 Docker 启停实现。唯一入口在内部调用 Phase 1 的
<code>run_quick_map.sh start/fixed/mixed/stop</code>,只新增通信基线、硬件采集、时间对齐和代表负载编排。
顶层仍只保留一个 Shell 文件,不创建额外 tmux、launch、start 或 stop 脚本。
</p>
<h2>7. 结果结构</h2>
<pre><code>results/&lt;RUN_ID&gt;/
manifest.json
run.log
bench/
bench_cmd.txt
bench.log
bench.jsonl
service/
head_server_cmd.txt
worker_server_cmd.txt
head_server.log
worker_server.log
communication/
communication_baseline.py
communication_baseline.sha256
p2p_head.log
p2p_worker.log
allreduce_head_8gpu.log
allreduce_worker_8gpu.log
allreduce_two_node_x0.log
allreduce_two_node_x1.log
allreduce_two_node_x2.log
head/
gpu_samples.csv
dcgm_dmon.log
mpstat.log
pidstat.log
sar_net.log
perf_stat.log
docker_top.log
numa_samples.csv
rdma.csv
static_before.log
static_after.log
collector_commands/
worker/
...
collector_status.csv
markers.csv
bench_summary.csv
gpu_summary.csv
rdma_summary.csv
case_windows.csv
communication_summary.csv
communication_aggregate.csv
case_gpu_summary.csv
case_gpu_node_summary.csv
case_dcgm_summary.csv
case_cpu_summary.csv
case_process_summary.csv
case_perf_summary.csv
case_numa_summary.csv
case_netdev_summary.csv
case_rdma_summary.csv
summary.json
report.md</code></pre>
<h2>8. 最终验收</h2>
<ul>
<li class="pass">最终 Run <code>dsv4pro-phase2-20260731-163620</code> 状态为 <code>COMPLETED</code>8/8 benchmark 成功0 失败、0 OOM。</li>
<li class="pass">8/8 Case 使用正式 benchmark 精确时间窗18 个采集器全部记录 <code>STARTED</code><code>STOPPED</code></li>
<li class="pass">Head 与 Worker 的 DCGM、GPU、CPU、进程、NUMA、网卡和 HCA Counter 均有有效样本。</li>
<li class="pass">P2P、8-rank 和 16-rank AllReduce 全部完成,所有正确性检查均为 <code>wrong_values=0</code></li>
<li class="pass">Run 结束后 Head/Worker 无相关容器、无 GPU 计算进程,端口 <code>30002/30003</code> 已释放。</li>
</ul>
<h2>9. 正式运行</h2>
<p class="decision">
<strong>Run<code>dsv4pro-phase2-20260731-163620</code></strong>
运行时间为 16:36:20 至 17:05:04 CST总用时 28 分 44 秒。
Manifest 记录代码提交 <code>5f24b7d22f98108f6cc234edba6768d55ea0a962</code>
<code>git_dirty=false</code>
</p>
<pre><code class="language-bash"># 仅在 Head 174.1.51.5 执行
cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution
RUN_ID=dsv4pro-phase2-20260731-163620
tmux new-session -d -s dsv4pro-phase2 \
"RUN_ID=${RUN_ID} bash run_hardware_contention_attribution.sh all \
2&gt;&amp;1 | tee /data/hzy/${RUN_ID}.log"</code></pre>
<h2>10. 端到端结果</h2>
<h3>10.1 五个代表负载</h3>
<table>
<thead>
<tr><th>Case</th><th>Input TPS</th><th>Output TPS</th><th>TTFT P95</th><th>TPOT P95</th></tr>
</thead>
<tbody>
<tr><td>128K → 1, C=1</td><td>2,641.38</td><td>0.02</td><td>49.610 s</td><td></td></tr>
<tr><td>32K → 1, C=16</td><td>3,115.45</td><td>0.10</td><td>161.938 s</td><td></td></tr>
<tr><td>1K → 1K, C=32</td><td>448.95</td><td>448.95</td><td>10.167 s</td><td>65.36 ms</td></tr>
<tr><td>1K → 4K, C=16</td><td>79.39</td><td>317.56</td><td>1.724 s</td><td>49.98 ms</td></tr>
<tr><td>128K → 1K, C=1</td><td>1,614.99</td><td>12.62</td><td>48.279 s</td><td>32.11 ms</td></tr>
</tbody>
</table>
<h3>10.2 混合 Prefill/Decode A/B</h3>
<table>
<thead>
<tr><th>Decode 指标</th><th>Control</th><th>注入 128K Prefill</th><th>变化</th></tr>
</thead>
<tbody>
<tr><td>Output TPS</td><td>453.55</td><td>344.89</td><td>-23.96%</td></tr>
<tr><td>TTFT P95</td><td>9.443 s</td><td>9.892 s</td><td>+4.76%</td></tr>
<tr><td>TPOT P95</td><td>66.24 ms</td><td>110.45 ms</td><td>+66.75%</td></tr>
<tr><td>E2E P95</td><td>72.270 s</td><td>118.076 s</td><td>+63.38%</td></tr>
</tbody>
</table>
<p>
这是 Phase 2 最关键的现象:长 Prefill 与 Decode 共存时,首 token 延迟只增加
4.76%,但 Decode 单 token 成本增加 66.75%,最终令 Output TPS 下降 23.96%。
问题主要发生在持续 Decode 阶段,而不是只表现为 Prefill 请求排队。
</p>
<h2>11. 第 5 节指标逐项结果</h2>
<h3>11.1 GPU 基础状态与 DCGM</h3>
<p><strong>服务器证据路径:</strong><br>
汇总:<code>/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/case_gpu_summary.csv</code>
<code>case_gpu_node_summary.csv</code><code>case_dcgm_summary.csv</code><br>
原始:同一 Run 目录下的 <code>head/gpu_samples.csv</code><code>worker/gpu_samples.csv</code>
<code>head/dcgm_dmon.log</code><code>worker/dcgm_dmon.log</code>
</p>
<ul>
<li>各 Case GPU Util Mean 大多为 94%99%P95 为 100%SM Clock 约 2.392.42 GHz未见降频。</li>
<li>每卡显存稳定在约 83,00083,364 MiB。Decode 功耗约 216258 WPrefill 功耗约 293307 W。</li>
<li>普通 Decode 的 SM Active 约 0.5230.525、DRAM Active 约 0.4150.417128K Prefill 的 SM Active 升至 0.6830.686。</li>
<li>32K C16 Prefill 的 SM Active 约 0.7130.715、DRAM Active 约 0.440,是本轮最重的并发 Prefill 计算负载。</li>
<li>混合 Treatment 中Decode 背景 SM Active 约 0.5780.581;注入 Prefill 窗口升至 0.7200.723,证明两类工作确实争用同一 GPU 执行资源。</li>
</ul>
<h3>11.2 CPU、进程与 NUMA</h3>
<p><strong>服务器证据路径:</strong><br>
汇总:<code>/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/case_cpu_summary.csv</code>
<code>case_process_summary.csv</code><code>case_perf_summary.csv</code><code>case_numa_summary.csv</code><br>
原始:同一 Run 目录下 Head/Worker 各自的 <code>mpstat.log</code><code>pidstat.log</code>
<code>perf_stat.log</code><code>numa_samples.csv</code><code>docker_top.log</code>
</p>
<ul>
<li>整机 CPU Active Mean 约 9.6%10.4%P95 约 10%11.4%;没有全机 CPU 饱和。</li>
<li>服务进程峰值约 1,210%1,226%,相当于约 12 个 CPU Core热点 Core 数量最多 1213 个。</li>
<li><code>perf</code> 观察到 IPC 约 2.73.1,未出现明显 Host 侧停摆。</li>
<li>Head/Worker 的 NUMA 不均衡约 21.1% / 13.2%,跨 Case 基本稳定;它是拓扑基线,但不像混合性能退化的直接诱因。</li>
</ul>
<h3>11.3 双 Rail RDMA</h3>
<p><strong>服务器证据路径:</strong><br>
汇总:<code>/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/case_rdma_summary.csv</code>
<code>rdma_summary.csv</code><code>case_netdev_summary.csv</code><br>
原始:同一 Run 目录下的 <code>head/rdma.csv</code><code>worker/rdma.csv</code>
<code>head/sar_net.log</code><code>worker/sar_net.log</code>;端口/HCA 静态状态在两端
<code>static_before.log</code><code>static_after.log</code>
</p>
<ul>
<li>RoCE 绕过普通 Linux Socket 数据路径,因此 <code>sar</code><code>eth0/eth3</code> 流量接近 0实际流量必须看 <code>mlx5_0/mlx5_3</code> HCA Counter。</li>
<li>普通 Decode 每 Rail 约 36.736.8 Gbit/s128K Prefill 每 Rail约 70.571.5 Gbit/s。</li>
<li>最高点 32K C16 Prefill 每 Rail 约 83.083.45 Gbit/s仅约占单条 400G Rail 的 20.9%。</li>
<li>两条 Rail 流量对称,<code>port_xmit_wait</code>、丢弃、错误和 Retry Exceeded 增量均为 0。</li>
</ul>
<h3>11.4 PCIe 与 NCCL 通信基线</h3>
<p><strong>服务器证据路径:</strong><br>
汇总:<code>/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/communication_aggregate.csv</code>
<code>communication_summary.csv</code><br>
原始:同一 Run 目录的 <code>communication/p2p_head.log</code><code>p2p_worker.log</code>
<code>allreduce_head_8gpu.log</code><code>allreduce_worker_8gpu.log</code>
<code>allreduce_16gpu_crossnic{0,1,2}_{head,worker}.log</code>;实际执行命令在 <code>commands/communication_*.cmd.txt</code>
</p>
<table>
<thead><tr><th>测试</th><th>结果</th><th>解释</th></tr></thead>
<tbody>
<tr><td>Head PCIe P2P 256 MiB</td><td>同 Switch 53.61 GB/s跨 NUMA 52.40 GB/s</td><td>跨 NUMA 损失约 2.3%</td></tr>
<tr><td>Worker PCIe P2P 256 MiB</td><td>同 Switch 53.50 GB/s跨 NUMA 52.32 GB/s</td><td>两节点表现对称</td></tr>
<tr><td>Head / Worker 8-GPU AllReduce 1 GiB</td><td>busbw 39.76 / 39.75 GB/s</td><td>节点内基线一致</td></tr>
<tr><td>16-GPU AllReduceCROSS_NIC=0</td><td>busbw 39.345 GB/s51.169 ms</td><td>正确性 0 错误</td></tr>
<tr><td>16-GPU AllReduceCROSS_NIC=1</td><td>busbw 39.685 GB/s50.732 ms</td><td>本轮数值最好</td></tr>
<tr><td>16-GPU AllReduceCROSS_NIC=2</td><td>busbw 39.530 GB/s50.931 ms</td><td>正确性 0 错误</td></tr>
</tbody>
</table>
<p>
<code>NCCL_CROSS_NIC=1</code> 比 0 仅高 0.86%,比 2 仅高 0.39%。
差异小于 1%不足以把它当成主要调优旋钮保留当前值即可Phase 3 不再重复测试。
NCCL 日志明确证明跨机路径使用 <code>mlx5_0,mlx5_3</code>
<code>NET/IB/.../GDRDMA</code>
</p>
<h2>12. 结论与 Phase 3 入口</h2>
<p class="decision">
<strong>Phase 2 已把范围明显缩小:</strong>混合 Prefill/Decode 退化真实且稳定,
但不是由整机 CPU 饱和、GPU 降频、双 Rail 原始带宽饱和、Rail 失衡、
PCIe 跨 NUMA 带宽崩塌或 <code>NCCL_CROSS_NIC</code> 选择造成。
Phase 3 应只捕获 Control 与 Treatment 的短时间线,定位 Attention/Indexer、
MoE、NCCL Collective、Scheduler gap 和慢 Rank 同步之间的串行与重叠关系。
</p>
<ul>
<li>不重复 Phase 2 的长时间 DCGM、CPU、RDMA 和通信微基准。</li>
<li>优先对比混合 Control 与注入 128K Prefill 的 Treatment。</li>
<li>再用单独 128K Prefill 作为 Kernel 对照,解释 SM Active 与 Tensor Active 的来源。</li>
</ul>
<h2>13. 证据与清理说明</h2>
<ul>
<li><a href="./results/dsv4pro-phase2-20260731-163620/report.md">自动生成逐指标报告</a></li>
<li><a href="./results/dsv4pro-phase2-20260731-163620/analysis.md">阶段归因摘要</a></li>
<li><a href="./results/dsv4pro-phase2-20260731-163620/bench_summary.csv">端到端 benchmark 汇总</a></li>
<li><a href="./results/dsv4pro-phase2-20260731-163620/communication_aggregate.csv">通信微基准汇总</a></li>
<li><a href="./results/dsv4pro-phase2-20260731-163620/service/head_server_cmd.txt">Head 实际服务命令</a> /
<a href="./results/dsv4pro-phase2-20260731-163620/service/worker_server_cmd.txt">Worker 实际服务命令</a></li>
</ul>
<p>
Worker 日志在所有 benchmark 完成后的编排关闭阶段出现 Gloo
<code>Connection closed by peer</code>;时间与 Head 主动退出进程组一致,
未影响 8/8 结果。NCCL 日志中的可选 mlx5 symbol 探测提示同样未影响
Collective全部正确性检查为 0 错误。
</p>
<p><a class="back" href="./phase1_exp.html">返回 Phase 1 实验档案</a></p>
<p><a class="back" href="./推理优化计划.html">返回推理优化主计划</a></p>
</main>
</body>
</html>