Standalone Code Walkthrough / Phase 2

DSV4-Pro 双机 Pro6000D SGLang 硬件竞争归因:代码详解

行号基线:39fc2ba565a3  完成时间:2026-07-31 17:22:20 CST  唯一入口:run_hardware_contention_attribution.sh all

返回推理优化主计划 · 打开 Phase 2 实验档案

文档边界:本文只解释提交 39fc2ba565a3 的 Phase 2 代码和文件调用关系。Phase 1 负责模型服务与请求;Phase 2 负责通信基线、 两节点监控、精确时间切片和逐指标报告。最终正式 Run dsv4pro-phase2-20260731-163620 使用提交 5f24b7d22f98108f6cc234edba6768d55ea0a962,代码树包含本页所述修复。

1. 阅读导航

2. 总体控制流

main "$@" → run_all
  ├─ validate_config
  ├─ preflight_node_tools
  │    └─ 两节点 dcgmi discovery -l 必须成功
  ├─ preflight_clock_sync + preflight_gpus_idle
  ├─ run_communication_baseline
  │    ├─ 两节点 CUDA P2P 全矩阵
  │    ├─ 两节点各自 8-rank AllReduce
  │    └─ 16-rank AllReduce,CROSS_NIC=0/1/2
  ├─ start_service → Phase 1 start
  ├─ capture_static_snapshots before
  ├─ start_collectors → Head/Worker 同时采集
  ├─ idle → fixed cases → mixed A/B → cooldown
  ├─ check_collectors + stop_collectors
  ├─ capture_static_snapshots after
  ├─ stop_service → Phase 1 stop
  ├─ summarize_results
  │    └─ 按正式 benchmark 窗口生成第 5 节逐项数据表
  └─ finish_manifest

all 是唯一正式入口。communicationsummarizestop 是排错/恢复 action,不需要在正常执行前手工调用。

3. 文件职责与调用关系

文件行数职责
config.env61节点、Case、分层采样周期、通信尺寸、NCCL 选择和 fail-closed 策略。
run_hardware_contention_attribution.sh1036唯一 Shell 编排器:预检、通信文件分发、通信基线、Phase 1 委托、采集器、Case 和清理。
communication_baseline.py227CUDA P2P 全矩阵及 PyTorch/NCCL AllReduce 正确性、延迟和带宽测试。
hardware_contention_attribution.py1480解析所有原始采集器,按 Case 切片,聚合通信并生成 CSV/JSON/report.md。
tests/test_hardware_contention_attribution.py3229 项纯 Python 单元测试,覆盖 worker 无仓库依赖、精确窗口、解析器、RDMA 单位和通信聚合。
用户
  └─ Phase2/run_hardware_contention_attribution.sh all
       ├─ source Phase2/config.env
       ├─ docker/torchrun → Phase2/communication_baseline.py
       ├─ env ... bash Phase1/run_quick_map.sh start/fixed/mixed/stop
       │    └─ Phase1/quick_map_results.py 写 benchmark meta
       ├─ Shell 采集 Head/Worker 原始时间序列
       └─ Phase2/hardware_contention_attribution.py summarize
            ├─ 读取 Phase1 bench/cases/*/meta.json
            ├─ 读取 Head/Worker 原始监控
            ├─ 读取 communication/COMM_RESULT
            └─ 输出逐 Case、逐节点、逐指标表和 report.md

3.1 Phase 1 与 Phase 2 的边界

问题由哪个文件负责证据
模型路径、镜像、TP16、EP、显存比例Phase 1 config.env + run_quick_map.shservice/head_server_cmd.txtworker_server_cmd.txt
ISL/OSL/C、random 请求和 mixed A/BPhase 1 场景表与 benchmark 函数bench/*/bench_cmd.txtbench.json
通信基线、监控周期、Case 选择Phase 2 config.envPhase 2 manifest.json
硬件归因和数值报告Phase 2 Python 汇总器case_*_summary.csvreport.md

4. 配置来源

