diff --git a/README.md b/README.md
index a0b47e7..f416104 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,9 @@
# sskj — 多平台大模型推理性能基准测试项目
+> **更新(2026-07-31 13:40:03 CST)**
+>
+> 完成 DeepSeek-V4-Pro 双机 Pro6000D SGLang TP16 的 Phase 2 首轮硬件归因。正式 Run `dsv4pro-phase2-20260731-130125` 在 26 分 26 秒内完成 8/8 个 benchmark,无 OOM;混合负载下 Decode Output TPS 下降 24.03%,TPOT P95 增加 66.79%。两端双 Rail `NET/IB + GDRDMA` 流量均衡、错误增量为 0,最高每 Rail 平均约 70 Gbit/s,原始 RoCE 带宽未饱和;整机 CPU 与 GPU 频率也未见全局瓶颈。档案补充了 6000D 无 NVLink、机内 PCIe P2P/IPC、跨机 GDRDMA 的真实通信路径,并记录 Worker DCGM Host Engine 未启动、Case 时间窗过宽和 `pidstat` 日志过大的采集限制。
+>
> **更新(2026-07-31 13:11:40 CST)**
>
> 新增 Phase 1 与 Phase 2 的独立代码详解 HTML 档案,行号固定到提交 `ca1f2f63375c`。文档从唯一入口展开到配置来源、文件调用关系、双机服务与 RDMA 门禁、benchmark 请求生成、混合 Prefill/Decode 时序、两节点采集器、Case 时间窗切片和结构化结果,并为 `MEM_FRACTION_STATIC` 等关键变量记录“默认值定义 → Shell 传递 → 服务参数 → Run 证据”的完整追踪路径。代码档案保持独立,不加入主计划 HTML 或阶段介绍 HTML 的导航。
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html b/docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html
index 5db3d8e..47043dc 100644
--- a/docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html
+++ b/docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html
@@ -135,7 +135,7 @@
节点:174.1.51.5 + 174.1.51.7
拓扑:SGLang TP16 / EP2
- 更新:2026-07-31 12:26:00 CST
+ 更新:2026-07-31 13:40:03 CST
@@ -144,9 +144,10 @@
返回推理优化主计划
- 当前状态:Phase 2 代码已实现,静态检查、5 项单元测试与本地 Dry-run 已通过。
- 尚未启动双机模型服务或正式采集 GPU 数据。真机运行后,本页只保留成功 Run 的
- Run ID、命令、结果与结论。
+ 当前状态:Phase 2 首次正式双机 Run 已完成。
+ Run dsv4pro-phase2-20260731-130125 在 26 分 26 秒内完成
+ 8/8 个 benchmark,无 OOM;GPU、CPU 和双 Rail RDMA 数据已完成首轮归因。
+ 本阶段在此停止,不自动进入 Phase 3。
1. Phase 1 交接结果
@@ -292,7 +293,7 @@ dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/
顶层仍只保留一个 Shell 文件,不创建额外 tmux、launch、start 或 stop 脚本。
- 7. 预期结果结构
+ 7. 结果结构
results/<RUN_ID>/
manifest.json
run.log
@@ -331,15 +332,14 @@ dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/
summary.json
report.md
- 8. 验收条件
+ 8. 验收结果
- - Bench 的 ISL、OSL、并发、Seed、缓存状态与 Phase 1 对应 Case 一致。
- - 两节点采集器均覆盖请求开始前 15 秒到结束后 15 秒。
- - GPU/DCGM/RDMA 时间序列带节点名和墙钟时间,能按 Phase 1 的实际 Case 测量窗口切片。
- - 采集器不可用时记录
UNAVAILABLE 和原因,不静默跳过。
- - 异常退出仍会停止采集器、Head/Worker 容器并确认 GPU 释放。
- - 报告至少能缩小到“计算/显存、CPU 调度、网络通信、频率节流、节点不均衡”中的一个或两个方向。
- - 若粗粒度指标仍无法区分,明确指出需要 Phase 3 的哪一段 Timeline,而不是强行给根因。
+ - 五个固定负载和混合 A/B 共 8 行全部成功,口径与 Phase 1 一致。
+ - Head/Worker GPU、CPU、NUMA、RDMA 采集完成,Case 时间窗和结构化摘要已生成。
+ - 两端 NCCL 日志确认
mlx5_0/mlx5_3 双 Rail NET/IB + GDRDMA。
+ - 服务和采集器完成清理,两节点 16 张 GPU 均已释放。
+ - Worker DCGM 因宿主
nvidia-dcgm 未启动而提前退出;Head DCGM 有效,但本 Run 不能做双节点 DCGM 对称比较。
+ - 当前 Case 时间窗包含客户端准备和 Warm-up,硬件均值可用于方向判断,但不能替代精确的主测量窗口或 Phase 3 Timeline。
9. 实施记录
@@ -352,15 +352,95 @@ dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/
| 2026-07-30 22:55:37 CST | 完成 Phase 1 阶段交接 | 双 Rail 门禁和 12/12 正式结果通过;选定纯 Prefill、并发 Prefill、混合干扰三个诊断负载 |
| 2026-07-31 12:26:00 CST | 完成 Phase 2 代码 | 扩展为五个固定负载和混合 A/B;实现双节点 GPU/DCGM/CPU/NUMA/网络/RDMA 采集、时间对齐和异常清理 |
| 2026-07-31 12:26:00 CST | 本地验证 | bash -n、Python 编译、5 项单元测试与全流程 Dry-run 通过;未占用 GPU |
+ | 2026-07-31 13:27:51 CST | 完成正式双机 Run | Run dsv4pro-phase2-20260731-130125:8/8 benchmark 成功,总用时 26 分 26 秒,无 OOM |
+ | 2026-07-31 13:40:03 CST | 完成首轮结果归因 | 排除原始双 Rail 带宽饱和、整机 CPU 饱和和频率塌陷作为首要原因;锁定 TP16 Kernel、调度与同步时间线 |
10. 真机结果
-
- 尚未运行正式双机诊断。代码和本地 Dry-run 已完成;下一步是在
- 174.1.51.5 做服务器端静态检查与 Dry-run,随后由同一
- all 入口启动正式 Run。正式完成后本节将替换为成功 Run 的结果和瓶颈判断。
+
+ Run:dsv4pro-phase2-20260731-130125,状态
+ COMPLETED。运行时间为 13:01:25 至 13:27:51 CST,
+ 8 个结果全部成功,0 个失败。正式入口仅在 174.1.51.5 执行;
+ Worker 服务和采集器由脚本通过 SSH 自动启动。
+ cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution
+
+RUN_ID=dsv4pro-phase2-20260731-130125
+tmux new-session -d -s dsv4pro-phase2 \
+ "RUN_ID=${RUN_ID} bash run_hardware_contention_attribution.sh all \
+ 2>&1 | tee /data/hzy/${RUN_ID}.log"
+
+ 10.1 代表负载
+
+
+ | Case | Input TPS | Output TPS | TTFT P95 | TPOT P95 |
+
+
+ | 128K → 1, C=1 | 2,618.53 | 0.02 | 50.036 s | — |
+ | 32K → 1, C=16 | 3,116.20 | 0.10 | 161.899 s | — |
+ | 1K → 1K, C=32 | 447.41 | 447.41 | 10.144 s | 65.63 ms |
+ | 1K → 4K, C=16 | 79.35 | 317.41 | 1.727 s | 50.01 ms |
+ | 128K → 1K, C=1 | 1,610.89 | 12.59 | 48.489 s | 32.12 ms |
+
+
+
+ 10.2 混合 Prefill/Decode
+
+
+ | Decode 指标 | Control | 注入 128K Prefill | 变化 |
+
+
+ | Output TPS | 454.39 | 345.20 | -24.03% |
+ | TTFT P95 | 9.437 s | 9.869 s | +4.58% |
+ | TPOT P95 | 66.17 ms | 110.36 ms | +66.79% |
+ | E2E P95 | 72.225 s | 117.941 s | +63.30% |
+
+
+
+ 这再次证明 Prefill 会明显干扰正在进行的 Decode。ITL P95 仍约为
+ 62 ms,并不与 TPOT 恶化矛盾:少量同步长停顿可能不足全部 token 间隔的 5%,
+ 因而会被全局 token 级 ITL P95 隐藏,而请求级 TPOT 和 E2E 会暴露它。
+
+
+ 10.3 GPU、CPU 与通信
+
+ - 128K Prefill 注入窗口两节点平均 GPU 利用率为 99.78% / 99.34%,平均功耗约 274 W;频率稳定在约 2.38–2.41 GHz,没有频率塌陷证据。
+ - 显存稳定在每卡约 83.2–83.4 GiB / 85,651 MiB,只剩约 2.3 GiB 余量。
+ - 整机 CPU 平均约 8%–11%,I/O Wait 为 0;但注入窗口仍有 5/4 个 Head/Worker 核平均超过 80%,单线程调度或 NUMA 热点尚未排除。
+ - 两条 RDMA Rail 流量几乎对称,所有采集到的错误增量均为 0。最高负载为 32K → 1, C=16:Head/Worker 总发送约 140.0/139.3 Gbit/s,即每条 400G Rail 约 70 Gbit/s。
+ - 因此原始 RoCE 带宽没有饱和;但 TP16 collective 的延迟、调度和 Rank 同步开销仍需 Timeline 才能拆开。
+
+
+ 10.4 卡间通信路径
+
+
+ | 范围 | 实际路径 | 本轮是否测量 |
+
+
+ | 单机 8 卡内部 | 无 NVLink;NCCL P2P/IPC 走 PCIe。GPU0–3、GPU4–7 各自在 PCIe Switch 内为 PIX,两组之间为 SYS | 采集了 DCGM PCIe 指标;未做独立 P2P 带宽/延迟微基准 |
+ | 两机之间 | mlx5_0 + mlx5_3 双 Rail NET/IB + GDRDMA | 已测量每 Case HCA 流量、均衡性和错误增量 |
+
+
+
+ 在进入 Phase 3 前只需一次性补 p2pBandwidthLatencyTest、单机 8 卡
+ all_reduce_perf 和双机 16 卡 all_reduce_perf,
+ 分开量化机内 PCIe 与跨机 RoCE 的硬件基线;后续阶段不重复跑这些微基准。
+
+
+ 10.5 首轮结论与采集限制
+
+ 当前证据支持把下一步缩到 TP16 的 Kernel、Scheduler、PCIe/RDMA Collective
+ 和 Rank 同步时间线。Phase 3 只分析真实请求中通信出现的位置、耗时和与计算的
+ 重叠关系,不重复 Phase 2 的平均 GPU/CPU/RDMA 采集。原始双 Rail 带宽、整机
+ CPU 容量和降频都不像首要瓶颈;但 Phase 2 粗粒度指标还不能给出具体 Kernel 根因。
+
+
+ - Worker 的
nvidia-dcgm Host Engine 未启动,导致 Worker DCGM 提前退出。重跑前只需在 .7 启动 DCGM;整套 Phase 2 仍只在 .5 执行。
+ - 当前 Case 时间窗包含客户端启动、数据准备、Warm-up 和退出,硬件平均值被非正式测量阶段稀释;后续要增加主 benchmark 精确起止标记。
+ pidstat -durwt 一秒采样生成约 850/735 MB 日志;后续改为进程级或 5 秒采样,减少诊断扰动。
+ - 完整归因见
analysis.md,原始结构化摘要和两端 NCCL 证据已一并归档。
+
返回 Phase 1 实施记录
返回推理优化主计划
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/analysis.md b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/analysis.md
new file mode 100644
index 0000000..ca411bd
--- /dev/null
+++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/analysis.md
@@ -0,0 +1,138 @@
+# Phase 2 Hardware Attribution Analysis
+
+## Run
+
+- Run ID: `dsv4pro-phase2-20260731-130125`
+- Status: `COMPLETED`
+- Time: `2026-07-31 13:01:25` to `13:27:51 CST`
+- Duration: 26 minutes 26 seconds
+- Topology: two Pro6000D nodes, SGLang TP16 / EP2
+- Bench result: 8 completed, 0 failed, no OOM
+
+The command was run only on `174.1.51.5`:
+
+```bash
+cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution
+
+RUN_ID=dsv4pro-phase2-20260731-130125
+tmux new-session -d -s dsv4pro-phase2 \
+ "RUN_ID=${RUN_ID} bash run_hardware_contention_attribution.sh all \
+ 2>&1 | tee /data/hzy/${RUN_ID}.log"
+```
+
+The entry script started the Worker and its collectors on `174.1.51.7` over SSH.
+The full Phase 2 command must not be run a second time on the Worker.
+
+## Endpoint Results
+
+| Case | Input TPS | Output TPS | TTFT P95 | TPOT P95 | E2E P95 |
+|---|---:|---:|---:|---:|---:|
+| 128K -> 1, C=1 | 2,618.53 | 0.02 | 50.036 s | - | 50.036 s |
+| 32K -> 1, C=16 | 3,116.20 | 0.10 | 161.899 s | - | 161.899 s |
+| 1K -> 1K, C=32 | 447.41 | 447.41 | 10.144 s | 65.63 ms | 73.189 s |
+| 1K -> 4K, C=16 | 79.35 | 317.41 | 1.727 s | 50.01 ms | 206.427 s |
+| 128K -> 1K, C=1 | 1,610.89 | 12.59 | 48.489 s | 32.12 ms | 81.343 s |
+
+## Mixed Prefill/Decode
+
+| Decode metric | Control | With one 128K Prefill | Change |
+|---|---:|---:|---:|
+| Output TPS | 454.39 | 345.20 | -24.03% |
+| TTFT P95 | 9.437 s | 9.869 s | +4.58% |
+| TPOT P95 | 66.17 ms | 110.36 ms | +66.79% |
+| E2E P95 | 72.225 s | 117.941 s | +63.30% |
+
+This reproduces the Phase 1 contention result. Prefill mainly damages ongoing
+Decode progress rather than its first-token latency. Global token-level ITL P95
+stayed near 62 ms because a small number of synchronized long stalls can remain
+below the top 5% of all token gaps. Per-request TPOT and E2E expose the impact
+more clearly.
+
+## Hardware Evidence
+
+### GPU
+
+- During the 128K Prefill injection, average GPU utilization was 99.78% on the
+ Head and 99.34% on the Worker; average power was about 274 W on both nodes.
+- During 32K -> 1, C=16 Prefill, average GPU utilization was about 82% on both
+ nodes and power was about 265 W.
+- GPU clocks remained around 2.38 to 2.41 GHz. There is no evidence of a
+ frequency collapse.
+- GPU memory stayed near 83.2 to 83.4 GiB of 85,651 MiB per GPU, leaving only
+ about 2.3 GiB of headroom.
+- Head DCGM data is valid. During the injection window, `GRACT=0.995`,
+ `SMACT=0.648`, `SMOCC=0.215`, `Tensor Active=0.108`, and
+ `DRAM Active=0.412`.
+
+### CPU
+
+- Whole-machine CPU utilization stayed around 8% to 11% across 128 logical
+ CPUs, with zero average I/O wait.
+- A few individual cores were saturated. During the injection window, 5 Head
+ cores and 4 Worker cores averaged above 80%.
+- Therefore the machine is not globally CPU-bound, but scheduler, affinity, or
+ NUMA hot threads remain plausible contributors.
+
+### Inter-node RDMA
+
+- NCCL logs on both nodes verified `NET/IB + GDRDMA` over
+ `mlx5_0,mlx5_3`.
+- Both rails carried nearly identical traffic and all recorded RDMA error
+ deltas were zero.
+- The largest average traffic occurred in 32K -> 1, C=16 Prefill:
+ about 140.0 Gbit/s total transmit on the Head and 139.3 Gbit/s on the Worker,
+ or about 70 Gbit/s per 400G rail.
+- This is only about 17.5% of each rail's nominal line rate. Raw RoCE bandwidth
+ saturation is therefore not the primary ceiling, although collective
+ latency and synchronization overhead are not ruled out.
+
+### Intra-node GPU Communication
+
+- RTX Pro 6000D has no NVLink. `nvidia-smi nvlink --status` reports no links.
+- `nvidia-smi topo -m` shows GPU0-3 and GPU4-7 connected through local PCIe
+ switches (`PIX`), while traffic between the two four-GPU groups crosses the
+ host bridge and CPU/NUMA interconnect (`SYS`).
+- NCCL logs show intra-node transfers through `P2P/IPC`; on this machine that
+ means CUDA peer-to-peer over PCIe, not NVLink.
+- Phase 2 collected DCGM PCIe counters but did not run a dedicated GPU-to-GPU
+ bandwidth/latency microbenchmark. A later short diagnostic should run
+ `p2pBandwidthLatencyTest`, 8-GPU `all_reduce_perf`, and 16-GPU
+ `all_reduce_perf`.
+
+## Preliminary Attribution
+
+The first successful Phase 2 run supports three conclusions:
+
+1. Prefill/Decode resource contention is real and reproducible.
+2. Raw dual-rail RoCE bandwidth, whole-machine CPU capacity, and clock
+ throttling do not explain the observed slowdown.
+3. The next useful target is the TP16 execution timeline: GPU kernels,
+ scheduler gaps, PCIe/RDMA collectives, and synchronization between ranks.
+
+This is a bottleneck direction, not a final kernel-level root cause. Phase 3
+should capture short Prefill, Decode, and mixed timelines rather than repeat the
+full benchmark matrix.
+
+## Collection Limitations
+
+- Worker DCGM exited because `nvidia-dcgm` hostengine was inactive on
+ `174.1.51.7`. Before another hardware run, execute on the Worker:
+
+ ```bash
+ systemctl start nvidia-dcgm
+ systemctl is-active nvidia-dcgm
+ dcgmi discovery -l
+ ```
+
+ The main Phase 2 entry still runs only on the Head.
+
+- Current Case windows include benchmark-client startup, tokenizer/data
+ preparation, warm-up, the measured run, and client exit. Hardware averages
+ are therefore diluted outside the true main benchmark interval. Future
+ profiling must add explicit main-run start/end markers.
+- `pidstat -durwt` at one-second intervals generated about 850 MB on the Head
+ and 735 MB on the Worker. The next run should use process-level sampling
+ and/or a five-second interval.
+- Worker teardown logged a Gloo connection reset after the Head stopped. It
+ occurred after all eight benchmark rows completed and is a cleanup artifact,
+ not a benchmark failure.
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/manifest.json b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/manifest.json
new file mode 100644
index 0000000..2e2159a
--- /dev/null
+++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/manifest.json
@@ -0,0 +1,20 @@
+{
+ "run_id": "dsv4pro-phase2-20260731-130125",
+ "status": "COMPLETED",
+ "created_at": "2026-07-31T13:01:25+08:00",
+ "completed_at": "2026-07-31T13:27:51+08:00",
+ "experiment": "dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution",
+ "git_commit": "ca1f2f63375cd6e2bd249a91cbdbe7576aafad7e",
+ "git_dirty": false,
+ "phase1_entry": "/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/run_quick_map.sh",
+ "head_node": "10.101.0.11",
+ "worker_node": "10.101.0.13",
+ "fixed_case_ids": "long_prefill_latency_128k_c1,mid_prefill_throughput_32k_c16,decode_throughput_1k_to_1k_c32,long_output_decode_1k_to_4k_c16,long_context_decode_128k_to_1k_c1",
+ "run_mixed_case": true,
+ "sample_interval_s": 1,
+ "numastat_interval_s": 5,
+ "clock_skew_tolerance_s": 2,
+ "idle_baseline_s": 15,
+ "post_run_cooldown_s": 15,
+ "dry_run": false
+}
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/report.md b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/report.md
new file mode 100644
index 0000000..ddb618c
--- /dev/null
+++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/report.md
@@ -0,0 +1,34 @@
+# Phase 2 Hardware Attribution
+
+- Generated: `2026-07-31T13:27:51+08:00`
+- Bench rows: `8`
+- Failed bench rows: `0`
+- GPU summary rows: `16`
+- RDMA summary rows: `4`
+- Case windows: `8`
+- Collector status counts: `{"EXITED_BEFORE_STOP": 1, "STARTED": 18, "STOPPED": 17}`
+
+## Bench
+
+| Run | Case | Status | Input TPS | Output TPS | TTFT P95 (ms) | TPOT P95 (ms) |
+|---|---|---|---:|---:|---:|---:|
+| fixed_decode_throughput_1k_to_1k_c32 | decode_throughput_1k_to_1k_c32 | COMPLETED | 447.41274460374615 | 447.41274460374615 | 10144.207949569682 | 65.62598442892012 |
+| fixed_long_context_decode_128k_to_1k_c1 | long_context_decode_128k_to_1k_c1 | COMPLETED | 1610.8926328335153 | 12.585098694011839 | 48488.74244495528 | 32.11543163640164 |
+| fixed_long_output_decode_1k_to_4k_c16 | long_output_decode_1k_to_4k_c16 | COMPLETED | 79.35259394563253 | 317.41037578253014 | 1726.5846392256208 | 50.00692894707874 |
+| fixed_long_prefill_latency_128k_c1 | long_prefill_latency_128k_c1 | COMPLETED | 2618.53322910782 | 0.019977823098051604 | 50036.02714801673 | 0.0 |
+| fixed_mid_prefill_throughput_32k_c16 | mid_prefill_throughput_32k_c16 | COMPLETED | 3116.2035105433815 | 0.0950989840864069 | 161899.06251549837 | 0.0 |
+| mixed_prefill_decode_interference | decode_control_1k_to_1k_c32 | COMPLETED | 454.3923063408163 | 454.3923063408163 | 9436.576361441985 | 66.170705189718 |
+| mixed_prefill_decode_interference | decode_with_128k_prefill_1k_to_1k_c32 | COMPLETED | 345.2031620939666 | 345.2031620939666 | 9868.98645934416 | 110.36397890971698 |
+| mixed_prefill_decode_interference | long_prefill_injection_128k_to_1_c1 | COMPLETED | 2844.468616501081 | 0.021701573307045603 | 45999.09703899175 | 0.0 |
+
+## Machine-readable summaries
+
+- `gpu_summary.csv`
+- `rdma_summary.csv`
+- `bench_summary.csv`
+- `case_windows.csv`
+- `case_gpu_summary.csv`
+- `case_rdma_summary.csv`
+- `summary.json`
+
+The final bottleneck conclusion is written only after aligning these files with `markers.csv`, raw DCGM/sysstat logs, and SGLang service logs.
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/service/head_server_cmd.txt b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/service/head_server_cmd.txt
new file mode 100644
index 0000000..bd8d931
--- /dev/null
+++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/service/head_server_cmd.txt
@@ -0,0 +1 @@
+docker run -d --name dsv4pro_pro6000d_2node_sglang_tp16_quick_map_head --gpus all --network host --ipc host --shm-size 20g --ulimit memlock=-1 --ulimit stack=67108864 -v /data/hf_models/DeepSeek-V4-Pro:/data/hf_models/DeepSeek-V4-Pro:ro -v /data/hzy/sglang_cache/dsv4_pro_tp16:/root/.cache -e CUDA_VISIBLE_DEVICES=0\,1\,2\,3\,4\,5\,6\,7 -e PYTHONUNBUFFERED=1 -e HF_HUB_OFFLINE=1 -e TRANSFORMERS_OFFLINE=1 -e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True -e NCCL_SOCKET_IFNAME=eth0 -e NCCL_IB_HCA==mlx5_0:1\,mlx5_3:1 -e NCCL_CROSS_NIC=1 -e NCCL_DEBUG=INFO -e SGLANG_SHARED_EXPERT_TP1=1 --device /dev/infiniband/rdma_cm --device /dev/infiniband/uverbs0 --device /dev/infiniband/uverbs3 --entrypoint python3 lmsysorg/sglang:nightly-dev-cu13-20260720-b3570a45 -m sglang.launch_server --model-path /data/hf_models/DeepSeek-V4-Pro --tp-size 16 --ep-size 2 --nnodes 2 --node-rank 0 --dist-init-addr 10.101.0.11:20002 --trust-remote-code --host 0.0.0.0 --port 30002 --mem-fraction-static 0.9 --cuda-graph-max-bs-decode 64 --max-running-requests 256
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/service/worker_server_cmd.txt b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/service/worker_server_cmd.txt
new file mode 100644
index 0000000..3b18997
--- /dev/null
+++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/service/worker_server_cmd.txt
@@ -0,0 +1 @@
+docker run -d --name dsv4pro_pro6000d_2node_sglang_tp16_quick_map_worker --gpus all --network host --ipc host --shm-size 20g --ulimit memlock=-1 --ulimit stack=67108864 -v /data/hf_models/DeepSeek-V4-Pro:/data/hf_models/DeepSeek-V4-Pro:ro -v /data/hzy/sglang_cache/dsv4_pro_tp16:/root/.cache -e CUDA_VISIBLE_DEVICES=0\,1\,2\,3\,4\,5\,6\,7 -e PYTHONUNBUFFERED=1 -e HF_HUB_OFFLINE=1 -e TRANSFORMERS_OFFLINE=1 -e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True -e NCCL_SOCKET_IFNAME=eth0 -e NCCL_IB_HCA==mlx5_0:1\,mlx5_3:1 -e NCCL_CROSS_NIC=1 -e NCCL_DEBUG=INFO -e SGLANG_SHARED_EXPERT_TP1=1 --device /dev/infiniband/rdma_cm --device /dev/infiniband/uverbs0 --device /dev/infiniband/uverbs3 --entrypoint python3 lmsysorg/sglang:nightly-dev-cu13-20260720-b3570a45 -m sglang.launch_server --model-path /data/hf_models/DeepSeek-V4-Pro --tp-size 16 --ep-size 2 --nnodes 2 --node-rank 1 --dist-init-addr 10.101.0.11:20002 --trust-remote-code --host 0.0.0.0 --port 30002 --mem-fraction-static 0.9 --cuda-graph-max-bs-decode 64 --max-running-requests 256
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/summary.json b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/summary.json
new file mode 100644
index 0000000..4a55636
--- /dev/null
+++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase2-20260731-130125/summary.json
@@ -0,0 +1,45 @@
+{
+ "generated_at": "2026-07-31T13:27:51+08:00",
+ "bench_rows": 8,
+ "failed_bench_rows": 0,
+ "gpu_summary_rows": 16,
+ "rdma_summary_rows": 4,
+ "case_windows": 8,
+ "case_gpu_summary_rows": 128,
+ "case_rdma_summary_rows": 32,
+ "collector_status_counts": {
+ "STARTED": 18,
+ "STOPPED": 17,
+ "EXITED_BEFORE_STOP": 1
+ },
+ "collector_files": {
+ "head": {
+ "dcgm_dmon.log": 1638191,
+ "docker_top.log": 11692641,
+ "gpu_samples.csv": 726449,
+ "markers.csv": 1860,
+ "mpstat.log": 15587271,
+ "numastat.log": 3280062,
+ "perf_stat.log": 744719,
+ "pidstat.log": 850254976,
+ "rdma.csv": 230202,
+ "sar_net.log": 2118579,
+ "static_after.log": 1195680,
+ "static_before.log": 1306492
+ },
+ "worker": {
+ "dcgm_dmon.log": 243,
+ "docker_top.log": 11989768,
+ "gpu_samples.csv": 758155,
+ "markers.csv": 1902,
+ "mpstat.log": 15587260,
+ "numastat.log": 3579303,
+ "perf_stat.log": 747768,
+ "pidstat.log": 734994477,
+ "rdma.csv": 242603,
+ "sar_net.log": 2383072,
+ "static_after.log": 1195267,
+ "static_before.log": 1306098
+ }
+ }
+}
diff --git a/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html b/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html
index 7586581..9f99ec8 100644
--- a/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html
+++ b/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html
@@ -400,7 +400,7 @@
@@ -415,7 +415,7 @@
6000D 双机 DeepSeek-V4-Pro 推理优化计划
-适用环境:174.1.51.5 + 174.1.51.7,每台 8 张 RTX PRO 6000 Blackwell Server Edition
当前部署:DeepSeek-V4-Pro,16 张 GPU 组成一个完整实例
当前约束:模型暂时只能使用全部 16 张 GPU,无法额外复制一套模型进行 PD 分离
计划版本:2026-07-30 22:55:37 CST
+适用环境:174.1.51.5 + 174.1.51.7,每台 8 张 RTX PRO 6000 Blackwell Server Edition
当前部署:DeepSeek-V4-Pro,16 张 GPU 组成一个完整实例
当前约束:模型暂时只能使用全部 16 张 GPU,无法额外复制一套模型进行 PD 分离
计划版本:2026-07-31 13:40:03 CST
当前执行状态与阶段档案
@@ -439,7 +439,7 @@
| DeepSeek-V4-Pro / 双机 Pro6000D / SGLang 硬件与资源竞争归因 |
-代码、单元测试与本地 Dry-run 已完成;等待服务器端 Dry-run 与正式运行 |
+首轮正式 Run 已完成;8/8 benchmark 成功,已获得 GPU、CPU 与双 Rail RDMA 瓶颈方向 |
打开 Phase 2 档案 |
@@ -475,6 +475,14 @@
400 Gbit/s ≈ 50 GB/s 只是单向理论上限,NCCL 的
algbw/busbw 与端到端模型吞吐都不能直接等同于该数字。
+
+当前 6000D 机内没有 NVLink。单机 8 卡由 PCIe 连接:
+GPU0–3 与 GPU4–7 各自在本地 PCIe Switch 内通信,两组之间还要经过 Host Bridge
+和 CPU/NUMA 互联。NCCL 机内日志中的 P2P/IPC 是 CUDA P2P over PCIe;
+两机之间则使用 mlx5_0/mlx5_3 双 Rail
+NET/IB + GDRDMA。Phase 2 已测跨机 HCA 流量,但机内 PCIe 的独立
+GPU-to-GPU 带宽和延迟仍需微基准补齐。
+
1. 目标与原则
1.1 最终目标
在不做 PD 分离的前提下,定位 DeepSeek-V4-Pro 在双机 6000D 上的端到端瓶颈,并提高:
@@ -727,10 +735,24 @@ TPOT P95 增加 66.55%。Phase 2 将围绕这两个现象采集硬件时间序
Phase 2:硬件与资源竞争归因档案。本阶段重放长 Prefill、并发 Prefill、
普通 Decode、长输出 Decode、长上下文 Decode,以及
-1K → 1K, C=32 的混合 A/B。目标是在约 30 分钟内区分 GPU、
-CPU、NUMA、双 Rail、调度排队、频率节流和节点不均衡。
+1K → 1K, C=32 的混合 A/B。正式 Run
+dsv4pro-phase2-20260731-130125 已在 26 分 26 秒内完成 8/8 个结果,
+无 OOM;本阶段先停在首轮归因,不自动进入 Phase 3。
-6.1 GPU
+6.1 首轮归因结果
+
+- 混合负载再次稳定复现:Decode Output TPS 下降 24.03%,TPOT P95 增加 66.79%,E2E P95 增加 63.30%。
+- 128K Prefill 注入窗口两节点 GPU 平均利用率约 99%,功耗约 274 W,频率稳定;显存每卡约 83.2–83.4 GiB,只剩约 2.3 GiB 余量。
+- 整机 CPU 平均约 8%–11%,没有全机 CPU 或 I/O Wait 饱和,但少量 CPU 核持续高负载,Scheduler/Affinity/NUMA 热点仍需关注。
+- 双 Rail 流量对称且错误增量为 0;最高平均总发送约 140 Gbit/s,即每条 400G Rail 约 70 Gbit/s,原始 RoCE 带宽未饱和。
+- 下一步应捕获短 TP16 Timeline,区分 GPU Kernel、Scheduler gap、机内 PCIe、跨机 Collective 与 Rank 同步,而不是重跑完整矩阵。
+
+
+首轮仍有两个采集限制:Worker 的 DCGM Host Engine 未启动,因此只有 Head DCGM
+有效;Case 时间窗包含客户端准备和 Warm-up,硬件均值并非纯主测量窗口。重跑前应先在
+.7 启动 nvidia-dcgm,并增加主 benchmark 精确起止标记。
+
+6.2 GPU
测试期间持续记录:
nvidia-smi dmon -s pucvmt -d 1
@@ -751,7 +773,7 @@ CPU、NUMA、双 Rail、调度排队、频率节流和节点不均衡。
PCIe Throughput。
GPU Stall 与 XID。
-6.2 CPU
+6.3 CPU
记录服务主进程与 Worker 线程:
pidstat -t -p <PID> 1
mpstat -P ALL 1
@@ -764,7 +786,7 @@ numastat -p <PID>
Worker 是否跨 NUMA 访问。
CPU 空洞是否对应 GPU 空洞。
-6.3 网络
+6.4 网络
Phase 1 正式 Run 已从两端 NCCL 日志确认
NET/IB 同时识别 mlx5_0/mlx5_3,跨节点 Channel
@@ -788,7 +810,7 @@ ethtool -S eth3
NCCL_DEBUG_SUBSYS=INIT,NET,GRAPH,TUNING
该日志开销较高,不应在正式性能结果中长期启用。
-6.4 NCCL_CROSS_NIC 快速 A/B
+6.5 NCCL_CROSS_NIC 快速 A/B
Phase 1 已证明 NCCL_CROSS_NIC=1 可以稳定完成端到端 Run,
但这不代表它是性能最优值。固定其余环境后比较 0/1/2,
@@ -800,12 +822,12 @@ Phase 1 已证明 NCCL_CROSS_NIC=1 可以稳定完成端到端 Run
每个值重启同配置 SGLang 服务,仅重放一个 Decode 高并发代表点,比较 Output TPS、TPOT P95 与稳定性。
先排除不正确或不稳定的值,再比较 NCCL 中位带宽,最终以 SGLang 端到端结果决定生产值。
-6.5 与其他阶段的组合边界
+6.6 与其他阶段的组合边界
- Phase 1 保留一份不启用 Profiler 的端到端基线,避免 TPS 和时延被诊断工具污染。
- GPU、CPU 和网络的轻量采样可以伴随后续基线运行,但必须从 Case 开始前启动,并使用统一时间戳与 Case ID 对齐。
- Phase 1 已完整结束,其无 Profiler 结果作为后续 A/B 的请求层基线。
-- Phase 2 重放五个固定代表负载和一组混合 A/B,并完整采集轻量指标;得到瓶颈方向后,再决定 Phase 3 捕获哪段短时间线。
+- Phase 2 已重放五个固定代表负载和一组混合 A/B,并完成首轮轻量采集;下一步只需补齐 Worker DCGM 和精确时间窗,然后决定 Phase 3 的短 Timeline。
- 联合诊断 Run 的吞吐和时延只用于解释时间线;正式性能变化仍与 Phase 1 的无 Profiler 结果比较。
7. Phase 3:时间线 Profiling(Nsight Systems 为主)
@@ -814,15 +836,34 @@ Nsight Systems、PyTorch Profiler 和 NVTX 是三件不同的东西:Nsight Sys
记录系统级 CUDA/NCCL/CPU 时间线;PyTorch Profiler 由框架接口触发;
NVTX 只是在时间线上添加可读标记。启用 NVTX 不等于已经启动 Nsight。
-7.1 捕获策略
+7.1 与 Phase 2 的分工
+
+
+| 问题 | 负责阶段或工具 | 是否在 Phase 3 重复 |
+
+
+| GPU/CPU 平均利用率、功耗、频率、显存 | Phase 2 轻量采样 | 否;Phase 3 只保留最低限度健康检查 |
+| 双 Rail 流量、均衡与错误计数 | Phase 2 HCA Counter | 否 |
+| 机内 PCIe P2P 与 8/16 卡 Collective 峰值能力 | 一次性通信微基准:p2pBandwidthLatencyTest 与 all_reduce_perf | 只建立一次硬件基线,不随每个 Phase 重跑 |
+| 真实请求中 NCCL Kernel 在何时发生、耗时多久 | Phase 3 Nsight Systems Timeline | 是,Phase 3 的核心 |
+| 通信是否与 Attention/MoE Kernel 重叠、GPU 是否在等待 Rank | Phase 3 Nsight Systems Timeline | 是,Phase 2 无法回答 |
+
+
+
+因此 Phase 3 可以分析卡间通信,但分析的是真实请求里的时间与依赖关系,
+不是再次统计平均网络带宽。通信微基准负责给出硬件上限,Phase 3 负责解释 SGLang
+距离该上限有多远,以及通信是否落在关键路径上。
+
+7.2 捕获策略
- 只捕获预热后的 5 到 10 个 Engine Step。
- Prefill、Decode 和混合干扰分别生成报告。
- 两台机器分别保存原始报告。
- 优先保留所有 Rank;文件过大时至少保留代表 Rank 和跨机通信相关 Rank。
- 报告必须和对应 Benchmark Case ID 绑定。
+- 不重复运行 Phase 2 的五点硬件采集矩阵,不同时开启高频
pidstat、mpstat、sar 或 DCGM 全量采样。
-7.2 vLLM
+7.3 vLLM
当前版本支持时,使用 CUDA Profiler 动态 Capture:
export VLLM_WORKER_MULTIPROC_METHOD=spawn
@@ -839,7 +880,7 @@ nsys profile \
压测端使用支持 Profile Trigger 的 Bench:
vllm bench serve ... --profile
-7.3 SGLang
+7.4 SGLang
以下 SGLANG_TORCH_PROFILER_DIR 与 /start_profile
属于 SGLang 的 PyTorch Profiler 路径,可用于框架级时间线,但不能把生成物