From 7be3062c51224f8886a01a59020a7fa04dae0e51 Mon Sep 17 00:00:00 2001 From: Zhiyi Hong <2497491955@qq.com> Date: Fri, 31 Jul 2026 17:00:22 +0800 Subject: [PATCH] [Docs] unify phase experiment archive naming --- README.md | 4 + .../phase1_code.html | 4 + ..._sglang_quick_map.html => phase1_exp.html} | 229 +++++- .../phase2_code.html | 4 + ...ntion_attribution.html => phase2_exp.html} | 4 +- .../report.md | 12 + .../run_manifest.json | 42 + .../summary.csv | 3 + .../推理优化计划.html | 23 +- .../推理优化计划.md | 737 ++++++++++++++++++ .../Hy3_Preview_AI_Infra_精读笔记.md | 659 ++++++++++++++++ 11 files changed, 1695 insertions(+), 26 deletions(-) rename docs/dsv4pro_pro6000d_2node_sglang/{phase1_dsv4pro_pro6000d_2node_sglang_quick_map.html => phase1_exp.html} (69%) rename docs/dsv4pro_pro6000d_2node_sglang/{phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html => phase2_exp.html} (99%) create mode 100644 docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/report.md create mode 100644 docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/run_manifest.json create mode 100644 docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/summary.csv create mode 100644 docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.md create mode 100644 docs/hy3_infra_article/Hy3_Preview_AI_Infra_精读笔记.md diff --git a/README.md b/README.md index 5e3cca4..41967e1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # sskj — 多平台大模型推理性能基准测试项目 +> **更新(2026-07-31 16:46:05 CST)** +> +> 统一 DeepSeek-V4-Pro 推理优化档案命名与导航:Phase 1/2 实验页分别更名为 `phase1_exp.html`、`phase2_exp.html`,代码页保持 `phase1_code.html`、`phase2_code.html`。主计划中的入口统一为“打开 Phase N 实验档案 / 代码详解”,并为实验页与代码页补齐双向链接。Phase 1 状态同步为固定点 11/11、混合 A/B 3/3、阶段总结果 14/14。 +> > **更新(2026-07-31 16:27:58 CST)** > > 完成 Phase 2 Worker 通信代码分发的双节点真机 smoke test。Run `dsv4pro-phase2-stage-smoke-20260731-162326` 依次通过 Head/Worker P2P、两组单机 8-rank AllReduce 和一组双机 16-rank AllReduce,全部 `wrong_values=0`。两节点暂存文件 SHA256 一致;结束后 `/tmp` 暂存、通信容器和 GPU 进程均已清理。本次使用 1 MiB、单次迭代,仅验证执行链路,不作为正式性能数据。 diff --git a/docs/dsv4pro_pro6000d_2node_sglang/phase1_code.html b/docs/dsv4pro_pro6000d_2node_sglang/phase1_code.html index 5f4e157..6d60e26 100644 --- a/docs/dsv4pro_pro6000d_2node_sglang/phase1_code.html +++ b/docs/dsv4pro_pro6000d_2node_sglang/phase1_code.html @@ -134,6 +134,10 @@
+

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

文档边界:这是一份独立代码档案,只解释 Phase 1 实现,不承担阶段结论展示。 下文的行号均绑定提交 ca1f2f63375c。代码变更后应先更新基线提交,再重新核对行号。 diff --git a/docs/dsv4pro_pro6000d_2node_sglang/phase1_dsv4pro_pro6000d_2node_sglang_quick_map.html b/docs/dsv4pro_pro6000d_2node_sglang/phase1_exp.html similarity index 69% rename from docs/dsv4pro_pro6000d_2node_sglang/phase1_dsv4pro_pro6000d_2node_sglang_quick_map.html rename to docs/dsv4pro_pro6000d_2node_sglang/phase1_exp.html index d12d64d..baab43d 100644 --- a/docs/dsv4pro_pro6000d_2node_sglang/phase1_dsv4pro_pro6000d_2node_sglang_quick_map.html +++ b/docs/dsv4pro_pro6000d_2node_sglang/phase1_exp.html @@ -234,19 +234,23 @@
节点:174.1.51.5 + 174.1.51.7 拓扑:SGLang TP16 / EP2 - 更新:2026-07-30 22:55:37 CST + 更新:2026-07-31 16:46:05 CST
返回推理优化主计划 + 打开 Phase 1 代码详解

阶段状态:已完成。 正式 Run dsv4pro-phase1-full-20260730-220916 在双 Rail NET/IB + GDRDMA 下完成 9 个固定点和 3 个混合 A/B 结果, - 共 12/12 成功,用时 28 分 36 秒;服务、容器与 16 张 GPU 已清理。 + 共 12/12 成功,用时 28 分 36 秒。补充 Run + dsv4pro-phase1-long-decode-20260730-234236 完成长输出与 + 长上下文 Decode 2/2。两个 Run 合计 11 个固定点和 3 个混合结果, + 14/14 成功;服务、容器与 16 张 GPU 已清理。

1. 目标与边界

@@ -287,7 +291,7 @@ dsv4pro_pro6000d_2node_sglang_tp16_quick_map/ quick_map_scenarios.tsv - 九个固定工作负载点 + 十一个固定工作负载点 quick_map_results.py @@ -392,13 +396,16 @@ bash run_quick_map.sh stop decode_throughput_1k_to_1k_c161K1K16Decode 吞吐 decode_throughput_1k_to_1k_c321K1K32Decode 吞吐 decode_throughput_1k_to_1k_c641K1K64Decode 高并发 + long_output_decode_1k_to_4k_c161K4K16持续 Decode 与 KV 增长 + long_context_decode_128k_to_1k_c1128K1K1长上下文上的 Decode 成本 balanced_32k_to_1k_c832K1K8综合压力

快速 Run 使用一次重复和一波测量请求,即 num_prompts=C。 - 32K/128K Prefill 不做昂贵的同形状 Warm-up;短 Prefill 与 Decode 使用一个 - Warm-up,并在正式计时前清空 Prefix Cache。固定矩阵不做 SLO 截断或自适应并发搜索。 + 32K/128K Prefill 与 128K 长上下文 Decode 不做昂贵的同形状 Warm-up; + 短 Prefill、普通 Decode 与 1K → 4K 长输出 Decode 使用一个 Warm-up, + 并在正式计时前清空 Prefix Cache。固定矩阵不做 SLO 截断或自适应并发搜索。

5. SGLang Benchmark 与 Prefix Cache