行号配置组关键变量
config.env:L3-L16入口与节点PHASE1_ENTRY、Head/Worker、端口和容器名。
L18-L21诊断 Case五个 fixed Case、mixed A/B 开关。
L23-L39采样与严格性GPU/DCGM/RDMA 1 秒;CPU/进程/网络/NUMA/perf 5 秒;精确窗口和采集器 fail-closed。
L40-L55通信基线镜像、消息尺寸、迭代次数、P2P 大小、CROSS_NIC 列表、Socket/HCA。
L57-L61路径与模式RESULT_BASE、Runtime、Dry-run、是否允许部分采集器。

MEM_FRACTION_STATIC 不在 Phase 2 重复定义。它仍来自 Phase 1, 最终展开为 SGLang 的 --mem-fraction-static。判断某次 Run 的真实值, 应读取 service/head_server_cmd.txt,不能只看默认配置。

5. 通信微基准

5.1 Shell 如何编排

run_hardware_contention_attribution.sh:L281-L513 负责源码暂存、 Docker 命令、两节点同步和清理。所有命令先写入 commands/*.txt

Docker 使用和 SGLang 一致的 CUDA 13 nightly 镜像,并显式透传 rdma_cmuverbs0uverbs3NCCL_DEBUG=INFO 只在微基准中打开,用于证明 NET/IB/GDRDMA 路径。 Worker 不要求存在 Git 仓库;容器只读挂载自动分发的 /tmp/.../<RUN_ID>/communication_baseline.py。结果目录同时保存 当次源码副本和 SHA256,避免两个节点 checkout 不一致造成版本漂移。

5.2 P2P 代码

communication_baseline.py:L45-L106 遍历所有源 GPU 和目标 GPU, 先调用 torch.cuda.can_device_access_peer,再对 256 MiB FP16 Tensor 做预热和 CUDA Event 计时。输出包括方向、P50/P95 latency 和 GB/s。 汇总器按拓扑拆成同 PCIe Switch 的 PIX 与跨 NUMA 的 SYS。

5.3 AllReduce 代码

communication_baseline.py:L107-L198 初始化 NCCL process group, 对 1 MiB、64 MiB、1 GiB 分别预热和重复测量。每轮先把各 rank latency gather 到 rank 0,使用最慢 rank 作为 collective 完成时间,并检查归约结果:

algbw = message_bytes / latency
busbw = algbw × 2 × (world_size - 1) / world_size
wrong_values = count(output != expected_sum)

这样不会用某个提前返回 rank 的时间美化结果;wrong_values=0 才算正确完成。

6. 两节点采集器

6.1 启动前门禁

Shell L67-L199 完成配置、工具、时钟和 GPU 空闲检查。 preflight_node_tools 不只检查 dcgmi 文件存在, 还实际运行 dcgmi discovery -l;两节点任一 Host Engine 不可用即退出。

6.2 采集器包装

start_stream_collector 位于 Shell L517-L551。 它保存完整命令、PID、唯一进程 tag 和日志;check_collectorsL722-L740 检查采集器是否提前退出,默认不允许部分成功。

采集器Shell 位置周期输出
nvidia-smiL552-L5651 秒gpu_samples.csv
RDMA HCA countersL566-L5921 秒rdma.csv
DCGML645-L6551 秒dcgm_dmon.log
mpstatL656-L6635 秒mpstat.log
pidstat -durwL664-L6715 秒,进程级pidstat.log
sar -n DEV,EDEVL672-L6785 秒sar_net.log
perf statL680-L6895 秒perf_stat.log
numastatL618-L6445 秒numa_samples.csv

CPU、进程、perf 和 sar 的每行均由 Shell 增加 wall_time_ns TAB node TAB payload。NUMA 直接转成结构化 CSV, 避免旧版线程级 1 秒日志过大,也让所有指标能按 Case 切片。

7. 精确测量窗口

7.1 Phase 1 如何标记主测量

Phase 1 run_quick_map.sh:L547-L564 每 100 ms 观察 bench 日志; 发现 Starting main benchmark run 后调用 quick_map_results.py mark-measurement-startquick_map_results.py:L340-L385 用这个起点和 bench.json.duration 生成:

measurement_started_at
measurement_ended_at
measurement_duration_s
measurement_window_source = bench_main_marker_plus_duration

7.2 Phase 2 如何使用

hardware_contention_attribution.py:L509-L560 优先读取上述字段。 只有兼容旧结果时才可能使用进程级窗口;正式配置 REQUIRE_PRECISE_WINDOWS=1 会拒绝任何 fallback。 L561-L841 对 GPU、DCGM、CPU、进程、perf、NUMA、netdev 和 RDMA 使用同一个 started_ns ≤ sample ≤ ended_ns 条件。

8. 逐指标报告

Python summarize 位于 hardware_contention_attribution.py:L1036-L1378。 它不只生成一个抽象结论,而是按 Phase 2 第 5 节依次写出:

指标解析函数Case 汇总文件
GPUsummarize_gpu_rows L377-L413case_gpu_summary.csvcase_gpu_node_summary.csv
DCGMparse_dcgm L167-L192case_dcgm_summary.csv
CPUparse_mpstat L193-L222case_cpu_summary.csv
进程parse_pidstat L223-L289case_process_summary.csv
perfparse_perf L290-L310case_perf_summary.csv
NUMA结构化 CSV + summarize_case_metricscase_numa_summary.csv
Linux netdevparse_sar_net L311-L358case_netdev_summary.csv
RDMAsummarize_rdma_rows L424-L484case_rdma_summary.csv
P2P/NCCLload_communication_rows + aggregate_communication_rows L842-L928communication_summary.csvcommunication_aggregate.csv

report.md 对每组都打印有效样本数、Mean/P95/Max、Head/Worker 或 Case 间比较和源文件。解析不到的值保留为 -,不会被写成 0。

9. 结果目录

results/<RUN_ID>/
  manifest.json
  commands/
  communication/
  service/
  bench/<phase1-sub-run>/
  head/
    gpu_samples.csv
    dcgm_dmon.log
    mpstat.log
    pidstat.log
    perf_stat.log
    sar_net.log
    numa_samples.csv
    rdma.csv
    collector_commands/
  worker/
    ...同上...
  case_windows.csv
  bench_summary.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
  communication_summary.csv
  communication_aggregate.csv
  summary.json
  report.md

10. 函数行号索引

10.1 Shell 编排器

行号函数组职责
L26-L66日志、远端执行、命令证据基础设施。
L67-L199配置、工具、时钟、GPU 空闲门禁正式运行前 fail-fast。
L200-L268Manifest、marker、Phase 1 委托运行身份与复用边界。
L281-L513通信基线按 Run 分发源码、P2P、8/16-rank AllReduce、CROSS_NIC A/B 与清理。
L448-L516服务和静态快照启停 Phase 1 双机服务并保存环境。
L517-L710采集命令与启动两节点分层采样。
L711-L772采集器检查和停止fail-closed 与残留清理。
L782-L835fixed/mixed Case代表负载编排。
L836-L858汇总、Manifest、trap结果收口。
L859-L928run_all完整状态机。
L929-L968辅助 action 与 maincommunication/all/summarize/stop 分发。

10.2 Python 文件

文件/行号职责
communication_baseline.py:L20-L44尺寸解析、分位数和 JSON 结果协议。
L45-L106CUDA P2P 全矩阵。
L107-L198NCCL AllReduce 与正确性。
hardware_contention_attribution.py:L76-L166时间、CSV、数字统计基础函数。
L167-L358DCGM、mpstat、pidstat、perf、sar 解析器。
L359-L508通信、GPU、RDMA、bench 读取与汇总。
L509-L841精确窗口和全部 Case 指标切片。
L842-L1035通信聚合、CSV、Marker、Manifest。
L1036-L1378全部输出表和逐指标 report.md
L1379-L1480CLI 子命令。

11. 最终 Run 证据

正式 Run 完成 8/8 benchmark、8/8 精确测量窗口和 18/18 采集器启停。 代码产生的各类输出与实验结论一一对应: