当前状态:Phase 2 已完成。
最终 Run dsv4pro-phase2-20260731-163620 在 28 分 44 秒内完成
8/8 个 benchmark,正式测量窗口 8/8 精确,18/18 个采集器正常启停。
Head/Worker 的 DCGM、CPU、NUMA、双 Rail RDMA 和通信微基准证据均有效;
实验结束后两节点容器、服务端口和 16 张 GPU 已清理。
1. Phase 1 交接结果
| 代表负载 | 关键结果 | Phase 2 用途 |
|---|---|---|
| 128K → 1,C=1 | Input TPS 2,710.16;TTFT P95 48.344 s | 纯长 Prefill 的计算、显存与通信归因 |
| 32K → 1,C=16 | Input TPS 3,112.77;TTFT P95 162.087 s | 并发 Prefill 的排队、Chunk 调度与节点均衡 |
| 1K → 1K,C=32 | Output TPS 461.68;TPOT P95 63.31 ms | 普通 Decode 的 GPU、CPU 与通信基线 |
| 1K → 4K,C=16 | Output TPS 310.02;TPOT P95 50.33 ms | 持续 Decode、KV 增长和稳态资源占用 |
| 128K → 1K,C=1 | TTFT P95 49.326 s;TPOT P95 32.24 ms | 分离长 Prefill 与长上下文 Decode 成本 |
| 1K → 1K,C=32 + 128K 注入 | Output TPS -24.08%;TPOT P95 +66.55% | Prefill 干扰 Decode 时的硬件资源竞争 |
最终基线已由 Head 与 Worker 日志证明使用
mlx5_0/mlx5_3 双 Rail NET/IB + GDRDMA,
正式测量请求为冷 Prefix。正式矩阵 12/12、长 Decode 补测 2/2 均成功。
Phase 2 保持相同服务配置和请求口径。
2. 本阶段的边界
- 只测试 SGLang,不测试 vLLM。
- 保留模型、镜像、TP16、EP2、显存比例和已验证的双 Rail NCCL 配置。
- 模型端到端 Case 不启用 Nsight Systems、PyTorch Profiler、NCCL DEBUG 或投机解码;独立通信基线临时启用 NCCL INFO 以保存实际路径证据。
- 不调参,不尝试优化;先获得足以区分瓶颈类别的硬件证据。
- 只重放五个固定代表负载和一组混合 A/B,不重复 Phase 1 全矩阵。
- 采集器从请求开始前启动,到请求结束后停止,不能中途补采后声称完整。
3. 待验证假设
| 假设 | 预期硬件表现 | 后续方向 |
|---|---|---|
| DSV4/NSA Prefill Kernel 计算受限 | GPU 持续忙、高功耗和稳定频率;双 Rail 流量不高 | Phase 3 捕获 Kernel 与 Attention/Indexer 时间线 |
| 权重或激活显存带宽受限 | GPU Memory Utilization 高,SM 指标未必饱和;功耗可能低于纯计算 | 补 DCGM/Profiler 的 DRAM Active,再看 Kernel |
| TP16 跨机通信受限 | RoCE 吞吐高或两条 Rail 明显失衡,GPU 出现等待 | NCCL_CROSS_NIC 0/1/2 快速 A/B,随后看 NCCL Timeline |
| CPU Scheduler 或 Kernel Launch 受限 | GPU 利用率锯齿或有空洞,单 CPU 核持续满载 | 定位 Scheduler/Tokenizer 线程与 launch gap |
| 频率、功耗或温度限制 | P-state、SM Clock 或 Power 持续异常,可能出现节流原因 | 修正电源、散热或 Clock Policy 后复测 |
| 节点或 Rank 不均衡 | 两节点或不同 GPU 的利用率、功耗、网络流量存在固定偏差 | 检查 NUMA、GPU-NIC 亲和与慢 Rank |
4. 诊断 Run
- 确认 16 张 GPU 空闲,先跑两节点 PCIe P2P、单机 8 rank AllReduce 和双机 16 rank AllReduce;双机分别测试
NCCL_CROSS_NIC=0/1/2。 - 保存两节点静态快照:GPU/NIC/NUMA 拓扑、驱动、CUDA、镜像与服务命令。
- 复用 Phase 1 已验证的
run_quick_map.sh start启动同配置双机服务。 - 在 Head 和 Worker 同时启动 GPU、CPU、网卡与 RDMA 采样,先记录 15 秒空闲基线。
- 依次重放
128K → 1, C=1、32K → 1, C=16与1K → 1K, C=32。 - 重放
1K → 4K, C=16和128K → 1K, C=1,观察持续与长上下文 Decode。 - 重放
1K → 1K, C=32Control 与 128K Prefill 注入 Treatment,保留相同注入时序。 - 请求结束后继续采样 15 秒,再停止采集器和服务。
- 按时间戳将请求、GPU、CPU 和双 Rail 指标对齐,生成摘要与判定。
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 的所有采集器覆盖完整诊断窗口。
Phase 1 中服务加载约 5 分 30 秒;通信基线、五个固定负载、混合 A/B、 静态快照、采样和清理组成一次完整 Phase 2 Run。
4.1 你只需要运行的入口
操作规则:先在 Worker .7 做一次 DCGM 准备,再只在
Head .5 执行 Phase 2 的 all。
不要手工执行 Phase 1 的 start 或 stop。
Phase 2 会在内部复用它们,并负责异常退出时的采集器、Head、Worker 清理。
# [仅在 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>&1 | tee /data/hzy/${RUN_ID}.log"
tmux attach -t dsv4pro-phase2
.7 的三条命令只负责让 Worker DCGM Host Engine 可用;
SGLang Worker、其余采集器和结果回收仍由 .5 的唯一入口通过 SSH 管理。
若需要机器重启后自动启动 DCGM,应由运维另行决定是否执行
systemctl enable nvidia-dcgm。
all 内部执行顺序:
配置、工具、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
Phase 1 的作用是提供已经验证过的双机 Docker 服务和 Benchmark 实现,
不是第二个用户入口。实际展开的服务、Benchmark 和采集命令都会写入
results/<RUN_ID>/service/、commands/ 和
head|worker/collector_commands/,不依赖跨文档猜测。
5. 采集指标
本节记录正式实现使用的命令,而不是建议性伪代码。命令由
run_hardware_contention_attribution.sh 在 Head 和 Worker 同时启动;
每条展开后的命令会另外保存在
results/<RUN_ID>/head|worker/collector_commands/。
| 层级 | 连续采样 | 静态或前后快照 |
|---|---|---|
| GPU | 利用率、Memory Utilization、显存、功耗、SM/Memory Clock、温度、P-state | nvidia-smi topo -m、Compute Process |
| CPU | 每核利用率、上下文切换、服务进程 CPU/内存 | NUMA 拓扑、容器 PID 与 CPU Affinity |
| Network | eth0/eth3 RX/TX | ethtool -S 错误计数前后差 |
| RDMA | mlx5_0/mlx5_3 port_xmit/recv_data 差分 | Port State、GID 与错误计数 |
| DCGM | SM Active、DRAM Active、Tensor Active、PCIe | 工具版本与可用 Field |
5.1 时间对齐与 Case Marker
# 每条 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
| 数据 | 含义 | 为什么需要 |
|---|---|---|
wall_time_ns | Unix Epoch 纳秒时间 | 把 GPU、CPU、RDMA 与 Benchmark 放到同一时间轴 |
case_start/case_end | 一个 Case 的编排边界 | 从整段连续采样中切出对应负载 |
CLOCK_SKEW_TOLERANCE_S=2 | 两节点允许的最大秒级时钟差 | 避免 Head/Worker 的同一时刻被错位比较 |
最终实现由 Phase 1 监听 bench.log 中的
Starting main benchmark run,立刻写入
measurement_start.json;再使用 SGLang bench.json
的正式 benchmark duration 计算结束时间。Phase 2 优先读取
measurement_started_at/measurement_ended_at,不会把数据生成和
Warm-up 混入硬件均值。REQUIRE_PRECISE_WINDOWS=1 时,任何 Case
缺少精确窗口都会让汇总失败,而不是悄悄回退。
5.2 GPU 基础状态:nvidia-smi
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
脚本每秒运行一次,并在每行前加入 wall_time_ns 和节点角色。
| 字段 | 代表什么 |
|---|---|
utilization.gpu | 采样周期内至少有一个 Kernel 在执行的时间比例 |
utilization.memory | 采样周期内显存控制器处于忙碌状态的时间比例 |
memory.used/total | 当前总显存分配量与设备显存容量 |
power.draw | GPU 当前功耗,用于比较不同负载的能耗状态 |
clocks.sm/clocks.mem | SM 与显存当前工作频率 |
pstate | GPU 性能状态,P0 通常是最高性能态 |
原始输出为 head|worker/gpu_samples.csv;
gpu_summary.csv 汇总整段运行,
case_gpu_summary.csv 按节点、Case 和 GPU 汇总平均值与峰值。
5.3 GPU Profiling Counter:DCGM
DCGM_FIELD_IDS=1001,1002,1003,1004,1005,1009,1010
dcgmi dmon \
-e 1001,1002,1003,1004,1005,1009,1010 \
-d 1000
| Field ID | Field Tag | 含义 |
|---|---|---|
| 1001 | gr_engine_active | Graphics/Compute Engine 活跃比例,接近整体 GPU 执行忙碌度 |
| 1002 | sm_active | SM 至少有一个 Warp 活跃的比例 |
| 1003 | sm_occupancy | 活跃 Warp 相对硬件可容纳 Warp 的比例 |
| 1004 | tensor_active | Tensor Core 指令活跃比例 |
| 1005 | dram_active | 设备显存接口活跃比例;Pro6000D 为 GDDR7,用于判断设备显存带宽压力 |
| 1009 | pcie_tx_bytes | GPU 经 PCIe 发出的字节速率 |
| 1010 | pcie_rx_bytes | GPU 经 PCIe 接收的字节速率 |
sm_active 高而 sm_occupancy 低,表示 SM 经常有工作,
但同时驻留的 Warp 不多;后续通过 Kernel Timeline 区分小 Kernel、
寄存器/共享内存约束和同步。DCGM 是 NVIDIA Data Center GPU Manager:
nvidia-dcgm/nv-hostengine 是后台 Host Engine,
dcgmi 是客户端,Field ID 是指标编号。最终代码在两节点预检
dcgmi discovery -l,任一 Host Engine 不可用即 fail-fast;
正式结果必须同时包含 Head 和 Worker 的 case_dcgm_summary.csv。
5.4 CPU、进程与 Kernel Launch 侧证据
# 全部逻辑 CPU,每 5 秒输出一次
mpstat -P ALL 5
# 找到容器内进程对应的宿主 PID
docker top <container> -eo pid,ppid,psr,pcpu,pmem,stat,comm,args
# 最终命令:进程级 CPU、I/O、缺页、上下文切换,不展开全部线程
pidstat -durw -p "<comma-separated-host-pids>" 5
# 每 5 秒输出一次硬件/软件计数器增量
perf stat -p "<comma-separated-host-pids>" -I 5000 \
-e cycles,instructions,cache-misses,context-switches,\
cpu-migrations,page-faults
# mpstat/pidstat/perf 每行都由包装器增加:
# wall_time_ns TAB node TAB 原始输出
| 命令/字段 | 回答的问题 |
|---|---|
mpstat -P ALL | 整机是否 CPU 饱和,是否只有少量核心接近 100%,是否存在 I/O Wait |
docker top | 把容器进程映射为宿主 PID、CPU 核 PSR 和进程状态 |
pidstat -u | 服务进程的用户态、内核态 CPU 时间 |
pidstat -d | 进程块设备 I/O |
pidstat -r | 内存和 Page Fault 行为 |
pidstat -w | 主动/被动上下文切换,辅助发现线程阻塞或调度抖动 |
perf cycles/instructions | CPU 周期与指令执行量,可计算近似 IPC |
cache-misses/migrations | CPU Cache 压力和线程跨核迁移 |
最终实现使用进程级 5 秒采样,避免首轮线程级 1 秒采样产生数百 MB 日志。
case_cpu_summary.csv、case_process_summary.csv 和
case_perf_summary.csv 都按正式测量窗口切片;只有先发现异常进程,
才在后续短窗口单独开启线程级采样。
5.5 NUMA 与 CPU/内存亲和
# 静态 NUMA 节点、CPU 和内存布局
numactl --hardware
numastat -m
# 每 5 秒按容器宿主 PID 查看本地/远端 NUMA 内存
numastat -p <host-pid>
# 解析为:
# wall_time_ns,node,node0_mib,node1_mib,total_mib,process_count
# 同时保存 GPU、CPU、NIC 的拓扑关系
nvidia-smi topo -m
NUMA 是多路 CPU 机器的“本地内存”结构。进程长期从远端 NUMA Node 取内存,
或 GPU/NIC 对应的 CPU 线程被调度到另一侧,可能增加 Host 侧延迟。
最终采集器把 numastat -p 解析为
numa_samples.csv,再按正式测量窗口生成
case_numa_summary.csv。这样可以直接比较 Node0/Node1 MiB,
而不是依靠人工阅读不断刷新的文本。
5.6 普通网卡统计与 RDMA 数据面
# 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
sar 记录 Linux 普通网络栈中的 eth0/eth3 流量;
GDRDMA 数据量由 mlx5_0/mlx5_3 HCA 的 sysfs Counter 记录:
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
| Counter | 含义 |
|---|---|
port_xmit_data/port_rcv_data | HCA 发送/接收数据累计量;IB Counter 单位是 4 Octets,脚本用 delta × 4 × 8 / seconds 换算 Gbit/s |
port_xmit_wait | 端口因缺少发送 Credit 等原因等待的时间,持续增长可能指向拥塞 |
port_xmit_discards/port_rcv_errors | 发送丢弃和接收错误增量 |
req_transport_retries_exceeded | RDMA Transport 重试耗尽 |
req_rnr_retries_exceeded | Receiver Not Ready 重试耗尽 |
roce_adp_retrans* | RoCE 自适应重传及超时相关计数 |
np_ecn_marked* / *cnp* | ECN 标记和拥塞通知包,用于辅助判断 RoCE 拥塞 |
原始数据为 head|worker/rdma.csv;
case_rdma_summary.csv 按 Case、节点和 HCA 计算吞吐及错误增量。
它说明双 Rail 的实际流量、均衡性和错误增量;
case_netdev_summary.csv 同时保留 Linux netdev 层的
eth0/eth3 RX/TX 与错误。Phase 3 再把 NCCL Collective
放到请求 Timeline 中分析持续时间和计算重叠。
5.7 机内 PCIe 与 NCCL 通信基线
# 由 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 <0-or-1> \
communication_baseline.py all-reduce \
--sizes 1M,64M,1G --repetitions 3 --warmup 5 --iterations 10
P2P 结果按 same_pcie_switch(PIX)和
cross_numa_sys(SYS)分别汇总,不用一个平均值掩盖跨 CPU 路径。
AllReduce 同时报告 P50/P95 latency、algbw、
busbw、正确性错误数和实际 NCCL 路径。1 MiB、64 MiB、1 GiB
分别覆盖小消息延迟、中等消息和大消息带宽;双机 A/B 直接给出
NCCL_CROSS_NIC=0/1/2 的数值比较。
5.8 静态快照与结果关系
nvidia-smi
nvidia-smi topo -m
lscpu
numactl --hardware
ip -details link show eth0
ip -details link show eth3
docker inspect <container>
docker top <container> -eo pid,ppid,psr,pcpu,pmem,stat,comm,args
| 结果文件 | 内容 | 主要用途 |
|---|---|---|
static_before.log / static_after.log | GPU、CPU、NUMA、NIC、RDMA、容器前后快照 | 证明运行环境,并比较错误计数和清理状态 |
collector_status.csv | 每个采集器的启动、停止或提前退出状态 | 防止把缺失采集器当作 0 值 |
case_windows.csv | 每个 Benchmark Case 的起止时间 | 从连续硬件日志中切片 |
bench_summary.csv | TPS、TTFT、TPOT、ITL、E2E | 把硬件现象与用户侧性能对应 |
case_gpu_summary.csv | 每 Case、节点、GPU 的利用率、显存、功耗、频率 | 比较负载与节点/GPU 不均衡 |
case_dcgm_summary.csv | 每 Case、节点、GPU 的 SM/Tensor/显存接口/PCIe 指标 | 区分计算、设备显存和 PCIe 活跃度 |
case_cpu_summary.csv | 整机与逐核 CPU 利用率、I/O Wait | 识别整机饱和和少数热点核 |
case_process_summary.csv | 服务进程 CPU、I/O、缺页、内存与上下文切换 | 定位 Host 进程开销与阻塞 |
case_perf_summary.csv | cycles、instructions、cache miss、迁移与缺页 | 计算 IPC 并判断 Cache/调度压力 |
case_numa_summary.csv | Node0/Node1 进程内存分布 | 识别跨 NUMA 放置 |
case_netdev_summary.csv | eth0/eth3 吞吐与错误 | 与 RDMA HCA Counter 做分层核对 |
case_rdma_summary.csv | 每 Case、节点、Rail 的吞吐和错误增量 | 判断双 Rail 使用、均衡和数据面错误 |
communication_summary.csv | 每次 P2P/AllReduce 原始测量 | 保留每条 GPU 对、消息尺寸、CROSS_NIC 和重复实验 |
communication_aggregate.csv | PIX/SYS P2P 与单/双机 AllReduce 聚合 | 提供 P50/P95、algbw、busbw 和正确性比较 |
5.9 最终结果如何逐项汇报
最终 report.md 的章节顺序与本节一一对应。每一项必须同时给出
原始文件、有效样本数、Head/Worker 数值、Case 间变化和解释;
不能只写“GPU 较忙”“网络未饱和”这类抽象结论。
| 第 5 节指标 | 报告中的数值 | 最小分析动作 |
|---|---|---|
| 5.1 时间窗 | 窗口来源、开始/结束、duration、采样数 | 确认全部为 bench_main_marker_plus_duration |
| 5.2 GPU | 利用率/显存/功耗/频率的 Mean、P95、Max | 比较两节点、8 卡离散度和不同 Case |
| 5.3 DCGM | SM Active/Occupancy、Tensor/DRAM Active、PCIe TX/RX | 比较计算、设备显存和 PCIe 哪一侧随负载上升 |
| 5.4 CPU/进程/perf | 整机/热点核、进程 CPU/I/O/缺页/切换、IPC/Cache miss | 区分整机容量、单线程热点和 Host 调度开销 |
| 5.5 NUMA | Node0/Node1 MiB 与比例 | 比较服务内存是否偏离 GPU/NIC 所在 NUMA |
| 5.6 Network/RDMA | eth0/eth3、mlx5_0/mlx5_3 Gbit/s 与错误增量 | 计算双 Rail 均衡比例并核对丢弃/重试 |
| 5.7 Communication | PIX/SYS P2P、8/16 rank AllReduce P50/P95、algbw/busbw | 比较跨 NUMA 损失与 CROSS_NIC 0/1/2 |
某个采集器无数据时报告显示 - 并附失败状态,不会把缺失值写成
0。正式 Run 默认 ALLOW_PARTIAL_COLLECTORS=0,
因此必需采集器提前退出会让 Run 失败。
6. 精简代码设计
已新增目录:
/data/hzy/sskj/experiments/pro6000/
dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/
| 文件 | 职责 | 当前状态 |
|---|---|---|
run_hardware_contention_attribution.sh | 唯一 Shell 入口;按 Run 分发通信代码、通信基线、服务启停、双节点采集器、Case 编排、门禁和 Trap 清理 | 已实现 |
config.env | Phase 1 相对路径、节点、代表 Case、分层采样周期、通信基线与 fail-closed 策略 | 已实现 |
communication_baseline.py | CUDA P2P 全矩阵与 PyTorch/NCCL 8/16-rank AllReduce 微基准 | 已实现 |
hardware_contention_attribution.py | 精确窗口、全部采集器解析、逐 Case 汇总、通信聚合和逐指标报告 | 已实现 |
tests/test_hardware_contention_attribution.py | Worker 无仓库依赖、GPU/RDMA、精确窗口、DCGM/CPU 解析、通信聚合和结果生成测试 | 9/9 通过 |
README.md | 唯一入口、范围和结果目录说明 | 已实现 |
Phase 2 不复制双机 Docker 启停实现。唯一入口在内部调用 Phase 1 的
run_quick_map.sh start/fixed/mixed/stop,只新增通信基线、硬件采集、时间对齐和代表负载编排。
顶层仍只保留一个 Shell 文件,不创建额外 tmux、launch、start 或 stop 脚本。
7. 结果结构
results/<RUN_ID>/
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
8. 最终验收
- 最终 Run
dsv4pro-phase2-20260731-163620状态为COMPLETED,8/8 benchmark 成功,0 失败、0 OOM。 - 8/8 Case 使用正式 benchmark 精确时间窗;18 个采集器全部记录
STARTED与STOPPED。 - Head 与 Worker 的 DCGM、GPU、CPU、进程、NUMA、网卡和 HCA Counter 均有有效样本。
- P2P、8-rank 和 16-rank AllReduce 全部完成,所有正确性检查均为
wrong_values=0。 - Run 结束后 Head/Worker 无相关容器、无 GPU 计算进程,端口
30002/30003已释放。
9. 正式运行
Run:dsv4pro-phase2-20260731-163620。
运行时间为 16:36:20 至 17:05:04 CST,总用时 28 分 44 秒。
Manifest 记录代码提交 5f24b7d22f98108f6cc234edba6768d55ea0a962,
git_dirty=false。
# 仅在 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>&1 | tee /data/hzy/${RUN_ID}.log"
10. 端到端结果
10.1 五个代表负载
| Case | Input TPS | Output TPS | TTFT P95 | TPOT P95 |
|---|---|---|---|---|
| 128K → 1, C=1 | 2,641.38 | 0.02 | 49.610 s | — |
| 32K → 1, C=16 | 3,115.45 | 0.10 | 161.938 s | — |
| 1K → 1K, C=32 | 448.95 | 448.95 | 10.167 s | 65.36 ms |
| 1K → 4K, C=16 | 79.39 | 317.56 | 1.724 s | 49.98 ms |
| 128K → 1K, C=1 | 1,614.99 | 12.62 | 48.279 s | 32.11 ms |
10.2 混合 Prefill/Decode A/B
| Decode 指标 | Control | 注入 128K Prefill | 变化 |
|---|---|---|---|
| Output TPS | 453.55 | 344.89 | -23.96% |
| TTFT P95 | 9.443 s | 9.892 s | +4.76% |
| TPOT P95 | 66.24 ms | 110.45 ms | +66.75% |
| E2E P95 | 72.270 s | 118.076 s | +63.38% |
这是 Phase 2 最关键的现象:长 Prefill 与 Decode 共存时,首 token 延迟只增加 4.76%,但 Decode 单 token 成本增加 66.75%,最终令 Output TPS 下降 23.96%。 问题主要发生在持续 Decode 阶段,而不是只表现为 Prefill 请求排队。
11. 第 5 节指标逐项结果
11.1 GPU 基础状态与 DCGM
服务器证据路径:
汇总:/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/case_gpu_summary.csv、
case_gpu_node_summary.csv、case_dcgm_summary.csv
原始:同一 Run 目录下的 head/gpu_samples.csv、worker/gpu_samples.csv、
head/dcgm_dmon.log、worker/dcgm_dmon.log
- 各 Case GPU Util Mean 大多为 94%–99%,P95 为 100%;SM Clock 约 2.39–2.42 GHz,未见降频。
- 每卡显存稳定在约 83,000–83,364 MiB。Decode 功耗约 216–258 W,Prefill 功耗约 293–307 W。
- 普通 Decode 的 SM Active 约 0.523–0.525、DRAM Active 约 0.415–0.417;128K Prefill 的 SM Active 升至 0.683–0.686。
- 32K C16 Prefill 的 SM Active 约 0.713–0.715、DRAM Active 约 0.440,是本轮最重的并发 Prefill 计算负载。
- 混合 Treatment 中,Decode 背景 SM Active 约 0.578–0.581;注入 Prefill 窗口升至 0.720–0.723,证明两类工作确实争用同一 GPU 执行资源。
11.2 CPU、进程与 NUMA
服务器证据路径:
汇总:/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/case_cpu_summary.csv、
case_process_summary.csv、case_perf_summary.csv、case_numa_summary.csv
原始:同一 Run 目录下 Head/Worker 各自的 mpstat.log、pidstat.log、
perf_stat.log、numa_samples.csv 和 docker_top.log
- 整机 CPU Active Mean 约 9.6%–10.4%,P95 约 10%–11.4%;没有全机 CPU 饱和。
- 服务进程峰值约 1,210%–1,226%,相当于约 12 个 CPU Core;热点 Core 数量最多 12–13 个。
perf观察到 IPC 约 2.7–3.1,未出现明显 Host 侧停摆。- Head/Worker 的 NUMA 不均衡约 21.1% / 13.2%,跨 Case 基本稳定;它是拓扑基线,但不像混合性能退化的直接诱因。
11.3 双 Rail RDMA
服务器证据路径:
汇总:/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/case_rdma_summary.csv、
rdma_summary.csv、case_netdev_summary.csv
原始:同一 Run 目录下的 head/rdma.csv、worker/rdma.csv、
head/sar_net.log、worker/sar_net.log;端口/HCA 静态状态在两端
static_before.log 与 static_after.log
- RoCE 绕过普通 Linux Socket 数据路径,因此
sar的eth0/eth3流量接近 0;实际流量必须看mlx5_0/mlx5_3HCA Counter。 - 普通 Decode 每 Rail 约 36.7–36.8 Gbit/s;128K Prefill 每 Rail约 70.5–71.5 Gbit/s。
- 最高点 32K C16 Prefill 每 Rail 约 83.0–83.45 Gbit/s,仅约占单条 400G Rail 的 20.9%。
- 两条 Rail 流量对称,
port_xmit_wait、丢弃、错误和 Retry Exceeded 增量均为 0。
11.4 PCIe 与 NCCL 通信基线
服务器证据路径:
汇总:/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution/results/dsv4pro-phase2-20260731-163620/communication_aggregate.csv、
communication_summary.csv
原始:同一 Run 目录的 communication/p2p_head.log、p2p_worker.log、
allreduce_head_8gpu.log、allreduce_worker_8gpu.log 和
allreduce_16gpu_crossnic{0,1,2}_{head,worker}.log;实际执行命令在 commands/communication_*.cmd.txt
| 测试 | 结果 | 解释 |
|---|---|---|
| Head PCIe P2P 256 MiB | 同 Switch 53.61 GB/s;跨 NUMA 52.40 GB/s | 跨 NUMA 损失约 2.3% |
| Worker PCIe P2P 256 MiB | 同 Switch 53.50 GB/s;跨 NUMA 52.32 GB/s | 两节点表现对称 |
| Head / Worker 8-GPU AllReduce 1 GiB | busbw 39.76 / 39.75 GB/s | 节点内基线一致 |
| 16-GPU AllReduce,CROSS_NIC=0 | busbw 39.345 GB/s;51.169 ms | 正确性 0 错误 |
| 16-GPU AllReduce,CROSS_NIC=1 | busbw 39.685 GB/s;50.732 ms | 本轮数值最好 |
| 16-GPU AllReduce,CROSS_NIC=2 | busbw 39.530 GB/s;50.931 ms | 正确性 0 错误 |
NCCL_CROSS_NIC=1 比 0 仅高 0.86%,比 2 仅高 0.39%。
差异小于 1%,不足以把它当成主要调优旋钮;保留当前值即可,Phase 3 不再重复测试。
NCCL 日志明确证明跨机路径使用 mlx5_0,mlx5_3 和
NET/IB/.../GDRDMA。
12. 结论与 Phase 3 入口
Phase 2 已把范围明显缩小:混合 Prefill/Decode 退化真实且稳定,
但不是由整机 CPU 饱和、GPU 降频、双 Rail 原始带宽饱和、Rail 失衡、
PCIe 跨 NUMA 带宽崩塌或 NCCL_CROSS_NIC 选择造成。
Phase 3 应只捕获 Control 与 Treatment 的短时间线,定位 Attention/Indexer、
MoE、NCCL Collective、Scheduler gap 和慢 Rank 同步之间的串行与重叠关系。
- 不重复 Phase 2 的长时间 DCGM、CPU、RDMA 和通信微基准。
- 优先对比混合 Control 与注入 128K Prefill 的 Treatment。
- 再用单独 128K Prefill 作为 Kernel 对照,解释 SM Active 与 Tensor Active 的来源。
13. 证据与清理说明
Worker 日志在所有 benchmark 完成后的编排关闭阶段出现 Gloo
Connection closed by peer;时间与 Head 主动退出进程组一致,
未影响 8/8 结果。NCCL 日志中的可选 mlx5 symbol 探测提示同样未影响
Collective,全部正确性检查为 0 错误。