@@ -534,13 +541,14 @@ wait "${background_pid}" Shell 语法通过bash -n run_quick_map.sh Python 单测3/3 通过场景唯一性、百分位回退、失败结果汇总 - 完整 Dry-run通过服务、九个固定点、混合 A/B、清理均展开成功 + 完整 Dry-run通过服务、十一个固定点、混合 A/B、清理均展开成功 真实旧 Bench JSON 解析通过成功解析 P50/P95/P99 与吞吐字段 项目精简通过实验目录顶层仅保留一个 Shell 入口 双 Rail 传输门禁通过Head 与 Worker 均识别 mlx5_0/mlx5_3,跨节点 Channel 使用 NET/IB/*/GDRDMA 四点 Sanity4/4 通过1K/32K Prefill 与 C1/C32 Decode 均恢复到合理量级 冷 Prefix 口径通过正式测量请求的 Head 日志显示 #cached-token: 0 完整真机 Run12/12 通过固定矩阵 9/9,混合 A/B 3/3,运行期失败 0 + 长 Decode 补测2/2 通过1K → 4K C16 与 128K → 1K C1 均生成完整目标 OSL 资源清理通过两节点相关容器与计算进程为 0,16 张 GPU 显存占用为 0 @@ -560,7 +568,9 @@ wait "${background_pid}" Run IDdsv4pro-phase1-full-20260730-220916COMPLETED 运行时间28 分 36 秒22:09:47 至 22:38:22 CST 网络路径双 Rail NET/IB + GDRDMAmlx5_0mlx5_3 - 结果完整性12/12 成功固定点 9/9;混合 A/B 3/3 + 正式 Run 完整性12/12 成功固定点 9/9;混合 A/B 3/3 + 补充 Rundsv4pro-phase1-long-decode-20260730-234236固定点 2/2;约 12 分钟含服务启动与清理 + 阶段合计14/14 成功固定点 11/11;混合 A/B 3/3 @@ -596,7 +606,30 @@ wait "${background_pid}" 说明 Prefill 与 Decode 同时存在时干扰很强。

-

9.4 混合 Prefill/Decode A/B

+

9.4 长 Decode 补测

+ + + + + + + + +
场景Output TPSTTFT P95TPOT P95E2E P95
1K → 4K,C=16310.02 tok/s6.241 s50.33 ms211.364 s
128K → 1K,C=112.43 tok/s49.326 s32.24 ms82.312 s
+

+ 1K → 4K,C=16 相比 1K → 1K,C=16, + Output TPS 增加 4.99%,TPOT P95 只增加 0.62%。较长 Decode 没有出现 + 稳态吞吐塌陷;吞吐略升是固定启动和 Prefill 成本被更多输出 token 摊薄。 +

+

+ 128K → 1K,C=1 的 TTFT 只比 128K → 1 + 纯 Prefill 高 2.03%,而 TPOT P95 只比 1K → 1K,C=1 + 高 2.47%。因此这次长上下文请求的主要新增成本在 Prefill,而不是每个 Decode + token。表中的 12.43 Output TPS 是把 49 秒 Prefill 也计入总时长的端到端值, + 不能把它误读为纯 Decode 速率。 +

+ +

9.5 混合 Prefill/Decode A/B

@@ -609,16 +642,23 @@ wait "${background_pid}"
指标A:仅 DecodeB:注入 128K Prefill变化

- Phase 2 在上述长 Prefill、并发 Prefill和混合 A/B 之外,还会采集普通 Decode、 - 长输出 Decode 与长上下文 Decode。目标是区分计算、显存带宽、调度排队、 - 跨机通信、KV 增长和节点不均衡。 + Phase 2 重放五个固定代表点: + 128K → 1,C=132K → 1,C=16、 + 1K → 1K,C=321K → 4K,C=16、 + 128K → 1K,C=1,再执行有无 128K 注入的混合 A/B。 + 目标是区分计算、显存带宽、调度排队、跨机通信和节点不均衡。

完整产物: 报告逐点汇总聚合表、 - 运行清单。 + 运行清单; + 长 Decode 补测的 + 报告、 + 逐点汇总 + 和 + 运行清单

10. 经验教训

@@ -635,7 +675,15 @@ wait "${background_pid}" 不作为本阶段最终结果。

-

11. 运行命令

+

11. 实验复现命令

+

+ 本节记录的是本阶段实际执行过的命令。长命令同时由程序原样保存到 + results/<RUN_ID>/server/*_server_cmd.txt 和每个 Case 的 + bench_cmd.txt;这些落盘文件是最终证据,正文中的换行仅用于阅读。 +

+ +

11.1 实际执行:完整 Phase 1

+

执行位置:174.1.51.5;脚本通过 SSH 启动 .7 Worker。

cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map
 
 tmux new-session -d -s dsv4pro-phase1-full \
@@ -643,11 +691,162 @@ tmux new-session -d -s dsv4pro-phase1-full \
    2>&1 | tee /data/hzy/dsv4pro_phase1_full_20260730-220916.log"
 
 tmux attach -t dsv4pro-phase1-full
+

+ all 的真实顺序是: + Worker 启动 → Head 启动 → /health → NET/IB 门禁 → fixed → mixed → stop → summarize。 +

+ +

11.2 实际执行:Worker 服务

+
+ 展开 174.1.51.7 的完整 docker run +
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
+
+ +

11.3 实际执行:Head 服务

+
+ 展开 174.1.51.5 的完整 docker run +
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
+
+

+ NCCL_IB_HCA==... 的两个等号不是笔误:第一个是环境变量赋值分隔符, + 第二个是 NCCL HCA 列表的“精确匹配”前缀。 +

+ +

11.4 实际执行:代表 Benchmark

+

以下是正式 Run 的 128K → 1, C=1 冷 Prefix 命令:

+
+ 展开完整 sglang.benchmark.serving 命令 +
timeout --signal=TERM --kill-after=30s 7200s \
+docker run --rm \
+  --network host \
+  -v /data/hf_models/DeepSeek-V4-Pro:/data/hf_models/DeepSeek-V4-Pro:ro \
+  -v /data/yy/sskj/dataset/ShareGPT_V3_unfiltered_cleaned_split.json:/data/yy/sskj/dataset/ShareGPT_V3_unfiltered_cleaned_split.json:ro \
+  -v /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-full-20260730-220916/cases/long_prefill_latency_128k_c1/rep1:/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-full-20260730-220916/cases/long_prefill_latency_128k_c1/rep1 \
+  -e PYTHONUNBUFFERED=1 \
+  -e HF_HUB_OFFLINE=1 \
+  -e TRANSFORMERS_OFFLINE=1 \
+  --entrypoint python3 \
+  lmsysorg/sglang:nightly-dev-cu13-20260720-b3570a45 \
+  -m sglang.benchmark.serving \
+  --backend sglang \
+  --host 10.101.0.11 \
+  --port 30002 \
+  --dataset-name random \
+  --dataset-path /data/yy/sskj/dataset/ShareGPT_V3_unfiltered_cleaned_split.json \
+  --random-input-len 131072 \
+  --random-output-len 1 \
+  --random-range-ratio 1.0 \
+  --num-prompts 1 \
+  --max-concurrency 1 \
+  --request-rate 10000 \
+  --output-file /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-full-20260730-220916/cases/long_prefill_latency_128k_c1/rep1/bench.jsonl \
+  --output-details \
+  --disable-tqdm \
+  --warmup-requests 0 \
+  --seed 42 \
+  --flush-cache
+
+

+ 其余固定点使用同一命令模板,只替换 ISL、OSL、并发、请求数、Warm-up、Seed + 和输出目录。每个点的最终展开命令保存在自己的 bench_cmd.txt。 + 混合 A/B 的并行启动顺序和两条请求命令见第 6 节及相应 Case 目录。 +

+ +

11.5 实际执行:长 Decode 补测

+
cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map
+
+export CASE_IDS="long_output_decode_1k_to_4k_c16,long_context_decode_128k_to_1k_c1"
+export RUN_ID="dsv4pro-phase1-long-decode-20260730-234236"
+trap 'bash run_quick_map.sh stop' EXIT INT TERM
+bash run_quick_map.sh start
+bash run_quick_map.sh fixed
+ +

11.6 停止、清理与检查

+
cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map
+bash run_quick_map.sh stop
+
+curl -fsS http://10.101.0.11:30002/health || true
+docker ps --filter name=dsv4pro_pro6000d_2node_sglang_tp16_quick_map
+nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv

下一阶段: - - Phase 2:硬件与资源竞争归因 + + 打开 Phase 2 实验档案

返回推理优化主计划

diff --git a/docs/dsv4pro_pro6000d_2node_sglang/phase2_code.html b/docs/dsv4pro_pro6000d_2node_sglang/phase2_code.html index c4f5259..f2c62b8 100644 --- a/docs/dsv4pro_pro6000d_2node_sglang/phase2_code.html +++ b/docs/dsv4pro_pro6000d_2node_sglang/phase2_code.html @@ -113,6 +113,10 @@
+

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

文档边界:本文只解释提交 39fc2ba565a3 的 Phase 2 代码和文件调用关系。Phase 1 负责模型服务与请求;Phase 2 负责通信基线、 diff --git a/docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html b/docs/dsv4pro_pro6000d_2node_sglang/phase2_exp.html similarity index 99% rename from docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html rename to docs/dsv4pro_pro6000d_2node_sglang/phase2_exp.html index 01d2fa1..8fc7ab1 100644 --- a/docs/dsv4pro_pro6000d_2node_sglang/phase2_dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution.html +++ b/docs/dsv4pro_pro6000d_2node_sglang/phase2_exp.html @@ -135,7 +135,7 @@
节点:174.1.51.5 + 174.1.51.7 拓扑:SGLang TP16 / EP2 - 更新:2026-07-31 15:25:00 CST + 更新:2026-07-31 16:46:05 CST
@@ -762,7 +762,7 @@ tmux new-session -d -s dsv4pro-phase2 \
  • 完整归因见 analysis.md,原始结构化摘要和两端 NCCL 证据已一并归档。
  • -

    返回 Phase 1 实施记录

    +

    返回 Phase 1 实验档案

    返回推理优化主计划

    diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/report.md b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/report.md new file mode 100644 index 0000000..54a78ad --- /dev/null +++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/report.md @@ -0,0 +1,12 @@ +# DeepSeek-V4-Pro Pro6000D Two-Node SGLang Quick Map + +Profiler: disabled. Speculative decoding: disabled. + +## Aggregate results + +| Case | Suite / role | Stage | ISL | OSL | C | Reps | Total TPS | CV | Output TPS | TTFT P95 | TPOT P95 | E2E P95 | Status | +|---|---|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---| +| long_context_decode_128k_to_1k_c1 | fixed / - | long_context_decode | 131072 | 1024 | 1 | 1/1 | 1604.09 | -% | 12.43 | 49325.72 ms | 32.24 ms | 82312.21 ms | COMPLETED | +| long_output_decode_1k_to_4k_c16 | fixed / - | long_output_decode | 1024 | 4096 | 16 | 1/1 | 387.52 | -% | 310.02 | 6241.01 ms | 50.33 ms | 211363.56 ms | COMPLETED | + +The fixed map is descriptive and never stops on SLO. With one repetition, CV is intentionally unavailable. diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/run_manifest.json b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/run_manifest.json new file mode 100644 index 0000000..0d2f88b --- /dev/null +++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/run_manifest.json @@ -0,0 +1,42 @@ +{ + "schema_version": 1, + "workflow_stage": "quick_performance_map", + "run_id": "dsv4pro-phase1-long-decode-20260730-234236", + "status": "COMPLETED", + "started_at": "2026-07-30T23:48:13+08:00", + "updated_at": "2026-07-30T23:54:25+08:00", + "suites": [ + "fixed" + ], + "engine": "sglang", + "model_name": "DeepSeek-V4-Pro", + "model_path": "/data/hf_models/DeepSeek-V4-Pro", + "docker_image": "lmsysorg/sglang:nightly-dev-cu13-20260720-b3570a45", + "head_node": "10.101.0.11", + "worker_node": "10.101.0.13", + "head_ip": "10.101.0.11", + "sglang_port": 30002, + "dist_init_port": 20002, + "tp_size": 16, + "ep_size": 2, + "nnodes": 2, + "mem_fraction_static": 0.9, + "cuda_graph_max_bs_decode": 64, + "max_running_requests": 256, + "nccl_socket_ifname": "eth0", + "nccl_ib_hca": "=mlx5_0:1,mlx5_3:1", + "nccl_cross_nic": "1", + "enable_rdma": true, + "require_nccl_ib": true, + "rdma_device_paths": "/dev/infiniband/rdma_cm,/dev/infiniband/uverbs0,/dev/infiniband/uverbs3", + "git_commit": "06b017483cb1cfc6aace3c60e94576fb667ec9bc", + "git_dirty": false, + "scenario_file": "/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/quick_map_scenarios.tsv", + "case_ids": "long_output_decode_1k_to_4k_c16,long_context_decode_128k_to_1k_c1", + "notes": [ + "The fixed quick map does not stop on SLO.", + "Profiler is disabled; these results are eligible for performance comparison.", + "Speculative decoding is not enabled." + ], + "ended_at": "2026-07-30T23:54:25+08:00" +} diff --git a/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/summary.csv b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/summary.csv new file mode 100644 index 0000000..f7609e7 --- /dev/null +++ b/docs/dsv4pro_pro6000d_2node_sglang/results/dsv4pro-phase1-long-decode-20260730-234236/summary.csv @@ -0,0 +1,3 @@ +run_id,suite,case_id,role,stage,repetition,isl,osl,concurrency,num_prompts,warmup_requests,status,error_type,exit_code,started_at,ended_at,elapsed_s,completed,failed,duration_s,actual_concurrency,peak_concurrent_requests,total_input_tokens,total_output_tokens,request_throughput,input_token_throughput,output_token_throughput,total_token_throughput,peak_output_token_throughput,e2e_mean_ms,e2e_p50_ms,e2e_p95_ms,e2e_p99_ms,ttft_mean_ms,ttft_p50_ms,ttft_p95_ms,ttft_p99_ms,tpot_mean_ms,tpot_p50_ms,tpot_p95_ms,tpot_p99_ms,itl_mean_ms,itl_p50_ms,itl_p95_ms,itl_p99_ms,bench_file,bench_log +dsv4pro-phase1-long-decode-20260730-234236,fixed,long_context_decode_128k_to_1k_c1,,long_context_decode,1,131072,1024,1,1,0,COMPLETED,,0,2026-07-30T23:52:24+0800,2026-07-30T23:54:19+0800,115.0,1,0,82.34937581099803,0.9995487118435447,,131072,1024,0.012143382875118852,1591.6574802075781,12.434824064121704,1604.0923042716997,,82312.21251300303,82312.21251300303,82312.21251300303,82312.21251300303,49325.72139299009,49325.72139299009,49325.72139299009,49325.72139299009,32.244859354851364,32.244859354851364,32.244859354851364,32.244859354851364,32.2448224535841,32.23047900246456,32.468517863890156,32.707680857274674,/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-long-decode-20260730-234236/cases/long_context_decode_128k_to_1k_c1/rep1/bench.jsonl,/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-long-decode-20260730-234236/cases/long_context_decode_128k_to_1k_c1/rep1/bench.log +dsv4pro-phase1-long-decode-20260730-234236,fixed,long_output_decode_1k_to_4k_c16,,long_output_decode,1,1024,4096,16,16,1,COMPLETED,,0,2026-07-30T23:48:13+0800,2026-07-30T23:52:19+0800,246.0,16,0,211.3935806370573,15.996984262440824,,16384,65536,0.07568820184502423,77.50471868930481,310.01887475721924,387.52359344652405,,211353.73641450133,211353.21495501557,211363.55966723931,211364.98273107863,5862.642711690569,5970.386928500375,6241.009955512709,6241.542907894473,50.18097526320165,50.15488793663095,50.32745551037411,50.57979576238554,50.18097181628469,50.06324249552563,50.968476399430074,52.59070861677173,/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-long-decode-20260730-234236/cases/long_output_decode_1k_to_4k_c16/rep1/bench.jsonl,/data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_tp16_quick_map/results/dsv4pro-phase1-long-decode-20260730-234236/cases/long_output_decode_1k_to_4k_c16/rep1/bench.log diff --git a/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html b/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html index fa6df38..591781c 100644 --- a/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html +++ b/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.html @@ -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-31 15:25:00 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 16:46:05 CST

    当前执行状态与阶段档案

    @@ -434,14 +434,17 @@ - - + + - + @@ -604,7 +607,7 @@ Nsight Compute 或专项 Microbenchmark

    5. Phase 1:建立阶段化性能地图

    本阶段当前实现与结果维护在 -Phase 1:双机 SGLang TP16 快速性能地图实施记录。 +Phase 1:双机 SGLang TP16 快速性能地图实验档案。 代码采用单一 Shell 入口 run_quick_map.sh,不修改或调用旧的全天全量脚本。

    最终 Run dsv4pro-phase1-full-20260730-220916 已完成: @@ -735,12 +738,14 @@ TPOT P95 增加 66.55%。Phase 2 将围绕这两个现象采集硬件时间序

    6. Phase 2:同步采集轻量硬件指标

    本阶段的设计、代码改动与结果同步维护在 - -Phase 2:硬件与资源竞争归因档案。本阶段重放长 Prefill、并发 Prefill、 + +Phase 2:硬件与资源竞争归因实验档案。本阶段重放长 Prefill、并发 Prefill、 普通 Decode、长输出 Decode、长上下文 Decode,以及 1K → 1K, C=32 的混合 A/B。首轮 Run dsv4pro-phase2-20260731-130125 在 26 分 26 秒内完成 8/8 个结果; -最终采集代码固定到提交 30664faa41f8,完成最终复跑和汇报后才进入 Phase 3。 +最终采集代码在提交 39fc2ba565a3 修复 Worker 分发,并由 +Run dsv4pro-phase2-stage-smoke-20260731-162326 完成双节点通信功能验证; +完成最终正式复跑和汇报后才进入 Phase 3。

    6.1 首轮归因结果

      diff --git a/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.md b/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.md new file mode 100644 index 0000000..9016a3d --- /dev/null +++ b/docs/dsv4pro_pro6000d_2node_sglang/推理优化计划.md @@ -0,0 +1,737 @@ +# 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-31 12:26:00 CST + +## 阶段档案与实验命令规范 + +每个 Phase HTML 的正文只保留最终成功实验、有效结果和结论;失败尝试压缩到 +末尾的经验教训。阶段完成时删除“暂不能下结论”等过渡内容。 + +每个 Phase HTML 必须包含“实验复现命令”,并明确区分: + +| 标签 | 含义 | 必须记录的内容 | +|---|---|---| +| 实际执行命令 | 该次有效 Run 真正运行过 | 执行节点、工作目录、tmux/入口、完整 Docker 服务命令、Benchmark/Profile/监控命令、停止清理命令、Run ID 与命令证据路径 | +| 复现命令 | 根据实际 Run 整理,可重新执行 | 与实际参数等价;允许为可读性换行,但不得省略影响结果的参数 | +| 计划或示例命令 | 尚未在当前阶段运行 | 必须显式标注“未执行”,真机完成后替换为实际命令,不能作为结果证据 | + +长命令必须同时原样保存到结果目录的 `*_cmd.txt` 或 Manifest。HTML 负责教学、 +解释和索引,落盘命令文件负责精确审计。 + +## 0. 双机通信前置知识与当前修正 + +完整术语、设备映射、日志判读和 2026-07-30 网络事故复盘见: + +- [6000D 双机通信与 NCCL 术语入门](./6000D双机通信与NCCL术语入门.html) + +本项目部署时只使用两条节点间计算网: + +| 物理端口 | Linux netdev/IP 入口 | RDMA Verbs/HCA 入口 | 交换路径 | +|---|---|---|---| +| 400G Rail 1 | `eth0` | `mlx5_0` | switch 1 | +| 400G Rail 2 | `eth3` | `mlx5_3` | switch 2 | + +`eth0` 与 `mlx5_0` 不是同一个软件设备。它们是同一条 400G 物理 Ethernet +端口的两种入口:前者服务 IP/TCP Socket,后者服务 RoCE/RDMA Verbs。 +400G 指物理链路的标称线速,不专属于 TCP 或 RDMA;400 Gbit/s 约等于 +50 GB/s 单向理论上限,不能直接当作 NCCL 或模型端到端可达到的吞吐。 + +当前唯一启动入口只允许 `eth0/eth3` 与 `mlx5_0/mlx5_3`,在两端预检并 +透传 `rdma_cm/uverbs0/uverbs3`,并要求 NCCL INFO 证明两条 HCA 的 +`NET/IB + GDRDMA` 已启用,否则不开始 benchmark。修正后的 Phase 1 +正式矩阵 12/12、长 Decode 补测 2/2 均成功。 + +## 1. 目标与原则 + +### 1.1 最终目标 + +在不做 PD 分离的前提下,定位 DeepSeek-V4-Pro 在双机 6000D 上的端到端瓶颈,并提高: + +- 满足 TTFT、TPOT 等 SLO 时的最大吞吐。 +- 长上下文 Prefill 性能。 +- Decode 输出吞吐和单请求 TPOT。 +- 混合流量下的稳定性与 P95/P99 时延。 +- 16 张 GPU、PCIe 和双 Rail 计算网的有效利用率。 + +### 1.2 核心原则 + +1. 先找关键路径,再调参数。 +2. 先用端到端指标确认问题,再用 Timeline 找到阶段,最后才用 Kernel Profiler。 +3. Prefill、Decode 和混合干扰必须分别测试。 +4. 一次只改变一个变量,每项优化都要保留可复现的 A/B 结果。 +5. 单算子更快不代表服务吞吐更高,最终结论必须回到真实请求和 SLO。 +6. Profiling Run 只用于定位,不能与无 Profiler 的正式性能结果直接比较。 + +## 2. 当前最值得验证的瓶颈假设 + +| 编号 | 假设 | 为什么值得优先检查 | +|---|---|---| +| H1 | TP16 每层跨机通信暴露过多 | 两台机器没有跨机 NVLink,TP Collective 需要经过 RoCE | +| H2 | NSA Indexer 或 Sparse Attention Kernel 效率不足 | DSV4-Pro 的稀疏注意力路径复杂,Indexer 可能抵消稀疏收益 | +| H3 | MoE Grouped GEMM 或路由负载不均 | Decode 小 Batch 容易 Memory-bound,热门专家可能制造慢 Rank | +| H4 | 长 Prefill 干扰在线 Decode | 统一实例中 Prefill 与 Decode 竞争计算、显存带宽和调度预算 | +| H5 | CPU Scheduler、Metadata 或 Kernel Launch 产生 GPU 空洞 | 小 Batch Decode 对 CPU 和 Launch 开销特别敏感 | +| H6 | KV Cache 容量、碎片或 Preemption 限制并发 | 大模型权重占用高,剩余 HBM 决定上下文与并发容量 | +| H7 | 当前并行拓扑并非最优 | 使用 16 张卡不等于只能采用单一 TP16 拓扑 | + +## 3. Profiling 总体流程 + +```text +端到端性能地图 + ↓ +服务内部指标与硬件计数器 + ↓ +Nsight Systems 时间线 + ↓ +确定 1-3 个主要瓶颈 + ↓ +Nsight Compute 或专项 Microbenchmark + ↓ +提出优化并做单变量 A/B + ↓ +回到完整 Benchmark 和 SLO 验证 +``` + +不要直接对完整服务运行长时间 Nsight Compute。它的开销很高,也会生成巨大的报告。应先用 Nsight Systems 找到占关键路径的 Kernel,再构造小型复现。 + +## 4. Phase 0:冻结可复现环境 + +正式测试前,每个 Run 必须保存以下信息: + +- 两台机器的 GPU、Driver、CUDA、NCCL 版本。 +- vLLM 或 SGLang 的镜像名、镜像 ID、Git Commit 和 Python 包版本。 +- 模型目录、权重文件校验信息和模型配置。 +- 完整 Docker Run 与服务启动命令。 +- 完整 Benchmark 命令。 +- TP、DP、PP、EP 拓扑。 +- Attention、NSA、Indexer、MoE、GEMM 和通信 Backend。 +- `NCCL_SOCKET_IFNAME`、`NCCL_IB_HCA`、`NCCL_CROSS_NIC` 等通信变量。 +- GPU Memory Fraction、Context Limit、Active Request Limit、KV Cache Dtype。 +- CUDA Graph、Chunked Prefill、Prefix Cache 和投机解码状态。 +- 运行前后的 `nvidia-smi`、容器列表和网络状态。 + +建议每次运行生成: + +```text +results// + run_manifest.txt + server_cmd.txt + bench_cmd.txt + summary.csv + requests.jsonl + server/ + hardware/ + profiles/ + notes.md +``` + +### 基线约束 + +- 初始基线不启用 MTP、EAGLE、DSpark 等投机解码。 +- 初始基线使用唯一随机 Prompt,避免 Prefix Cache 影响。 +- 服务启动完成后做固定 Warm-up。 +- 每个测试点至少重复 3 次。 +- 正式结果使用无 Profiler 运行。 +- Profiling 只捕获预热后的少量 Engine Step。 + +## 5. Phase 1:建立阶段化性能地图 + +详细结果见 [Phase 1 实验档案](./phase1_exp.html),实现说明见 +[Phase 1 代码详解](./phase1_code.html)。 + +### 5.1 第一轮最小矩阵 + +| 场景 | ISL | OSL | 并发 | 主要目标 | +|---|---:|---:|---:|---| +| P1 短 Prefill 延迟底线 | 1K | 1 | 1 | 固定开销与最小 TTFT | +| P2 中长 Prefill | 32K | 1 | 1 | NSA、Indexer、Attention | +| P3 长 Prefill | 128K | 1 | 1 | 长上下文计算和显存压力 | +| P4 Prefill 吞吐 | 32K | 1 | 逐步加并发 | Chunked Prefill 与输入 TPS | +| D1 Decode 延迟底线 | 1K | 1K | 1 | 单请求 TPOT | +| D2 Decode 吞吐 | 1K | 1K | 16/32/64 | MoE、Batch 与通信 | +| M1 混合负载 | Decode C=32 时注入 128K Prefill | | | Prefill 对在线 Decode 的干扰 | + +长度应以当前已验证的服务容量为上限。如果 128K 不可用,先降到 64K,但必须在 Manifest 中记录原因。 + +### 5.2 并发搜索 + +沿用 Add-16 加退化回退策略: + +```text +C = 1(延迟基线) +C = 16, 32, 48, 64, ... +``` + +停止条件需要区分: + +- `OOM` +- `ENGINE_CRASH` +- `TTFT_SLO_EXCEEDED` +- `TPOT_SLO_EXCEEDED` +- `TPS_SATURATED` +- `TPS_REGRESSION` +- `MAX_CONCURRENCY_REACHED` + +不能把“最大成功并发”“最高 TPS 并发”和“满足 SLO 的最大并发”混为同一个值。 + +### 5.3 每个 Case 必须记录 + +#### 请求层 + +- 实际成功、失败和超时请求数。 +- 实际输入、输出和总 token 数。 +- Request Throughput。 +- Input、Output 和 Total TPS。 +- P50/P95/P99 TTFT。 +- P50/P95/P99 TPOT。 +- P50/P95/P99 ITL。 +- P50/P95/P99 E2E。 +- Queue Time 与 Service Time,若框架支持。 + +#### Scheduler 层 + +- Running、Waiting Request 数。 +- 每轮 Batch Sequence 数。 +- 每轮 Prefill、Decode Token 数。 +- Chunked Prefill 次数和 Chunk 大小。 +- Forward Step 时间。 +- Scheduler/Metadata 准备时间。 +- Preemption、Recompute、Retract 次数。 +- Prefix Cache Hit Tokens。 + +#### 显存层 + +- 权重占用。 +- KV Cache 总量、已用量和峰值。 +- CUDA Graph 占用。 +- Workspace 与临时 Tensor 峰值。 +- Reserved/Allocated 差异与碎片。 + +## 6. Phase 2:同步采集硬件指标 + +详细实现与运行命令见 +[Phase 2 实验档案](./phase2_exp.html),实现说明见 +[Phase 2 代码详解](./phase2_code.html)。 +首轮 8/8 benchmark 已完成;最终采集代码、Worker 分发修复和双节点通信 +smoke test 已通过,等待最终正式复跑。 + +Phase 2 只提供一个用户入口: + +```bash +cd /data/hzy/sskj/experiments/pro6000/dsv4pro_pro6000d_2node_sglang_hardware_contention_attribution +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" +``` + +`all` 会内部完成 TP16 服务启停、两节点采集、五个固定 Case、混合 A/B、 +结果汇总和异常清理。不要手工并行执行 Phase 1 的 `start/stop`。 + +### 6.1 GPU + +测试期间持续记录: + +```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 +``` + +重点观察: + +- SM Utilization。 +- HBM Utilization。 +- 显存占用。 +- GPU Clock、Memory Clock。 +- Power 与温度降频。 +- PCIe RX/TX。 + +如果有 DCGM,增加: + +- Tensor Core Active。 +- DRAM Active。 +- SM Active。 +- PCIe Throughput。 +- GPU Stall 与 XID。 + +### 6.2 CPU + +记录服务主进程与 Worker 线程: + +```bash +pidstat -t -p 1 +mpstat -P ALL 1 +numastat -p +``` + +需要发现: + +- 单个 Scheduler Thread 是否满核。 +- Tokenizer、HTTP Frontend 或 Python 线程是否阻塞。 +- Worker 是否跨 NUMA 访问。 +- CPU 空洞是否对应 GPU 空洞。 + +### 6.3 网络 + +Phase 1 正式 Run 已确认容器内可见 RDMA 设备,NCCL 同时识别 +`mlx5_0/mlx5_3`,跨节点 Channel 使用 `NET/IB + GDRDMA`。Phase 2 +保留相同 fail-closed 门禁,并同步采集两条 Rail 的流量和错误计数。 + +当前拓扑中需要分别观察两条 Compute Rail,确认: + +- 两条 Rail 是否同时有流量。 +- 带宽是否均衡。 +- 是否有丢包、重传、PFC Pause 或错误计数。 +- 慢 Rank 是否固定绑定某个 NIC 或 NUMA 节点。 + +基础监控可以使用: + +```bash +sar -n DEV 1 +ethtool -S eth0 +ethtool -S eth3 +``` + +通信调试 Run 可以临时开启: + +```bash +NCCL_DEBUG=INFO +NCCL_DEBUG_SUBSYS=INIT,NET,GRAPH,TUNING +``` + +该日志开销较高,不应在正式性能结果中长期启用。 + +## 7. Phase 3:Nsight Systems 时间线 + +### 7.1 捕获策略 + +- 只捕获预热后的 5 到 10 个 Engine Step。 +- Prefill、Decode 和混合干扰分别生成报告。 +- 两台机器分别保存原始报告。 +- 优先保留所有 Rank;文件过大时至少保留代表 Rank 和跨机通信相关 Rank。 +- 报告必须和对应 Benchmark Case ID 绑定。 + +### 7.2 vLLM + +当前版本支持时,使用 CUDA Profiler 动态 Capture: + +```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 +``` + +压测端使用支持 Profile Trigger 的 Bench: + +```bash +vllm bench serve ... --profile +``` + +### 7.3 SGLang + +服务启动前设置: + +```bash +export SGLANG_TORCH_PROFILER_DIR=/data/profile/sglang +``` + +Profiling 专用 Run 可增加: + +```text +--enable-layerwise-nvtx-marker +``` + +捕获预热后的 10 个 Step: + +```bash +curl -X POST http://127.0.0.1:30000/start_profile \ + -H 'Content-Type: application/json' \ + -d '{ + "output_dir": "/data/profile/sglang", + "start_step": 5, + "num_steps": 10, + "activities": ["CPU", "GPU"] + }' +``` + +多机 Trace 自动合并要求两台机器能访问同一个共享输出目录。没有共享目录时分别保存,再在本地汇总。 + +### 7.4 时间线必须回答的问题 + +1. Prefill 和 Decode 各自的 Top Kernel 是什么? +2. NCCL 在关键路径上的暴露时间是多少? +3. 通信与计算重叠了多少? +4. 每层之间是否存在 CPU 或同步空洞? +5. CUDA Graph 是否覆盖常见 Decode Batch? +6. 16 个 Rank 是否同时结束? +7. 是否存在固定慢 Rank? +8. MoE Expert Token 是否严重不均衡? +9. NSA Indexer 的成本占 Sparse Attention 总成本多少? +10. 长 Prefill 到来时,Decode Kernel 为什么被延迟? + +### 7.5 报告分析 + +```bash +nsys stats .nsys-rep +``` + +重点查看: + +- CUDA GPU Kernel Summary。 +- NCCL Summary。 +- NCCL GPU Time Utilization。 +- Communication/Compute Overlap。 +- NCCL Straggler。 +- CUDA API Summary。 +- OS Runtime 和 CPU Thread Timeline。 + +## 8. 证据到优化方向的映射 + +| 观察到的证据 | 更可能的根因 | 下一项 A/B | +|---|---|---| +| Decode 中 NCCL 占比高,且通信未被计算覆盖 | TP16 通信受限 | TP8+PP2、NCCL 拓扑与算法 | +| C=1 很慢,并发增加后 TPS 明显改善 | MoE/权重读取 Memory-bound | Batch、MoE Backend、MTP | +| GPU 利用率呈锯齿,Kernel 间有明显空洞 | CPU Scheduler 或 Launch 开销 | CUDA Graph、异步调度 | +| 一个或少数 Rank 长期最慢 | Expert、NIC 或 NUMA 不均衡 | EPLB、Affinity、Rank Mapping | +| NSA Indexer 时间接近或超过 Attention | 稀疏索引收益不足 | Indexer Backend、Top-K、融合 | +| 长 ISL 的 Attention 时间异常增长 | Prefill Kernel 或 Chunking 问题 | Prefill Backend、Chunk Size | +| KV Cache 长期接近满并发生重算 | HBM 容量不足 | FP8 KV、并发和 Context 上限 | +| 注入长 Prefill 后 Decode TPOT 暴涨 | Prefill/Decode 相互干扰 | Chunked Prefill 与 Scheduler | +| GPU 利用率低但 CPU 单核满载 | Host 端瓶颈 | Frontend、Tokenizer、Scheduler | +| 两条 Rail 流量明显不均 | NIC Mapping 或 NCCL 拓扑 | HCA、CROSS_NIC、NUMA Affinity | + +## 9. Phase 4:优先级最高的拓扑实验 + +### 9.1 A:TP16 基线 + +当前方案用于建立所有后续实验的对照。 + +风险是每层 TP Collective 都可能跨越两台机器,Decode 小消息通信尤其容易被延迟支配。 + +### 9.2 B:TP8 + PP2 + +逻辑上: + +```text +Node 5: Pipeline Stage 0, TP8 +Node 7: Pipeline Stage 1, TP8 +``` + +理想情况下,每卡权重占用与 TP16 接近: + +```text +TP16: + 每卡权重约为 W / 16 + +TP8 + PP2: + 每个 Stage 保存 W / 2 + Stage 内由 8 卡切分 + 每卡权重约为 (W / 2) / 8 = W / 16 +``` + +潜在收益: + +- 每层 TP Collective 留在单机。 +- 跨机主要传输 Pipeline Stage 边界激活。 +- 避免每层都进行跨机 AllReduce。 + +潜在代价: + +- Pipeline Bubble。 +- 低并发延迟可能变差。 +- KV Cache、Hybrid Cache 和 DSV4-Pro 模型实现可能暂不支持 PP。 +- 两个 Stage 的计算量可能不均衡。 + +测试顺序: + +1. 先做加载与单请求 Smoke Test。 +2. 对比 C=1 Decode 延迟。 +3. 对比 C=16/32/64 吞吐。 +4. 观察跨机网络流量是否显著下降。 +5. 观察两个 Pipeline Stage 是否负载均衡。 + +### 9.3 C:Attention TP8/DP2 + MoE EP16 + +目标是: + +- Attention 在节点内使用 TP8。 +- 两个 Attention DP Group 并行处理请求。 +- MoE Expert 在 16 张卡上分布。 + +这接近“Attention DP + MoE EP”的思路。Expert 权重通常占模型大头,因此即使 Attention 权重复制两份,也有机会放入显存。 + +必须先验证: + +- 当前 vLLM/SGLang 版本是否支持 DSV4-Pro 的该拓扑。 +- Expert 权重、非 Expert 权重和 KV Cache 的实际显存占用。 +- All-to-All 是否比当前 TP16 AllReduce 更划算。 +- Expert 负载是否均衡。 + +## 10. Phase 5:通信专项 + +### 10.1 不只测 1 GiB 大消息 + +之前的 1 GiB `all_reduce_perf` 主要说明大消息带宽。Decode 中的 Collective 往往更小,可能由延迟主导。 + +需要覆盖真实消息尺度: + +```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 +``` + +若启用 EP,还要测试 All-to-All。 + +### 10.2 通信优化顺序 + +1. 确认两条 Rail 都在工作。 +2. 确认 Rank、GPU、NIC 和 NUMA Affinity。 +3. 对照实际模型消息大小。 +4. 查看 NCCL 自动选择的 Algorithm、Protocol 和 Channel。 +5. 只有自动选择明显不合理时,才 A/B `Ring/Tree`、`Simple/LL128` 等设置。 +6. 观察模型端到端结果,而不只看 nccl-tests 峰值。 + +## 11. Phase 6:Kernel 专项 + +从 Nsight Systems 中选累计占关键路径最高的 1 到 3 个 Kernel,再使用 Nsight Compute。 + +DSV4-Pro 的优先怀疑对象: + +- NSA Indexer/Top-K。 +- Sparse MLA/Attention Prefill。 +- Sparse MLA/Attention Decode。 +- MoE Gate、Dispatch、Grouped GEMM、Combine。 +- FP8 Quant/Dequant 与 Scale Packing。 +- RMSNorm、Rope、KV Cache Store 等碎片化小算子。 +- NCCL Collective Kernel。 + +需要分析: + +- SM 和 Tensor Core 利用率。 +- DRAM 吞吐与 L2 Hit Rate。 +- Occupancy。 +- Register 与 Shared Memory 压力。 +- Warp Stall 原因。 +- Kernel Shape 与 Batch/Token 数。 +- 小 Kernel Launch 次数。 + +优化优先顺序: + +1. 切换已有高性能 Backend。 +2. 调整 Backend 的 Shape/Workspace/Tile 配置。 +3. 消除无用 Copy、Cast 和临时 Tensor。 +4. 融合相邻的 Memory-bound 小算子。 +5. 现有 Backend 不覆盖关键 Shape 时,再开发新 Kernel 或提交 PR。 + +## 12. Phase 7:Scheduler 与统一实例干扰 + +### 12.1 混合干扰实验 + +先建立稳定 Decode 背景流量: + +```text +ISL=1K +OSL=1K +C=32 +``` + +运行稳定后,周期性注入一个长 Prefill: + +```text +ISL=128K +OSL=1 +C=1 +``` + +比较注入前后: + +- Decode P50/P95/P99 TPOT。 +- Decode Output TPS。 +- 长请求 TTFT。 +- 每轮 Prefill Chunk。 +- Scheduler Queue。 +- GPU Timeline。 + +### 12.2 可调方向 + +- Chunked Prefill Size。 +- Max Prefill Tokens。 +- Max Batched Tokens。 +- Max Running Requests/Max Num Seqs。 +- Prefill 与 Decode 调度优先级。 +- CUDA Graph Batch Coverage。 +- 双 Batch Overlap 或框架已有的通算重叠能力。 + +调优目标不是单独最大化 Prefill TPS,而是减少长 Prefill 对 Decode SLO 的破坏。 + +## 13. Phase 8:显存与缓存 + +当前初始值应保持固定,只在发现明确证据后调整: + +- GPU Memory Fraction。 +- Max Context Length。 +- Active Request Limit。 +- KV Cache Dtype。 +- Page/Block Size。 +- CUDA Graph Capture Size。 + +若 KV Cache 是瓶颈,优先顺序: + +1. 确认权重和 Workspace 的真实占用。 +2. 检查 Allocated/Reserved 差值与碎片。 +3. 使用 FP8 KV Cache,前提是当前 Kernel 支持且精度可接受。 +4. 根据业务上限设置 Context Length,不为不会出现的极端长度预留容量。 +5. 设置合理的 Active Request Limit,避免运行时 OOM。 +6. 再考虑 CPU/L3 KV Offload。 + +Prefix Cache 单独做第二阶段测试: + +| 命中率 | 用途 | +|---:|---| +| 0% | 纯计算基线 | +| 20% | 低复用业务 | +| 50% | 中等公共前缀 | +| 80% | Agent/Coding 高复用 | + +Mooncake 或三级缓存只有在 Prefix 可复用时才有明显价值。随机独立 Prompt 不适合评价它。 + +## 14. Phase 9:MTP 与模型级优化 + +当 TP16 Baseline、并行拓扑、通信、Backend 和 Scheduler 已稳定后,再测试: + +- 原生 MTP。 +- DSpark。 +- EAGLE。 +- KV Cache 量化。 +- 更低比特权重量化。 +- Sparse Attention 算法或 Indexer 优化。 + +投机解码至少记录: + +- Accept Rate。 +- Mean Accept Length。 +- Target Forward TPS。 +- Draft/MTP 开销。 +- CPU 调度气泡。 +- 不同并发下的净收益。 + +不能只看 Accept Length,也不能只看 C=1。 + +## 15. 里程碑与交付物 + +### M1:可信 Baseline + +完成条件: + +- 七组最小矩阵均有 3 次重复。 +- 同一 Case 的关键 TPS 变异系数尽量不超过 3%。 +- 所有环境、命令和日志可追溯。 + +交付: + +- Baseline Summary。 +- SLO Frontier。 +- GPU/CPU/Network Timeline。 + +### M2:瓶颈报告 + +完成条件: + +- Prefill、Decode、混合三类 Profile 完成。 +- 找出累计贡献最高的 1 到 3 个瓶颈。 +- 每个判断都有 Trace、计数器或日志证据。 + +交付: + +- `.nsys-rep` 或 Torch Trace。 +- Kernel/NCCL Summary。 +- Bottleneck Evidence Table。 + +### M3:并行拓扑 A/B + +完成条件: + +- TP16 保留基线。 +- TP8+PP2 完成可行性与性能验证。 +- Attention DP + MoE EP 完成支持性和显存评估。 + +交付: + +- 每种拓扑的显存、通信、TTFT、TPOT 和 TPS 对比。 +- 推荐拓扑与不推荐拓扑的证据。 + +### M4:首轮优化闭环 + +完成条件: + +- 至少一项优化通过完整 Benchmark。 +- 结果在无 Profiler 环境下可复现。 +- 正确性无回归。 +- 满足 SLO 的吞吐有明确改善。 + +期望目标: + +- 首轮争取获得至少 10% 的 SLO 内吞吐提升,或显著降低 P95/P99 长尾。 +- 若无法提升,也必须形成排除结论,说明瓶颈为什么不在该方向。 + +## 16. 实验纪律 + +每次实验都必须回答: + +1. 改了什么? +2. 为什么认为它会影响当前瓶颈? +3. 除该变量外,还有什么发生了变化? +4. 端到端指标如何变化? +5. Profile 证据如何变化? +6. 是否引入精度、稳定性或显存风险? +7. 是否值得保留? + +禁止以下做法: + +- 同时修改多个参数后只报告最终 TPS。 +- 用 Profiling Run 和普通 Run 直接比较性能。 +- 只看平均值,不看 P95/P99。 +- 用配置 ISL/OSL 估算 TPS,而不核对实际 token 数。 +- 用 1 GiB NCCL 带宽代表 Decode 小消息性能。 +- 因单个 Kernel 更快就宣称端到端优化成功。 +- OOM 后不重启服务继续测试。 + +## 17. 首轮执行建议 + +建议直接按以下顺序推进: + +1. 固化当前 TP16 服务命令和 Manifest。 +2. 跑 P1、P2、P3、D1、D2、M1。 +3. 同步采集 GPU、CPU 和双 Rail 数据。 +4. 对 P3、D2、M1 各捕获 5 到 10 个 Engine Step。 +5. 输出 NCCL、NSA/Attention、MoE、CPU Gap 四项时间占比。 +6. 根据最大暴露时间选择第一个优化方向。 +7. 优先做 TP16 与 TP8+PP2 的可行性和性能对比。 +8. 回到完整 Benchmark 验证 SLO 内吞吐。 + +最重要的判定标准是: + +> 优化暴露在关键路径上的时间,而不是只优化看起来最慢的单个算子。 + +## 18. 参考资料 + +- [vLLM Profiling](https://docs.vllm.ai/en/stable/contributing/profiling/) +- [SGLang Benchmark and Profiling](https://github.com/sgl-project/sglang/blob/main/docs/developer_guide/benchmark_and_profiling.md) +- [SGLang Server Arguments](https://github.com/sgl-project/sglang/blob/main/docs/advanced_features/server_arguments.md) +- [NVIDIA Nsight Systems User Guide](https://docs.nvidia.com/nsight-systems/UserGuide/index.html) +- [NVIDIA Nsight Systems Analysis Guide](https://docs.nvidia.com/nsight-systems/AnalysisGuide/index.html) +- [腾讯混元 Hy3 Preview AI Infra 精读笔记](../hy3_infra_article/Hy3_Preview_AI_Infra_精读笔记.md) diff --git a/docs/hy3_infra_article/Hy3_Preview_AI_Infra_精读笔记.md b/docs/hy3_infra_article/Hy3_Preview_AI_Infra_精读笔记.md new file mode 100644 index 0000000..e73b1da --- /dev/null +++ b/docs/hy3_infra_article/Hy3_Preview_AI_Infra_精读笔记.md @@ -0,0 +1,659 @@ +# Hy3 Preview AI Infra 推理优化精读笔记 + +> 原文:[腾讯混元 AI Infra 如何优化 Hy3 Preview:一次大模型推理性能提升的技术拆解](https://zhuanlan.zhihu.com/p/2053138680768943935) +> 作者:混元 AI Infra 推理团队 +> 发布时间:2026-06-26 +> 整理时间:2026-07-29 +> 用途:推理优化学习、实验设计与工程路线参考 + +这是一份基于原文及配图整理的技术学习笔记,不是逐字转载。重点是解释每项优化在解决什么瓶颈、为什么有效、依赖什么条件,以及如何映射到我们当前的 vLLM、SGLang、DeepSeek-V4-Flash 和 Kimi-K3 实验。 + +## 1. 一页结论 + +这篇文章最值得学习的并不是某一个算子,而是它展示了一套完整的推理优化方法: + +1. 先用真实业务数据和明确 SLO 定义目标,而不是只看固定长度随机请求。 +2. 将 Prefill 和 Decode 分开分析,因为二者的瓶颈、并行策略和优化目标不同。 +3. 从算子、融合、并行、缓存、调度、量化和稀疏算法六个层级逐层消除瓶颈。 +4. 不是寻找一个对所有场景都最好的配置,而是围绕业务分布寻找吞吐、时延、容量之间的 Pareto 前沿。 +5. 单算子加速不等于端到端等比例加速,必须回到真实流量和 SLO 重新测量。 + +文章的最终测试口径很有参考价值: + +- 5000 条真实请求。 +- 最大输入约 192K,平均输入约 68K。 +- 最大输出约 64K,平均输出约 0.9K。 +- 理论 Prefix Cache 命中率约 80%。 +- 硬件为 96 GB Hopper 架构 GPU,结果图标注为 H20。 +- SLO 为 TTFT 不超过 4 秒、TPOP 不超过 50 毫秒。 +- 总体测试精度标注为 W8A8C8。 + +图中报告的最终单卡吞吐约为: + +- 输入:287.8 万 token/min/GPU,约 47,967 token/s/GPU。 +- 输出:8.6 万 token/min/GPU,约 1,433 token/s/GPU。 + +![最终单卡输入与输出 TPM](assets/01_overall_results.jpg) + +这里需要特别注意:输入吞吐远高于输出吞吐并不奇怪。文章的真实流量平均输入约 68K、平均输出约 0.9K,输入 token 数本来就比输出多很多;同时 Prefix Cache 命中也会改变 Prefill 的实际计算量。不能只用这两个柱子的比例推断 Prefill 和 Decode 的硬件速度。 + +## 2. 模型与问题背景 + +Hy3 Preview 是一个 GQA + MoE 模型。官方仓库给出的主要规格包括: + +- 总参数量约 295B,单 token 激活参数约 21B。 +- 另有约 3.8B 的 MTP 层参数。 +- 80 层主模型。 +- 192 个专家,每个 token 激活 8 个专家。 +- 64 个 Attention Head、8 个 KV Head,Head Dim 为 128。 +- 原生上下文上限 256K。 + +官方模型仓库:[Tencent-Hunyuan/Hy3-preview](https://github.com/Tencent-Hunyuan/Hy3-preview) + +它在 Hopper 96 GB GPU 上主要面对四类矛盾: + +| 矛盾 | 表现 | +|---|---| +| 长上下文与 TTFT | Prefill 计算量大,混合长度请求造成长尾 | +| MoE 与通信 | Expert Dispatch/Combine、TP AllReduce 和跨节点流量较重 | +| 权重与 KV Cache | 权重挤压 HBM,限制长上下文和并发容量 | +| MTP 与异步调度 | 每轮实际接受 token 数不固定,CPU 无法按传统方式提前准备 | + +文章的优化可以整理成六层: + +| 层级 | 代表技术 | 主要目标 | +|---|---|---| +| 算子 | 动态 Attention、Router GEMM、FusedMoE | 提高单个热点算子的效率 | +| 融合 | Rope/Norm/Quant/KV、AllReduce/Norm/Add、Sampler、GEMM/RS | 减少 Kernel Launch、HBM 往返和通信等待 | +| 并行 | Prefill TPSP、Decode Attention-DP + MoE-EP | 为不同阶段选择合适的数据切分 | +| 缓存 | GPU、CPU、KVStore 三级缓存 | 扩大 Prefix Cache 容量并支持跨实例复用 | +| 调度 | MTP 异步流水 | 隐藏 CPU 调度开销 | +| 模型压缩 | W4A8、Attention FP8、Stem 稀疏注意力 | 降低权重、访存和长上下文计算成本 | + +## 3. 算子优化 + +### 3.1 Attention:动态切分和负载均衡 + +#### 问题 + +线上 Batch 中常同时存在长、短请求。静态 Split-KV 必须预先固定切分粒度: + +- 切得太少,长序列不能充分占满 SM。 +- 切得太多,短序列会承担额外调度、归约和 Kernel 开销。 +- 长短请求混合时,不同 CTA 的工作量不均,最慢 CTA 决定整次 Kernel 的结束时间。 + +#### 方案 + +文章采用统一 Tile 粒度加贪心装桶: + +1. 将所有请求拆成统一大小的 Attention Tile。 +2. 把不同请求产生的 Tile 汇总成一条任务流。 +3. 根据全局 Tile 数量,为每个 CTA 分配相同或接近的任务预算。 +4. 每轮推理前生成任务映射表,Attention Kernel 按表领取任务。 +5. 最后由 Combine Kernel 合并 Split-KV 的局部结果。 + +配图中的例子把长度为 1024、5120、2048 的三个请求按 512 token 拆成 2、10、4 个 Tile,再给 4 个 CTA 各分配 4 个 Tile。长请求可以跨 CTA 执行,不再让某个 CTA 单独拖住整批请求。 + +![动态 Attention 调度](assets/02_attention_dynamic_schedule.jpg) + +#### 收益 + +- 单 Batch 长文本场景,单算子最高约 2.95 倍加速。 +- 混合长度 Batch 场景约 1.59 到 1.76 倍加速。 + +#### 对我们的启发 + +我们当前固定 ISL/OSL Grid 适合测容量边界,但不能验证这种负载均衡优化。要增加一个混合长度测试: + +- 同一 Batch 同时放入 1K、4K、16K、64K、128K 请求。 +- 保持总 token 数近似相同,对比固定长度 Batch。 +- 观察 P95/P99 TTFT、GPU SM Occupancy、Attention Kernel 尾部空转时间。 + +### 3.2 Router GEMM:用两路 BF16 重构 FP32 + +#### 问题 + +MoE Router 和稀疏 Attention 的打分对精度敏感,可能需要 FP32 权重。直接执行 BF16 激活乘 FP32 权重会遇到: + +- Tensor Core 路径利用不足。 +- 激活转成 FP32/TF32 会增加类型转换。 +- 小 M Shape 下,CUDA Core 路径尤其低效。 + +#### 方案 + +离线把 FP32 权重拆成高位 BF16 与低位 BF16 残差: + +```text +W ≈ W_high + scale * W_low +scale = 1 / 256 +``` + +推理时执行两路 BF16 GEMM: + +```text +Y = X * W_high^T + scale * (X * W_low^T) +``` + +两路计算被放进同一个 Kernel: + +- X 只从 HBM 读取一次。 +- 两路结果分别在寄存器中累加。 +- Epilogue 中完成修正。 +- 最终只写回一次结果。 + +![双 BF16 重构 FP32 Router GEMM](assets/03_router_gemm.jpg) + +#### 收益 + +在 N=192、K=4096、M=2 到 4096 的测试范围内,相比 FP32 cuBLAS 路径约快 2.86 到 3.22 倍。 + +#### 对我们的启发 + +这不是简单的 `dtype` 开关,而是数值表示、Kernel 实现与模型精度共同设计。它提醒我们: + +- Router 往往是小矩阵,不能用大 GEMM 的经验判断性能。 +- 看 GPU 利用率时,要单独检查 Router、Indexer 和 Expert GEMM 的 Shape。 +- 对 DeepSeek/Kimi 的稀疏路由,需要区分“精度敏感的小算子”和“吞吐主导的大算子”。 + +### 3.3 FusedMoE:重排完整专家执行链 + +文章不是只替换 Grouped GEMM,而是重构了整个 MoE 数据通路: + +1. 在共享内存中分块统计路由结果,并为每个专家预留连续输出区间。 +2. Gate-Up GEMM 直接按路由索引读取原始输入,省略显式 Gather。 +3. 取消部分 Warp Specialization,以提高 SM 驻留密度。 +4. 激活量化结果按专家连续写入,供 Down GEMM 顺序读取。 +5. 末端直接完成 Top-K 加权聚合,减少中间 HBM 往返。 +6. 用 PDL 串联阶段,降低频繁 Kernel Launch 形成的空隙。 + +报告的单算子收益: + +- TP=8、EP=1:相比 vLLM CUTLASS、vLLM Triton 和 SGLang 路径约快 1.5 到 1.6 倍。 +- TP=1、EP=8:约快 1.2 到 1.5 倍。 + +开源实现:[Tencent/hpc-ops](https://github.com/Tencent/hpc-ops) + +这里有一个很重要的实验原则:同一个 MoE Kernel 在 TP8/EP1 与 TP1/EP8 下的收益不同,因为每卡 Expert 数、每个 Expert 收到的 token 数、通信方式和矩阵 Shape 都变了。比较 MoE Backend 时必须固定完整的 TP/DP/EP 拓扑。 + +## 4. 算子融合 + +### 4.1 Rope + Norm + Hadamard + Quant + Store KV + +QKV Projection 之后通常存在一串算术强度很低的 Element-wise 操作。若每一步都是独立 Kernel,就会反复: + +- 从 HBM 读数据。 +- 写回中间结果。 +- 发起新的 Kernel。 + +文章把 Rope、RMSNorm、Hadamard、量化和 KV Cache 写入融合为一个 Kernel。中间值尽量停留在寄存器中,最后直接以低比特格式写入 KV Cache。 + +报告的融合算子加速约 5 倍。它体现的是典型原则: + +> 对访存受限的小算子,减少一次 HBM 往返往往比减少几次算术操作更重要。 + +### 4.2 AllReduce + Norm + Add + +TP 路径通常按以下顺序执行: + +```text +AllReduce -> Residual Add -> RMSNorm +``` + +拆开执行会产生通信等待和中间 Tensor 读写。文章把它融合为: + +```text +RMSNorm(AllReduce(x) + residual, weight) +``` + +提供两类实现: + +- Prefill 高吞吐路径:利用 NVSwitch 多播,面向较大的 token Batch。 +- Decode 低延迟路径:使用 Lamport P2P,并用 PDL 让两个 Kernel 重叠。 + +覆盖约 8K 到 32K token 的场景,相比 NCCL 和 FlashInfer 同类路径最高约快 1.68 倍。 + +这说明通信优化不能只看 NCCL Bandwidth。对于小消息和 Decode,Kernel Launch、同步点与后处理往往和网络带宽同样重要。 + +### 4.3 Sampler 融合 + +常规采样可能包含重复惩罚、温度缩放、Top-K、Top-P、Softmax 和随机采样等十余个 Kernel。文章将其压缩成两个核心 CUDA Kernel,并根据简单温度采样或完整采样选择专用路径。 + +关键设计: + +- 全局词表尽量只读取一次。 +- 重复惩罚掩码留在 GPU 内处理。 +- 单请求可拆给多个 CTA。 +- Max Top-K 不超过 64 时使用局部堆归并。 +- Top-K 与 Softmax 的 max/sum 归约融合。 + +下图直观展示了融合前后的 profiler 时间线:融合前有大量碎片化 Kernel,融合后主体工作集中到少数长 Kernel。 + +![Sampler 融合前](assets/04_sampler_before.jpg) + +![Sampler 融合后](assets/05_sampler_after.jpg) + +文章报告相较 vLLM 与 FlashInfer 的采样路径分别约有 5.5 倍和 2.5 倍单算子提升。端到端收益仍取决于输出长度、Batch 和模型主体计算占比。 + +### 4.4 GEMM + ReduceScatter 细粒度重叠 + +传统执行顺序是完整 GEMM 结束后再开始 ReduceScatter。文章将 SM 分成两类角色: + +- 计算 SM:执行 GEMM。 +- 通信 SM:搬运已经完成的输出 Tile。 + +计算 SM 每生成一个 Tile,就写入本地 Buffer 并通知通信 SM;通信不必等待整个矩阵完成。 + +此外,GEMM 内部又划分为三级 Warp 流水: + +```text +Load Warp -> MMA Warp -> Epilogue Warp +``` + +![GEMM 三级 Warp 流水](assets/06_gemm_comm_fusion.jpg) + +在 M 为 8K、16K、32K、64K 的四组 Shape 上,通信覆盖率约从 76.5% 增长到 84.8%,端到端相较串行路径约快 1.68 到 1.81 倍。 + +这个方向对多机 TP/EP 特别重要。我们以后跑 NCCL Test 只能知道通信上限,真正的模型吞吐还取决于能否把通信藏在计算后面。 + +## 5. Prefill 与 Decode 的并行策略 + +### 5.1 Prefill:TPSP + +文章认为 Hy3 Preview 的纯 TP8 Prefill 有三个问题: + +1. Norm、Router 等 token-wise 算子在各 TP Rank 重复计算。 +2. 频繁 AllReduce 交换完整激活。 +3. MoE Grouped GEMM 沿 Hidden 维切得过窄,Shape 不利于 Tensor Core。 + +因此,它没有让整层始终使用同一种并行方式,而是在不同模块切换布局。配图给出的一层时间线包含: + +- Attention 使用 TP8。 +- Routed Expert 使用 TP4 + SP2。 +- Shared Expert 沿 token/sequence 维使用 SP8。 +- AG + QKV 和 RS + O Projection 做通信计算融合。 +- Shared Expert 与通信使用多 Stream 重叠。 +- AllGather 通信采用 FP8,图中说明可比 BF16 减少约 50% 通信带宽。 + +![TPSP 单层执行时间线](assets/07_prefill_tpsp.jpg) + +端到端 Prefill TTFT: + +| 输入长度 | 优化前 | 优化后 | 降幅 | +|---|---:|---:|---:| +| 16K | 764 ms | 536 ms | 29.9% | +| 32K | 1885 ms | 1424 ms | 24.5% | + +#### 对我们的启发 + +“TP 越小通信越少,所以一定更快”是不完整的。TP 改变的不只是通信量,还会改变: + +- 每卡权重与 KV Cache 容量。 +- GEMM 的 M/N/K Shape。 +- 是否存在重复 token-wise 计算。 +- Batch 在 DP Rank 之间的分散程度。 +- 是否能使用特定融合算子。 + +因此,TP2/DP4、TP4/DP2、TP8/DP1 必须端到端实测,不能只用通信直觉排序。 + +### 5.2 Decode:Attention DP + MoE EP + +Decode 阶段通常 Batch 较小,单 token GEMM 更偏 Memory-bound。文章采用 Attention DP 与 MoE EP 的混合并行: + +- Attention 权重在 DP Rank 上复制,让请求可以分开执行。 +- Expert 权重按 EP Rank 分布,减少每卡权重占用。 +- 多节点请求汇聚到 Expert 后形成更大的 Grouped GEMM Batch。 +- 使用异步 EPLB,根据真实专家负载重排权重。 +- Shared Expert 计算与 Dispatch/Combine 尽量重叠。 +- 长序列 Attention 使用 DPTP 混合方式缓解 DP Rank 负载不均。 + +报告的端到端吞吐提升约为 15.7% 到 44.7%。 + +这和我们之前 Custom DP 的现象能够对应: + +- 短上下文、高并发时,独立实例容易各自形成稳定 Batch,Custom DP 可能反超。 +- 低并发时,请求被分散后每个实例 Batch 太小,GPU 利用率下降。 +- 长上下文时,Prefill 和 KV Cache 压力成为主导,简单 Round Robin 无法替代全局调度与混合并行。 + +## 6. GPU、CPU、KVStore 三级缓存 + +文章把 Prefix Cache 扩展成三级: + +| 层级 | 介质 | 特点 | 复用范围 | +|---|---|---|---| +| L1 | GPU HBM | 延迟最低、容量最小 | GPU 进程 | +| L2 | CPU DRAM | 容量更大、回载较快 | 实例内部 | +| L3 | 本地盘或共享 KVStore | 容量最大、延迟最高 | 本机或跨实例 | + +完整请求流程: + +1. Scheduler 先查 L1 GPU Prefix Cache。 +2. 对未命中部分查询 L2/L3。 +3. 命中的完整 KV Block 按需加载回 GPU。 +4. 跳过已经命中的 Prefix Prefill。 +5. 新生成的完整 KV Block 异步下沉到 L2/L3。 +6. L3 连续读取失败时降级到 CPU-only,避免外部存储故障拖垮服务。 + +配图中的 L3 Backend 可以是: + +- HoverDB 本地磁盘:本机持久化缓存。 +- NitroFS 共享存储:支持跨实例复用。 + +![三级 KV Cache 架构](assets/08_multilevel_cache.jpg) + +#### 与 Mooncake 的关系 + +这正是 Mooncake/HiCache 一类系统的价值所在。即使不开 PD 分离,多级缓存仍能在以下场景产生价值: + +- 多轮 Agent 对话存在长公共前缀。 +- Coding 请求反复携带同一仓库上下文。 +- 实例扩缩容、迁移或重启后仍希望复用 Prefix。 +- GPU HBM 不足,希望把冷 KV 下沉到 CPU、SSD 或远端存储。 + +但如果测试流量全部是独立随机 token,几乎没有共享前缀,L2/L3 缓存只会增加查找和搬运开销。因此必须显式设计 0%、20%、50%、80% 命中率的测试组。 + +## 7. MTP 与异步调度 + +### 7.1 传统异步调度为什么失效 + +普通 Decode 每轮稳定生成一个 token,CPU 可以在 GPU 执行第 N 轮时提前准备第 N+1 轮。 + +MTP 会一次草拟多个 token,但实际接受长度是动态的。下一轮的: + +- Sequence Length。 +- Position ID。 +- KV Cache Block 映射。 +- 输入 token 布局。 + +都依赖本轮验证结果。若 CPU 必须等待 GPU 把接受长度拷回,就会重新出现同步气泡。 + +### 7.2 文章的方案 + +CPU 暂时不等待真实接受长度,而是: + +1. 按最大可能接受长度插入 Placeholder。 +2. 提前准备并 Launch 下一轮。 +3. 真实接受长度继续保留在 GPU。 +4. 下一轮正式计算前,再由 GPU 修正 Position、KV 映射等关键状态。 + +这样 CPU 可以提前一整轮,而不是只和很短的 MTP Layer Forward 重叠。 + +![MTP 与异步调度流水](assets/09_mtp_async_schedule.jpg) + +报告结果: + +- 每轮减少约 5 到 10 ms 的 CPU 气泡。 +- 端到端性能提升约 10% 到 20%。 + +#### 对我们的启发 + +投机解码测试不能只记录 Accept Length。至少要同时记录: + +- Target Model Decode TPS。 +- Draft/MTP 接受长度和接受率。 +- 每轮 CPU 调度时间。 +- GPU 间隙和 Kernel Launch 间隔。 +- 不同 Batch 下的收益。 + +小 Batch 时 CPU 气泡占比高,MTP 调度优化可能很重要;大 Batch 时 Target Forward 本身更重,收益比例可能下降。 + +## 8. W4A8、Attention FP8 与精度恢复 + +文章的压缩链路是: + +1. SmoothQuant 风格的激活平滑,抑制少数通道的离群值。 +2. Attention 的 Query/Key 在量化前做 Hadamard 正交旋转,把离群值打散。 +3. 使用 GPTQ 做逐层权重重建,根据二阶信息补偿低比特权重误差。 +4. 做轻量级 QAT,仅更新量化相关参数,使模型适应任务分布。 + +![Hy3 W4A8 量化流程](assets/10_quantization.jpg) + +报告称: + +- 多领域评测与 BF16 基线的差距控制在约 1% 以内。 +- 端到端吞吐提升超过 28%。 + +需要区分两种口径: + +- 文章开头的总体线上结果标注为 W8A8C8。 +- 量化章节进一步讨论的是 W4A8 + Attention FP8 路线。 + +二者不能当成同一套权重和同一组最终吞吐数据。 + +开源工具:[Tencent/AngelSlim](https://github.com/tencent/AngelSlim) + +#### 对我们的路线判断 + +这部分不适合当前最先做,因为它可能涉及 Calibration、GPTQ 重建和 QAT。优先级应该低于: + +- 正确部署和基线测量。 +- TP/DP/EP 与 Scheduler 调优。 +- Prefix Cache 和多级缓存。 +- Backend 与已有 Kernel 的选择。 + +当系统参数已稳定,并且确实被权重容量或 HBM 带宽限制时,再进入量化训练与精度评估。 + +## 9. Stem 稀疏注意力 + +Stem 的目标是在长上下文 Prefill 中,只计算最有价值的一部分 Attention Block。 + +### 9.1 Token Position Decay + +普通 Uniform Top-K 对不同 Query 位置使用相同预算。Stem 认为: + +- 序列头部 token 会参与更多后续因果聚合,误差可能逐层传播。 +- 序列尾部 token 的影响范围较小,可以更激进地稀疏。 + +因此 Top-K 预算从头部的 `k_start` 逐渐衰减到尾部: + +```text +k_end = mu * k_start +``` + +在总计算预算近似不变时,把更多预算留给影响更大的早期位置。 + +### 9.2 Output-Aware Metric + +仅按 `QK^T` 选 token,只衡量注意力路由概率,没有衡量 Value 实际携带的信息强度。Stem 加入 Value 向量模长: + +```text +M(i, j) = QK^T + beta * max(0, log(||V_j||_2)) +``` + +然后基于该分数做 Top-K,并交给 Block Sparse Flash Attention 计算。 + +![Stem 稀疏注意力](assets/11_stem_sparse_attention.jpg) + +### 9.3 性能与精度 + +文章给出的长上下文 Prefill 加速: + +| 长度 | FA3 BF16 | FA3 FP8 | Stem | +|---|---:|---:|---:| +| 16K | 1.27x | 1.45x | 1.50x | +| 32K | 1.36x | 1.73x | 1.96x | +| 64K | 1.42x | 2.02x | 2.68x | +| 128K | 1.47x | 2.29x | 3.62x | + +![稀疏 Attention Prefill 加速](assets/12_sparse_speedup.jpg) + +效果随长度增长而放大,符合稠密 Attention 计算复杂度快速增长的直觉。 + +配图还比较了 BF16 与“FP8-W8A8 + Stem”的多个任务分数。后者在不同任务上有小幅升降,例如 LongBench v2 和 SWE-bench Verified 约下降 2 个绝对分,Terminal-Bench 基本持平,ClawEval 略有提升。不能只看平均值,需要为实际业务单独设精度门槛。 + +![量化与 Stem 的任务精度对比](assets/13_sparse_accuracy.jpg) + +#### 对我们的意义 + +你以前做过稀疏注意力基模工作,这一块很适合作为中后期深入方向,但需要把“算法”和“系统”同时验证: + +- 稀疏索引本身的计算是否抵消节省。 +- Indexer 在 Prefill/Decode 的 Shape 是否覆盖。 +- Block Pattern 能否被现有 Kernel 高效执行。 +- 稀疏 KV 的布局是否引入额外 Gather。 +- 128K 以上是否仍保持精度。 +- Chunked Prefill 是否改变选块逻辑或数值结果。 + +## 10. 如何正确理解文章中的加速数字 + +### 10.1 不要把所有加速比相乘 + +例如 Attention 2.95x、融合算子 5x、FusedMoE 1.6x 并不意味着端到端能快几十倍。Amdahl 定律决定了: + +```text +总体收益 = 1 / (未优化部分 + 优化部分 / 加速比) +``` + +而且不同优化可能覆盖同一段时间,收益会重叠。 + +### 10.2 固定长度 Grid 与真实数据各有用途 + +| 方法 | 适合回答的问题 | 不适合回答的问题 | +|---|---|---| +| 固定 ISL/OSL/C Grid | 容量边界、Shape 性能、OOM 点、参数敏感度 | 真实 P95/P99、缓存收益、混合长度长尾 | +| 真实 Trace | 线上吞吐、SLO 达标率、Prefix Cache、调度效果 | 精确定位某个 Shape 的 Kernel 问题 | + +正确做法不是二选一,而是: + +1. 用 Grid 画出系统性能和容量地图。 +2. 用真实 Trace 验证业务加权结果。 +3. 对真实 Trace 暴露出的热点 Shape 再回到 Microbenchmark 和 Profiler。 + +### 10.3 文章没有完全披露的变量 + +做横向对比时还需要确认: + +- 总 GPU 数与节点数。 +- vLLM/SGLang 的具体版本和 Baseline 参数。 +- Cache 命中是按请求、token 还是 block 计算。 +- 输入 TPM 是否统计逻辑输入 token,还是实际执行 Prefill 的 token。 +- MTP 接受率和平均接受长度。 +- 量化精度数据与总体 W8A8C8 吞吐是否来自同一配置。 +- 各单算子收益对应的 Batch、并行拓扑和频率锁定条件。 + +因此,这篇文章非常适合作为优化地图,但不能直接把数字当成我们的性能目标。 + +## 11. 映射到我们当前的工程路线 + +### 阶段 A:建立可信 Baseline + +- 固定代码、镜像、模型权重和驱动版本。 +- 保留 TP2/DP4、TP4/DP2、TP8/DP1 的 Shape Grid。 +- 同时记录 TTFT、TPOT、ITL、E2E、请求吞吐、输入/输出/总 TPS。 +- 记录实际成功请求的 Prompt/Output token,避免只用配置长度估算 TPS。 +- 增加 GPU、HBM、PCIe/NVLink/RDMA、CPU 利用率和服务日志。 + +### 阶段 B:调度、缓存与并行 + +- 比较原生 DP 与 Custom DP。 +- 对短上下文高并发和长上下文分别选择路由策略。 +- 测试 Prefix Cache 命中率 0%、20%、50%、80%。 +- 测试 GPU-only、GPU+CPU、GPU+CPU+Mooncake/KVStore。 +- 对 MoE 分别测试 TP 主导、EP 主导和 Attention DP + MoE EP。 + +### 阶段 C:Profiler 驱动的 Kernel 优化 + +- 用 Nsight Systems 找 GPU 空洞、CPU 调度气泡和通信等待。 +- 用 Nsight Compute 找热点 Kernel 的访存、Occupancy 和 Tensor Core 利用率。 +- 先尝试已有 Backend:FlashInfer、FlashMLA、DeepGEMM、CUTLASS、Marlin、HPC-Ops。 +- 只有现有 Backend 不覆盖关键 Shape 时,才值得自己写算子或提交 PR。 + +### 阶段 D:模型相关优化 + +- MTP/DSpark/EAGLE。 +- W4A8、Attention FP8、KV Cache 量化。 +- Stem/DSA 等稀疏 Attention。 +- 精度回归、Calibration 和必要的轻量训练。 + +## 12. 建议补充的实验矩阵 + +### 12.1 真实流量 Baseline + +先构建一个与文章接近但适合当前模型的 Trace: + +- 输入长度按 1K、4K、16K、64K、128K、192K 分桶。 +- 输出长度以 1K 左右为中心,同时保留短输出和长输出尾部。 +- 混合长度请求一起进入服务。 +- 每次测试至少数百到数千请求,保证 P95/P99 有意义。 + +### 12.2 Prefix Cache + +| 变量 | 建议取值 | +|---|---| +| 前缀命中率 | 0%、20%、50%、80% | +| 前缀长度 | 4K、16K、64K、128K | +| Cache 层级 | GPU、GPU+CPU、GPU+CPU+L3 | +| 实例范围 | 单实例、跨实例 | + +### 12.3 并行策略 + +| 阶段 | 候选策略 | 重点指标 | +|---|---|---| +| Prefill | TP8、TP/SP 混合、Chunked Prefill | TTFT、输入 TPS、通信时间 | +| Decode | TP、DP、Attention DP + MoE EP | TPOT、输出 TPS、负载均衡 | +| 多机 | TP/EP、DP/EP、PD 分离 | 网络流量、跨机长尾、容错 | + +### 12.4 SLO 吞吐边界 + +不要只找 Total TPS 最大点。每个 Shape 应同时输出: + +- 最大成功并发。 +- Total TPS 峰值并发。 +- 满足 TTFT SLO 的最大并发。 +- 满足 TPOT SLO 的最大并发。 +- 同时满足全部 SLO 的最大并发。 + +这些并发可能不是同一个点。 + +## 13. 阅读文章时需要记住的十个问题 + +1. 当前瓶颈属于 Prefill 还是 Decode? +2. 是 Compute-bound、Memory-bound、Communication-bound,还是 CPU-bound? +3. 优化改变了计算量,还是只改变了数据搬运和重叠? +4. 收益对应什么 Batch、Shape、TP/DP/EP? +5. 单算子收益在端到端占比是多少? +6. 是否依赖 NVLink/NVSwitch、RDMA、特定 GPU 架构? +7. 是否需要新权重、Calibration、QAT 或模型结构支持? +8. 是否改变数值结果或精度? +9. 对低并发、长上下文和混合长度是否仍成立? +10. 最终是否提高了满足 SLO 的吞吐,而不只是无约束峰值 TPS? + +## 14. 术语速查 + +| 术语 | 含义 | +|---|---| +| CTA | CUDA Thread Block,Kernel 调度到 SM 的基本工作单元 | +| Tile | 对矩阵或序列任务做的固定粒度切块 | +| Split-KV | 将长 Attention 的 KV 维拆给多个 CTA,再合并局部结果 | +| PDL | Programmatic Dependent Launch,用于减少依赖 Kernel 之间的启动气泡 | +| SP | Sequence Parallel,沿 token/sequence 维切分 | +| TPSP | Tensor Parallel 与 Sequence Parallel 的混合布局 | +| EPLB | Expert Parallel Load Balancing,专家并行负载均衡 | +| TPOP | Time Per Output Token,与 TPOT 接近,衡量连续吐字速度 | +| Prefix Cache | 复用相同前缀已经生成的 KV Cache | +| W8A8C8 | 权重、激活和缓存均使用 8-bit 的总体精度标记,具体格式需看实现 | +| W4A8 | 4-bit 权重、8-bit 激活 | +| MTP | Multi-Token Prediction,一轮提出或预测多个后续 token | +| OAM | Output-Aware Metric,用 Value 强度修正稀疏 Attention 选块分数 | + +## 15. 延伸资料 + +- [原始知乎文章](https://zhuanlan.zhihu.com/p/2053138680768943935) +- [Hy3 Preview 官方仓库](https://github.com/Tencent-Hunyuan/Hy3-preview) +- [HPC-Ops](https://github.com/Tencent/hpc-ops) +- [AngelSlim](https://github.com/tencent/AngelSlim) +- [腾讯混元 AI Infra 新开源:HPC-Ops 推理核心算子全面升级](https://developer.cloud.tencent.com/article/2688857) +- [Mooncake](https://github.com/kvcache-ai/Mooncake) + +## 16. Mentor 结论 + +这篇文章可以作为我们后续推理优化工作的总地图,但学习顺序不要反过来。 + +当前最值得优先复刻的是: + +1. 真实流量 + SLO 的 Benchmark 方法。 +2. Prefill/Decode 分阶段分析。 +3. TP/DP/EP 与混合长度负载的系统实验。 +4. Prefix Cache 和多级缓存。 +5. Profiler 驱动的 Backend 与融合优化。 + +量化、MTP 和稀疏 Attention 很有价值,但更依赖模型结构、精度评估和训练支持。等 Baseline、调度、并行与缓存做扎实之后,再进入这些方向,收益会更容易被正确测量,也更容易形成有说服力的技术成果。
    DeepSeek-V4-Pro / 双机 Pro6000D / SGLang TP16 快速性能地图已完成;双 Rail NET/IB + GDRDMA,固定点 9/9、混合 A/B 3/3,总用时 28 分 36 秒打开实施记录已完成;双 Rail NET/IB + GDRDMA,固定点 11/11、混合 A/B 3/3,阶段结果 14/14 +打开 Phase 1 实验档案
    +打开 Phase 1 代码详解 +
    DeepSeek-V4-Pro / 双机 Pro6000D / SGLang 硬件与资源竞争归因最终采集代码已完成;首轮 8/8 成功,精确窗口、双节点 DCGM、PCIe/NCCL 基线和逐指标报告等待最终复跑最终采集代码已完成;首轮 8/8 成功,Worker 分发修复与双节点通信 smoke test 已通过,等待最终正式复跑 -打开 Phase 2 档案
    +打开 Phase 2 实验档案
    打开 Phase 2 代码详解