feat: add Kimi-K3 PP8 DFlash PD integration and warmup regression

This commit is contained in:
Zhiyi Hong 2026-08-31 17:10:00 +08:00
parent c06ef5fd61
commit 91ab3fe32d
15 changed files with 4104 additions and 0 deletions

View File

@ -1,5 +1,7 @@
# sskj — 多平台大模型推理性能基准测试项目
**更新2026-08-31 17:05:00 CST**:新增 Kimi-K3 PP8 + DFlash PD 适配验证入口。基于 SGLang PR #33863 固定源码,接通 PP 分段 hidden 投影、P 侧 prompt draft KV 生成、D 侧输入生命周期与 TP4→TP32 的 draft GQA KV 传输,保留 Kimi SM120 FlashInfer MXFP4 接入。修复 P 普通预热误带 DFlash verify metadata 的启动问题23 项 CPU 回归通过;修复镜像已同步 601608服务级验证正在进行尚无 GSM8K 结果。配置为 P TP4/PP8/EP4、D TP32/PP1/EP4、BF16 KV、8K Chunk计划固定 64 题 C1/C8。详见 `experiments/pro6000/kimi3_pro6000_pd_dflash_validation/README.md`
**更新2026-08-27 13:53:26 CST**:完成 Kimi-K3 八节点标准 PD 第一阶段。P 组 601-604 使用 PP8×TP4×EP4、FlashInfer MXFP4、Chunk 8KD 组 605-608 使用 PP1×TP32×EP32、Marlin通过 Mooncake 0.3.12.post1 和 4 Rail RDMA 传输;统一 P/D `page_size=64`16K→1 与 16K→512 的 C1/C8 共 91/91 请求成功。代表结果16K→1 C8 Input TPS 6364.31、TTFT P50/P95 20.555/21.345 秒16K→512 C8 TPOT P50/P95 63.20/66.55 ms。详见 `experiments/pro6000/kimi3_pro6000_pd_pp8_standard/README.md`
**更新2026-08-20 10:13:01 CST**:完成 Kimi-K3 Prefill TP Reduce Scatter 可行性审计并停止该方向。K3 的 MLA 输出门控仍依赖完整 7168 维 hidden且 69/93 层为 KDA保留或恢复 gate hidden 后,原 hidden All-Reduce 无法消除并新增 2112 维 latent All-Gather估算通信量反增约 14.7%。研究原型仅保留为否决证据,不进入四节点实验或上游 PR后续转向 MoE A2A 与 Pipeline Parallelism。详见 `experiments/pro6000/kimi3_pro6000_sglang_tp_reduce_scatter_prefill/README.md`

View File

@ -0,0 +1,119 @@
# Kimi-K3从 PP + DSpark 迁移到 PP + DFlash
更新2026-08-31PP、传输与 MoE 集成首版。
## 1. 决策与范围
**优先推进 DFlash 的 PP + PD 适配。** #33863 的分段投影设计能复用于 DFlash但需要补齐 DFlash worker、调度入口和异构 TP 下的 draft KV 传输。
当前已实现 DFlash PP worker、Kimi 跨 stage capture、PD 输入衔接、异构 TP 的 draft KV 传输,以及 Kimi FlashInfer 布局/SiTU 接入。首轮 P 启动暴露普通预热误带 verify metadata 的问题已修复并增加回归23 项 CPU 测试通过。SM120 编译及 Kimi SiTU GPU 集成回归已通过。修复镜像已同步全部八节点Run `pd-dflash-pwarm1-20260831-1652` 正在重新验证服务启动;尚无 PD 请求和 GSM8K 结果。详见 [实现进度与命令](evidence/kimi_k3_pd_dflash/README.md)。
暂停 EAGLE3 baseline。KV cache 保持 BF16chunk 保持 8192。FlashInfer 使用官方 0.6.18 加已合并 #4460 的显式 backport原版 0.6.18 wheel 尚未包含所需 CUTLASS SiTU 接口。
目标拓扑P 使用 601604 的 TP4/PP8/EP4 与已适配的 FlashInfer MXFP4D 使用 605608 的 TP32/PP1接入 DFlash。这里适配的是 **P 侧 PP 生成 draft 上下文**D 侧投机执行仍为 PP1。
审计固定版本:
| 对象 | 版本 |
|---|---|
| SGLang main | `3139ceaeec50868a441d68dc231663f3777e0d93` |
| PR #33863 head | `6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5` |
| PR 状态 | Open维护者要求拆分 DSv4 PP/PD、DSpark、Kimi/线性注意力工作 |
PR 公布的准确性数据来自 DSv4 Flash / H20不能代替本次 Kimi-K3 / 6000D / P-TP4 与 D-TP32 验证。[PR #33863](https://github.com/sgl-project/sglang/pull/33863)
## 2. 为什么可以迁移
DSparkDraftModel 继承 DFlashDraftModel。普通 Kimi draft 的 prompt 上下文处理都包含:采集多个 target 层的 hidden拼接后线性投影再归一化生成 draft KV。
#33863 将这一步改为:
```text
各 P/PP stage采集自己负责的 hidden → 使用对应权重列做局部投影
PP stage 间:传递并累加投影结果 [token 数, 7168]
最后一个 P/PP stage统一 RMSNorm → 各 draft 层 K/V 投影、K norm、RoPE → 写 draft KV
P → D传 target KV、KDA 状态及 draft KV
D使用已有 DFlash proposer / verify / commit 流程
```
依据是线性运算 `concat(h_i) × W^T = sum(h_i × W_i^T)`。归一化必须在求和后做。BF16 分段累加会改变舍入顺序因此需要比较中间张量、logits 和 token 接受行为。
关键接口已经加在共用 DFlash 模型中:[project_target_hidden_partial](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/models/dflash.py#L683)。最后阶段的归一化及 KV 写入实现位于 [write_projected_context_kv](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/models/dspark.py#L751)。
这一路线保留 P 侧 PP8 的收益,不要求把各层原始 hidden 通过 PD 网络传给 D。
## 3. 需要补哪些代码
以下路径均相对于 SGLang 的 `python/sglang/srt/`
| 模块 | 已有基础 | 本次增量 |
|---|---|---|
| `models/kimi_k3.py` | PR 已支持各 PP stage 局部采集 DSpark 特征 | 接通 DFlash capture setter按 DFlash checkpoint 的层号及 Kimi residual 语义采集 |
| `models/dflash.py` | PR 已有局部线性投影 | 复用投影;最后阶段归一化后复用 DFlash 的逐层 KV 写入路径 |
| `speculative/dflash_worker_v2.py` | 非 PP prefill 的 hidden → draft KV | 接收、转发 PP proxy仅最后阶段写完整 draft KV处理非末 stage 没有 logits/next token 的情况 |
| `managers/scheduler_pp_mixin.py` | PR 的成功交集、失败并集及一致释放机制 | 将目前 DSpark 专用的 proxy/input 衔接扩展到 DFlash保持请求顺序和完成条件一致 |
| `speculative/spec_info.py` | 当前 PD 输入分派只有 EAGLE、DSpark | 接入 DFlash 输入构造,并验证 overlap FutureMap 与 idle batch 生命周期 |
| `disaggregation/prefill.py``utils.py``mooncake/conn.py` | 最后 PP stage 传 draft KV、按层号配对 | 加入 draft GQA 的 head 分片/复制与收发端独立 stride保留 target MLA/KDA 的已有路径 |
| `arg_groups/speculative_hook.py``validation_hook.py` | 当前 main 拒绝 PP + DFlash | 仅放开已实现的 PD-prefill + PP 组合D 端 PP1 范围不变 |
关键证据:
- [Kimi 局部层采集](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/models/kimi_k3.py#L2912)。
- [DSpark PP 上下文处理](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/speculative/dspark_components/dspark_worker_v2.py#L655)。
- [PP scheduler 的 DSpark 专用入口](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/managers/scheduler_pp_mixin.py#L1391)。
- [main 的 PD 输入分派](https://github.com/sgl-project/sglang/blob/3139ceaeec50868a441d68dc231663f3777e0d93/python/sglang/srt/speculative/spec_info.py#L174)DFlash 仍返回 None。仓库里的 `dflash_disaggregation.py` 辅助函数尚未被这个入口调用,不能仅凭文件存在认定 PD 已支持。
相关 [#36140](https://github.com/sgl-project/sglang/issues/36140) 记录了输入缺失和 draft 状态缺失问题;[#36277](https://github.com/sgl-project/sglang/pull/36277) 是提前拒绝不支持配置的保护性改动,不是 DFlash PD 的实现。
## 4. 异构 TP 的明确风险
605 的 `/data/hf_models/Kimi-K3-DFlash/config.json` 为 6 层 draft、8 个 KV head、head_dim=128、BF16、4096 sliding windowtarget capture 层是 `[19,37,54,66,78,90]`
[DFlashAttention](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/models/dflash.py#L142) 使用 `max(1, total_kv_heads // tp_size)`
| draft 布局 | 每 rank KV heads | BF16、page=64 时单层 K 的页大小 |
|---|---:|---:|
| P TP4 | 2 | `64 × 2 × 128 × 2 = 32768 bytes` |
| D TP32 | 1按 head 复制到多个 rank | `64 × 1 × 128 × 2 = 16384 bytes` |
PR 当前 [Mooncake flat 传输分支](https://github.com/sgl-project/sglang/blob/6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5/python/sglang/srt/disaggregation/mooncake/conn.py#L686) 按 layer ID 配对后,对源偏移、目标偏移和复制字节数都使用源端 `item_len`。Kimi hybrid MLA 会进入这条路径。层号正确只能确认“哪层到哪层”,没有解决“该层哪些 head 到哪个 rank”。
### CPU 验证结果
从该 PR 源码直接用 AST 提取 `_send_kvcache_generic``build_transfer_entry_pairs`,使用 synthetic 地址、单页索引和记录型传输函数执行。未调用 GPU、Mooncake 或 RDMA。
[地址规划结果与源文件 SHA256](evidence/kimi_k3_pp_dflash_pr33863_transfer_plan.json)。
| 用例 | 地址/长度是否符合目标布局 |
|---|---|
| 收发双方均为 1 KV head | 符合 |
| P 为 2 head、D 为 1 head | 不符合:目标偏移和复制长度均按源端大条目计算 |
具体用例D buffer 起始地址设为 2000000目标 page ID=2。正确目标地址为 `2000000 + 2×16384 = 2032768`,当前函数生成 `2065536`,复制 32768 bytes 而不是单 head 页的 16384 bytes。
这是特定布局的地址规划复现,尚未启动完整服务复现。迁移时必须加入每条目的布局校验,并实现 GQA head-aware 传输;不能直接复用 flat copy。还需确认 D 接收到全部 target/draft 组件后才进入首轮 draft。
## 5. 实现与验收顺序
1. **局部数学与协议验证。** 检查各 stage capture 层覆盖、feature 顺序、空 capture stage、单次 RMSNorm比较拼接投影与分段投影误差。测试 TP4→TP32 的全部 8 个 draft KV head、K/V、6 层、页索引以及失败清理。源/目标布局不兼容时在传输前报错。
2. **最小 PD 请求。** 保留 P TP4/PP8、D TP32/PP1先 C1。核对真实 buffer metadata、draft KV 到达情况、首轮 draft logits以及成功/失败后的资源释放。
3. **GSM8K 固定 64 题。** 相同 prompt/template、采样设置依次测试 C1/C8保留准确率、完成率、接受长度、接受直方图、Output TPS、总耗时与显存状态。当前客户端非流式不把总耗时换算成 TTFT/ITL。输入不裁剪输出上限 512报告截断不新增 16K synthetic 测试。历史 5-shot 与前 64 题有重叠,本轮沿用以便部署回归,不能作为独立无泄漏的模型准确率评估。
4. **验收后决定继续投入。** DFlash 正确性与部署通过且有实际 Decode 收益,继续 PD 调优;若关键适配无法通过,或接受行为同样异常,切换到下面的 D-only 诊断。
真实实验代码继续维护在 601 的 `/data/hzy/sskj` 工作区,不改同事部署目录,不再创建分支。本轮核实当前检出名为 `hzy-kimi3-pd-pp8-standard`,保持现状;独立 SGLang 源码位于 `/data/hzy/src/sglang-kimi-pp-dflash-33863`
## 6. DSpark 接受长度诊断的备用路径
DSpark 低接受长度的问题先独立于 PD 排查。PP + PD 适配本身不会自动修复 D-only 已存在的问题。
| 检查项 | 目的 |
|---|---|
| checkpoint、tokenizer、mask token、target_layer_ids、RoPE | 排除 draft/target 配置失配及错误 hidden 来源 |
| 相同 token 前缀下,逐位置 draft token 与 target logits | 找到拒绝从第几个位置开始,区分首 token 错位与持续预测质量问题 |
| verify 的 KDA/SSM 状态更新、回滚与 token 位置 | 判断是否首次可用、随后状态漂移 |
| fused/replay 路径与参考执行比较 | 将 kernel/状态管理错误与 drafter 本身质量分开 |
| 接受统计定义、实际 proposal 数、bonus token | 统一接受长度口径,防止指标解释错误 |
605 的 DSpark checkpoint 为 block=7、5 层、capture `[7,23,51,67,83]`DFlash 为 block=16、6 层、另一组 capture 与 RoPE。二者的原始平均接受长度不能单独判断实现异常需同时看每次实际提议数、逐位置接受比例和实际吞吐。
本轮不重跑 no-spec 性能基线,保留此前结果作为参考。当前尚未确定 DSpark 接受长度异常的根因。

View File

@ -0,0 +1,32 @@
FROM lmsysorg/sglang@sha256:28e0d26073161e49ca56eba808d264a4223804a212020f1dfe1b2405b9f8a399
# Use the official core and compile SM120 CUTLASS through its supported JIT path.
# Remove old companion packages instead of suppressing their version checks.
COPY results/official_flashinfer_0618/flashinfer_python-0.6.18-py3-none-any.whl /opt/kimi-dflash-wheels/
RUN python3 -m pip uninstall -y flashinfer-jit-cache flashinfer-cubin && \
python3 -m pip install --no-index --no-deps --force-reinstall \
/opt/kimi-dflash-wheels/flashinfer_python-0.6.18-py3-none-any.whl
# #4460 is merged on main but absent from the v0.6.18 release branch.
# Apply the unchanged official commit to Python and wheel-bundled C++ sources.
COPY flashinfer_4460_b460bc0.patch /opt/kimi-dflash-wheels/
RUN cd "$(python3 -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')" && \
git apply --check --include='flashinfer/**' /opt/kimi-dflash-wheels/flashinfer_4460_b460bc0.patch && \
git apply --check --directory=flashinfer/data --include='flashinfer/data/csrc/**' /opt/kimi-dflash-wheels/flashinfer_4460_b460bc0.patch && \
git apply --include='flashinfer/**' /opt/kimi-dflash-wheels/flashinfer_4460_b460bc0.patch && \
git apply --directory=flashinfer/data --include='flashinfer/data/csrc/**' /opt/kimi-dflash-wheels/flashinfer_4460_b460bc0.patch
COPY results/sglang-kimi-pp-dflash-33863-integrated.tar.gz /opt/kimi-dflash-source.tar.gz
RUN mkdir -p /opt/kimi-dflash && \
tar -xzf /opt/kimi-dflash-source.tar.gz -C /opt/kimi-dflash
ENV PYTHONPATH=/opt/kimi-dflash/python
ENV PYTHONDONTWRITEBYTECODE=1
ENV FLASHINFER_DISABLE_VERSION_CHECK=""
ENV SGLANG_SOURCE_ROOT=/opt/kimi-dflash
# Build has no GPU: check the API, not SGLang's CUDA-device availability predicate.
RUN python3 -c "import inspect, flashinfer; from flashinfer.fused_moe import cutlass_fused_moe; from flashinfer.tllm_enums import ActivationType; from sglang.srt.speculative.dflash_worker_v2 import DFlashWorkerV2; from sglang.srt.disaggregation.mooncake.conn import MooncakeKVManager; assert hasattr(ActivationType, 'Situ'); assert {'situ_beta', 'situ_linear_beta'} <= set(inspect.signature(cutlass_fused_moe).parameters); print('RUNTIME_IMPORT_OK', flashinfer.__version__, 'upstream SiTU backport b460bc0')"
RUN python3 -m unittest discover -s /opt/kimi-dflash/test/registered/disaggregation -v
ENTRYPOINT ["python3", "-m", "sglang.launch_server"]

View File

@ -0,0 +1,105 @@
# Kimi-K3 PP + DFlash 适配进度
2026-08-31PP worker、PD 输入衔接、异构 TP 传输和 Kimi FlashInfer 接入已完成首版SM120 编译及 Kimi SiTU GPU 集成回归通过。首轮八节点部署在 P 侧预热阶段失败,已修复普通预热误带 DFlash verify metadata 的问题本地、601 构建镜像及 602 增量导入容器的 23 项 CPU 回归通过。正在重新验证服务启动,尚无 PD 请求或 GSM8K 结果。
## 源码和环境
- 基于官方 PR #33863`6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5`
- 上游 Python 目录的 4619 个文件均与 Git blob SHA1 校验一致。
- `pp_dflash_integration.patch` 包含完整 SGLang 增量;`pp_dflash_files.json` 记录文件 SHA256。`mixed_kv_transfer.patch` 保留传输层首版记录。
- 601 独立源码路径:`/data/hzy/src/sglang-kimi-pp-dflash-33863`
- 601 实验路径:`/data/hzy/sskj/experiments/pro6000/kimi3_pro6000_pd_dflash_validation`
- 不修改原 EAGLE3/DSpark 部署;不创建新分支。
## 本轮实现
| 部分 | 实现 |
|---|---|
| Kimi hidden 采集 | 接入 DFlash checkpoint 的 capture 层PP 边界由下一 stage 使用实际 residual 聚合权重采集 |
| 分段投影 | 各 stage 计算对应权重列的局部投影,通过 PP proxy 累加;末 stage 统一 RMSNorm 并写 6 层 draft KV |
| P 侧 draft 执行 | 非末 stage 只保留最小 KV poolP 不执行 draft decode CUDA GraphD 的原有初始化路径保留 |
| Scheduler 与 PD | 接通 DFlash proxy、next draft input、FutureMap 发布与 idle 生命周期;仅放开 P 侧 PP |
| Mooncake 传输 | 注册每 entry 的 dtype/head/page stride/容量target MLA 整页传输draft GQA 按 head 交集逐 token 切片;写入前完成全部边界检查 |
| FlashInfer | 迁移已验证的 Kimi SM120 布局与 SiTU 参数适配,同时保留新上游 SwigluStep 行为 |
目标范围Kimi hybrid MLA + 普通 NHD DFlash draft KV、Mooncake、CP=DCP=1无 staging/unified KV/HiSparse。P TP4/PP8/EP4D TP32/PP1BF16 KVchunk=8192。
## FlashInfer 依赖
官方 `#4460` 已于 2026-08-21 合并,提交为 `b460bc00cb373541102d2155aec35bd626e522ce`。但 `v0.6.18` 属于另一条发布分支,实际下载的官方 wheel 没有 CUTLASS `situ_beta/situ_linear_beta` API。
因此本镜像使用 **官方 0.6.18 wheel + 未改写的 #4460 合并补丁**。Dockerfile 对 2 个 Python 和 5 个 C++ 文件先执行 `git apply --check`,再应用上游补丁。它不是未经修改的官方 0.6.18,也不是旧的私人 SiTU kernel。
移除镜像内旧版 `flashinfer-cubin``flashinfer-jit-cache`保留版本校验SM120 CUTLASS 通过官方 JIT 路径编译。[安装说明](https://docs.flashinfer.ai/installation.html)、[#4460](https://github.com/flashinfer-ai/flashinfer/pull/4460)。
## CPU 验证
```bash
# 独立传输测试,无需 GPU 或 torch
cd /data/hzy/src/sglang-kimi-pp-dflash-33863
python3 test/registered/disaggregation/test_mixed_kv_entry_layout.py
# 全部 CPU 回归需要带 torch 的容器;镜像构建时自动执行
python3 -m unittest discover -s test/registered/disaggregation -v
```
| 回归 | 数量 | 主要覆盖 |
|---|---:|---|
| 传输 | 7 | 144 组 KV-head/TP 组合、实际 P-TP4→D-TP32 全 32 rank、逐字节复制、越界/重复写拒绝、注册往返 |
| PP 与 PD 输入 | 12 | PP1/2/4/8/16 capture 归属、边界 residual、空 capture stage、BF16/FP32 分段投影、单次 norm、末 stage 写 KV、输入生命周期、P 普通预热不创建 verify metadata |
| Kimi MoE 合并 | 4 | 两类 gate/up 布局、SiTU 参数、activation 白名单、非连续输入、保留 SwigluStep、API 能力检查 |
23 项在本地、601 修复镜像和 602 导入容器中通过,并完成真实 DFlashWorkerV2、MooncakeKVManager 导入。8 条启动命令的 CLI 解析及两类服务的参数后处理已检查。CPU 测试对实际方法作 AST 提取,使用 CPU tensor 或记录型 engine核验数学与调用契约不替代服务级验证。
601 GPU6 的 `test_kimi_k3_sm120_situ_layout_and_noncontiguous_input` 已通过:检查 Kimi gate/up 及 scale 布局、SiTU(4,25)、非连续输入,以及 SGLang adapter 与直接 FlashInfer 调用的输出一致性。这是小 shape 的集成回归;端到端正确性由后续 PD/GSM8K 检验。
修复前镜像 `local/sglang:kimi-k3-pp-dflash-33863-fi0618-situ4460` 的独立 GPU 复测通过Mooncake CUDA engine 导入成功GPU 测试 1 passed、25.28 秒(复用 JIT 缓存)。
当前镜像为 `local/sglang:kimi-k3-pp-dflash-33863-fi0618-situ4460-pwarm1`,只追加 P 预热修复,不改变 GPU kernel。Linux/amd64 manifest 为 `sha256:281ccb2666a38acd539e6fbb5d55d3682eb2af9ac9089f67e9bf92a8ddd822eb`image config 为 `sha256:8ab5eee9902556bcba2a2b439a9fa1b14d93e0554503754fb7ea74dad6c3cf79`OCI index 为 `sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78`。区分这三个摘要,不将 Docker 不同模式显示的 ID 当成代码不一致。
601 证据均位于实验目录 `results/`
- `pp_and_transport_cpu_601_20260831.log`18 项 CPU 回归。
- `patched_worker_import_20260831.log``patched_launch_help_20260831.log`:真实模块导入与 CLI。
- `image_build_situ4460_cpucheck_20260831.log`:集成镜像的完整 API/回归检查。
- `command_parse_20260831.log`P/D 全部 8 条命令通过 `ServerArgs` argparse 检查;该检查不执行 ServerArgs 后处理或服务初始化。
- `args_resolve_20260831.log``resolved_p_20260831.json``resolved_d_20260831.json`P/D 真实模型配置通过 `resolve_once()` 后处理;保持 BF16 KV、8K chunk 和 FlashInfer。Kimi 投机验证自动选择 `nv_cutedsl`P 侧 PP 自动关闭 overlap scheduler该检查不加载模型权重。
- `sm120_cutlass_compile_20260831.log`SM120 预编译进度。首次构建被外部 Docker SIGKILL 终止,退出 137Docker 事件为显式 kill无 OOM 事件。已编译的对象文件保留在独立缓存。
- `sm120_cutlass_compile_resume_20260831.log`:恢复后编译成功,`SM120_CUTLASS_BUILD_OK`,退出 0。
- `gpu_situ_smoke_detached_20260831.log`:首次完整单测发现 SiTU activation 白名单遗漏;已修复并增加 CPU 回归。
- `gpu_situ_smoke_fix_20260831.log`:修复后 GPU 回归通过1 passed首次 JIT 在内的总用时 771.10 秒。
- `image_build_activation_fix_20260831.log`:固化修复后的镜像构建及 22 项 CPU 回归。
- `final_image_gpu_verify_20260831.log``final_image_gpu_container_20260831.json`:最终镜像独立 GPU 复测、Mooncake 导入、镜像 ID 和挂载证据。
- `pd-dflash-20260831-1617/logs/p_0.log``p_3.log`:首轮 P 预热报错原始证据;该 Run 未进入请求测试,退出码 1。
- `image_build_pwarm1_20260831.log`:预热修复镜像构建及 23 项 CPU 回归。
- `pwarm1_602_cpu.log``pwarm1_602_inspect.json`:约 49 MiB 增量包导入后的容器回归与平台摘要。
已通过 compileall、Black 和 Ruff 的未定义变量/语法检查。
## 实验入口
代码位于 601 的 `/data/hzy/sskj/experiments/pro6000/kimi3_pro6000_pd_dflash_validation`。只运行 `deploy_pd_dflash.sh`,它负责 P/D 启动、健康检查、Router、smoke 和评测。`bench_gsm8k_acceptance.py` 沿用原客户端的 prompt 与请求设置,将结果标签改为 DFlash并增加原始 `meta_info`、verify 次数和输出结束原因归档。
```bash
# 601命令检查不需要 GPU 或 sudo
cd /data/hzy/sskj/experiments/pro6000/kimi3_pro6000_pd_dflash_validation
DRY_RUN=1 RUN_ID=command-audit-20260831 bash deploy_pd_dflash.sh all
```
首轮已执行 `all`,在 P 侧启动阶段退出。修复镜像同步完成后使用新 Run ID 重试。正式顺序为 `start``smoke``bench``logs``stop`,也可用 `all` 串行执行。所有操作使用同一个 `RUN_ID`。失败时保留本任务容器和日志,入口不会自动杀其他实验。
配置选择P 为 TP4/PP8/EP4D 为 TP32/PP1/EP4两侧 FlashInferKV 为 BF16chunk=8192page=64。为 C1/C8 评测将活跃请求与 Decode Graph 上限设为 8未额外改变模型 context 上限。
GSM8K 为原数据集前 64 题,沿用历史客户端的 5-shot、temperature=0、输出上限 512分别运行 C1/C8。输入不裁剪。历史 5-shot 也取自测试集前 5 题,和本次 64 题有重叠:结果适用于与历史流程的部署回归,不作为独立无泄漏的模型准确率评估。逐题输出和截断情况保留。
## 后续
确认 8 节点模型、镜像与网络一致,然后运行 C1 smoke 和固定 GSM8K 64 题 C1/C8。保留逐题答案、截断、接受直方图、总耗时、吞吐、原始 `meta_info` 与服务日志;不重跑 EAGLE3/no-spec 基线。当前客户端为非流式请求,不把客户端总耗时当作 TTFT 或 ITL。
运行时设置 `SGLANG_CACHE_DIR=/cache`FlashInfer、Triton、PyTorch 扩展和 CUDA 编译缓存也指向该挂载目录,`TMPDIR=/cache/tmp`,宿主路径见 `config.env``JIT_CACHE`,避免容器可写层占满根盘;预检会创建所需临时目录。
## 首轮启动修复
`base_runner.py::_dummy_run` 已将 PD Prefill target 设为普通 Decode 预热,但随后仍创建 `DFlashVerifyInput`。普通 Triton Attention 读取 `kv_indptr` 时因此报 `AttributeError`。修复让该分支的 `spec_info=None`D 侧真正的 TARGET_VERIFY 路径不变。没有强行添加字段,也没有修改 DFlash 接受算法。
镜像同步须检查 Docker 所在根盘,而不只检查模型盘 `/data`。本镜像层展开约 34.4GB,压缩内容约 15GB共享层会减少增量占用。607 已按用户授权删除两个无容器引用的 vLLM 镜像,根盘恢复到约 107GB原镜像元数据保存在 `results/607_vllm_images_before_delete_20260831.json`。用户清理 606 后其根盘恢复到约 91GB。601 使用 `ctr images export` 将既有 OCI 压缩层直接导出到 `/data`,其旧 vLLM 镜像尚未删除。

View File

@ -0,0 +1,204 @@
#!/usr/bin/env python3
"""Official SGLang GSM8K prompt semantics with speculative telemetry."""
import argparse
import ast
import json
import re
import time
from pathlib import Path
import numpy as np
import sglang as sgl
from sglang.lang.api import set_default_backend
from sglang.test.test_utils import (
add_common_sglang_args_and_parse,
select_sglang_backend,
)
from sglang.utils import read_jsonl
INVALID = -9999999
def get_one_example(lines, index, include_answer):
text = "Question: " + lines[index]["question"] + "\nAnswer:"
if include_answer:
text += " " + lines[index]["answer"]
return text
def get_answer_value(answer):
numbers = re.findall(r"\d+", answer.replace(",", ""))
if not numbers:
return INVALID
try:
return ast.literal_eval(numbers[-1])
except (SyntaxError, ValueError):
return INVALID
def histogram_accept_length(histogram):
if not histogram:
return None
if isinstance(histogram, dict):
pairs = ((int(key), int(value)) for key, value in histogram.items())
else:
pairs = enumerate(histogram)
total_steps = 0
accepted_drafts = 0
for accepted, count in pairs:
total_steps += count
accepted_drafts += accepted * count
return 1.0 + accepted_drafts / total_steps if total_steps else None
def main(args):
set_default_backend(select_sglang_backend(args))
lines = list(read_jsonl(args.data_path))
few_shot = "".join(
get_one_example(lines, index, True) + "\n\n"
for index in range(args.num_shots)
)
questions = []
labels = []
for index in range(args.num_questions):
prompt = few_shot + get_one_example(lines, index, False)
questions.append({"question": prompt})
labels.append(get_answer_value(lines[index]["answer"]))
@sgl.function
def few_shot_gsm8k(s, question):
s += question
s += sgl.gen(
"answer",
max_tokens=args.max_new_tokens,
stop=["Question", "Assistant:", "<|separator|>"],
)
start = time.perf_counter()
states = few_shot_gsm8k.run_batch(
questions,
temperature=args.temperature,
top_p=args.top_p,
num_threads=args.parallel,
progress_bar=True,
)
duration = time.perf_counter() - start
rows = []
for index, state in enumerate(states):
state_error = state.error()
if state_error is not None:
rows.append(
{
"prompt_id": index,
"output": None,
"correct": False,
"error": repr(state_error),
"completion_tokens": 0,
"spec_accept_length": None,
"spec_accept_length_from_histogram": None,
"spec_accept_rate": None,
"spec_accepted_drafts": None,
"spec_proposed_drafts": None,
"spec_accept_histogram": None,
}
)
continue
output = state["answer"]
metadata = state.get_meta_info("answer")
reported = metadata.get("spec_accept_length")
histogram = metadata.get(
"spec_correct_drafts_histogram", metadata.get("spec_accept_histogram")
)
reconstructed = histogram_accept_length(histogram)
rows.append(
{
"prompt_id": index,
"output": output,
"correct": get_answer_value(output) == labels[index],
"error": None,
"completion_tokens": metadata.get("completion_tokens"),
"spec_accept_length": reported,
"spec_accept_length_from_histogram": reconstructed,
"spec_accept_rate": metadata.get("spec_accept_rate"),
"spec_accepted_drafts": metadata.get("spec_accepted_drafts"),
"spec_proposed_drafts": metadata.get("spec_proposed_drafts"),
"spec_accept_histogram": histogram,
"spec_verify_ct": metadata.get("spec_verify_ct"),
"finish_reason": metadata.get("finish_reason"),
"meta_info": metadata,
}
)
Path(args.output_file).write_text(
"\n".join(json.dumps(row, ensure_ascii=False) for row in rows) + "\n",
encoding="utf-8",
)
successful_rows = [row for row in rows if row["error"] is None]
failed_rows = [row for row in rows if row["error"] is not None]
accept_lengths = [row["spec_accept_length"] for row in successful_rows]
if not successful_rows:
raise RuntimeError("all GSM8K requests failed")
if any(value is None for value in accept_lengths):
raise RuntimeError("speculative acceptance metadata is missing from responses")
total_output_tokens = sum(
row["completion_tokens"] or 0 for row in successful_rows
)
summary = {
"questions": len(rows),
"successful_requests": len(successful_rows),
"failed_requests": len(failed_rows),
"failed_prompt_ids": [row["prompt_id"] for row in failed_rows],
"num_shots": args.num_shots,
"max_new_tokens": args.max_new_tokens,
"parallel": args.parallel,
"temperature": args.temperature,
"top_p": args.top_p,
"prompt_format": "sglang_official_raw_five_shot",
"speculative_algorithm": args.speculative_algorithm,
"length_limited_requests": sum(
isinstance(row.get("finish_reason"), dict)
and row["finish_reason"].get("type") == "length"
for row in successful_rows
),
"accuracy_all_questions": float(
np.mean([row["correct"] for row in rows])
),
"accuracy_successful_requests": float(
np.mean([row["correct"] for row in successful_rows])
),
"mean_accept_length_equal_weight_per_question": float(
np.mean(accept_lengths)
),
"median_accept_length_per_question": float(np.median(accept_lengths)),
"min_accept_length_per_question": float(np.min(accept_lengths)),
"max_accept_length_per_question": float(np.max(accept_lengths)),
"duration_s": duration,
"output_throughput": total_output_tokens / duration,
}
Path(args.summary_file).write_text(
json.dumps(summary, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
print(json.dumps(summary, ensure_ascii=False, indent=2))
if failed_rows:
raise RuntimeError(
f"{len(failed_rows)} of {len(rows)} GSM8K requests failed; "
f"see {args.output_file}"
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--data-path", required=True)
parser.add_argument("--num-shots", type=int, default=5)
parser.add_argument("--num-questions", type=int, default=64)
parser.add_argument("--max-new-tokens", type=int, default=512)
parser.add_argument("--temperature", type=float, default=0.0)
parser.add_argument("--top-p", type=float, default=1.0)
parser.add_argument("--speculative-algorithm", default="DFLASH")
parser.add_argument("--output-file", required=True)
parser.add_argument("--summary-file", required=True)
args = add_common_sglang_args_and_parse(parser)
main(args)

View File

@ -0,0 +1,36 @@
EXPERIMENT=kimi3_pro6000_pd_dflash_validation
PD_IMAGE=local/sglang:kimi-k3-pp-dflash-33863-fi0618-situ4460-pwarm1
MODEL_PATH=/data/hf_models/Kimi-K3
DRAFT_MODEL_PATH=/data/hf_models/Kimi-K3-DFlash
P_NODES=(174.1.60.1 174.1.60.2 174.1.60.3 174.1.60.4)
D_NODES=(174.1.60.5 174.1.60.6 174.1.60.7 174.1.60.8)
SSH_USER=user
SSH_OPTIONS=(-o BatchMode=yes -o ConnectTimeout=10)
PORT=30000
DIST_PORT=20000
BOOTSTRAP_PORT=28800
ROUTER_PORT=31000
P_TP=4
P_PP=8
P_EP=4
D_TP=32
D_PP=1
D_EP=4
P_MEM=0.88
D_MEM=0.86
P_MAMBA_RATIO=0.36
D_MAMBA_RATIO=0.21
CHUNK=8192
PAGE_SIZE=64
KV_DTYPE=bfloat16
DRAFT_TOKENS=16
# GSM8K C1/C8 only; cap capture and scheduling to the measured concurrency.
MAX_RUNNING=8
GRAPH_BS=8
IB_DEVICES=mlx5_0,mlx5_1,mlx5_2,mlx5_3
JIT_CACHE=/data/hzy/cache/kimi-dflash-fi0618-situ4460
HEALTH_WAIT_S=2400
GSM8K="${SCRIPT_DIR}/../../../datasets/gsm8k/test.jsonl"
GSM8K_SHA256=3730d312f6e3440559ace48831e51066acaca737f6eabec99bccb9e4b3c39d14
# Reuse the established client and its prompt/telemetry definitions.
BENCH_CLIENT="${SCRIPT_DIR}/bench_gsm8k_acceptance.py"

View File

@ -0,0 +1,261 @@
#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/config.env"
ACTION="${1:-status}"
DRY_RUN="${DRY_RUN:-0}"
RUN_ID="${RUN_ID:-kimi3-pd-dflash-$(date +%Y%m%d-%H%M%S)}"
[[ "$RUN_ID" =~ ^[a-zA-Z0-9_.-]+$ ]] || exit 2
RESULT_ROOT="${SCRIPT_DIR}/results/${RUN_ID}"
SUDO_PASSWORD_FILE="${SUDO_PASSWORD_FILE:-/data/hzy/.sudo_password}"
ALL_NODES=("${P_NODES[@]}" "${D_NODES[@]}")
mkdir -p "${RESULT_ROOT}"/{commands,logs,bench,metadata}
remote() {
local host="$1" command
shift
if [[ "$host" == "${P_NODES[0]}" ]]; then
"$@"
else
printf -v command '%q ' "$@"
ssh "${SSH_OPTIONS[@]}" "${SSH_USER}@${host}" "$command"
fi
}
root() {
local host="$1" password command
shift
IFS= read -r password <"$SUDO_PASSWORD_FILE"
if [[ "$host" == "${P_NODES[0]}" ]]; then
printf '%s\n' "$password" | sudo -S -p '' -- "$@"
else
printf -v command '%q ' "$@"
printf '%s\n' "$password" | ssh "${SSH_OPTIONS[@]}" \
"${SSH_USER}@${host}" "sudo -S -p '' -- ${command}"
fi
}
name() { printf '%s_%s_%s' "$EXPERIMENT" "$1" "$2"; }
build_command() {
local group="$1" rank="$2" tp pp ep mem ratio head
if [[ "$group" == p ]]; then
HOST="${P_NODES[$rank]}"; head="${P_NODES[0]}"
tp="$P_TP"; pp="$P_PP"; ep="$P_EP"; mem="$P_MEM"; ratio="$P_MAMBA_RATIO"
MODE=prefill
else
HOST="${D_NODES[$rank]}"; head="${D_NODES[0]}"
tp="$D_TP"; pp="$D_PP"; ep="$D_EP"; mem="$D_MEM"; ratio="$D_MAMBA_RATIO"
MODE=decode
fi
CMD=(docker run -d --name "$(name "$group" "$rank")"
--gpus all --network host --ipc=host --ulimit memlock=-1
--device /dev/infiniband
-v "${MODEL_PATH}:${MODEL_PATH}:ro"
-v "${DRAFT_MODEL_PATH}:${DRAFT_MODEL_PATH}:ro"
-v "${JIT_CACHE}:/cache"
-e "SGLANG_HOST_IP=${HOST}" -e PYTHONUNBUFFERED=1
-e HF_HUB_OFFLINE=1 -e TRANSFORMERS_OFFLINE=1
-e GLOO_SOCKET_IFNAME=bond0 -e NCCL_SOCKET_IFNAME=bond1
-e "NCCL_IB_HCA=${IB_DEVICES}" -e NCCL_IB_GID_INDEX=3
-e NCCL_IB_TIMEOUT=22 -e NCCL_IB_RETRY_CNT=7 -e NCCL_CUMEM_ENABLE=1
-e SGLANG_ENABLE_TP_MEMORY_INBALANCE_CHECK=0
-e SGLANG_MOE_FUSED_GATE_RADIX=1
-e FLASHINFER_WORKSPACE_BASE=/cache -e FLASHINFER_CUDA_ARCH_LIST=12.0f
-e SGLANG_CACHE_DIR=/cache
-e XDG_CACHE_HOME=/cache -e TRITON_CACHE_DIR=/cache/triton
-e TORCH_EXTENSIONS_DIR=/cache/torch_extensions -e CUDA_CACHE_PATH=/cache/cuda
-e TMPDIR=/cache/tmp
-e MAX_JOBS=4 --entrypoint python3 "$PD_IMAGE" -m sglang.launch_server
--model-path "$MODEL_PATH" --served-model-name kimi-k3 --trust-remote-code
--tp-size "$tp" --pp-size "$pp" --ep-size "$ep"
--nnodes 4 --node-rank "$rank" --dist-init-addr "${head}:${DIST_PORT}"
--moe-runner-backend flashinfer_mxfp4 --moe-a2a-backend none
--kv-cache-dtype "$KV_DTYPE" --speculative-draft-kv-cache-dtype "$KV_DTYPE"
--chunked-prefill-size "$CHUNK" --page-size "$PAGE_SIZE"
--mem-fraction-static "$mem" --mamba-full-memory-ratio "$ratio"
--mamba-radix-cache-strategy extra_buffer_lazy --disable-radix-cache
--max-running-requests "$MAX_RUNNING" --cuda-graph-max-bs-decode "$GRAPH_BS"
--dist-timeout 3600 --disaggregation-transfer-backend mooncake
--disaggregation-mode "$MODE" --disaggregation-bootstrap-port "$BOOTSTRAP_PORT"
--disaggregation-ib-device "$IB_DEVICES"
--speculative-algorithm DFLASH --speculative-draft-model-path "$DRAFT_MODEL_PATH"
--speculative-num-draft-tokens "$DRAFT_TOKENS"
--enable-metrics --host 0.0.0.0 --port "$PORT")
}
emit() {
local key="$1" host="$2"
shift 2
printf '%q ' "$@" >"${RESULT_ROOT}/commands/${key}.cmd.txt"
printf '\n' >>"${RESULT_ROOT}/commands/${key}.cmd.txt"
printf '%s %s: ' "$key" "$host"
cat "${RESULT_ROOT}/commands/${key}.cmd.txt"
[[ "$DRY_RUN" == 1 ]] || root "$host" "$@"
}
preflight() {
local host gpu image reference="" hash
for host in "${ALL_NODES[@]}"; do
image="$(root "$host" docker image inspect --format '{{.Id}}' "$PD_IMAGE")"
if [[ -z "$reference" ]]; then reference="$image"; fi
[[ "$image" == "$reference" ]] || { echo "image mismatch: $host" >&2; return 1; }
remote "$host" test -r "${MODEL_PATH}/config.json"
remote "$host" test -r "${DRAFT_MODEL_PATH}/model.safetensors"
hash="$(remote "$host" sha256sum "${DRAFT_MODEL_PATH}/config.json")"
[[ "${hash%% *}" == 92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717 ]]
remote "$host" test -e /dev/infiniband/uverbs0
root "$host" mkdir -p "${JIT_CACHE}/tmp"
gpu="$(remote "$host" nvidia-smi --query-compute-apps=pid --format=csv,noheader)"
[[ -z "$gpu" ]] || { echo "GPU occupied: $host $gpu" >&2; return 1; }
remote "$host" python3 -c 'import socket,sys
for p in map(int,sys.argv[1:]):
with socket.socket() as s:
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
try:
s.bind(("0.0.0.0",p)); s.listen(1)
except OSError as exc:
raise SystemExit(f"TCP port {p} unavailable: {exc}")' "$PORT" "$DIST_PORT" "$BOOTSTRAP_PORT" "$ROUTER_PORT"
printf '%s %s\n' "$host" "$image"
done >"${RESULT_ROOT}/metadata/preflight.txt"
hash="$(sha256sum "$GSM8K")"
[[ "${hash%% *}" == "$GSM8K_SHA256" ]]
[[ -r "$BENCH_CLIENT" ]]
}
logs() {
local group rank host
for group in p d; do
for rank in 0 1 2 3; do
build_command "$group" "$rank"; host="$HOST"
root "$host" docker logs "$(name "$group" "$rank")" \
>"${RESULT_ROOT}/logs/${group}_${rank}.log" 2>&1 || true
done
done
root "${P_NODES[0]}" docker logs "$(name router 0)" \
>"${RESULT_ROOT}/logs/router.log" 2>&1 || true
}
wait_health() {
local host="$1" port="$2" deadline=$((SECONDS + HEALTH_WAIT_S))
local checked=$SECONDS group rank running
[[ "$DRY_RUN" == 1 ]] && return 0
while (( SECONDS < deadline )); do
if curl -fsS --max-time 3 "http://${host}:${port}/health" >/dev/null 2>&1; then return 0; fi
if (( SECONDS - checked >= 30 )); then
if [[ "$port" == "$ROUTER_PORT" ]]; then
running="$(root "$host" docker inspect --format '{{.State.Running}}' "$(name router 0)")"
[[ "$running" == true ]] || return 1
else
if [[ "$host" == "${P_NODES[0]}" ]]; then group=p; else group=d; fi
for rank in 0 1 2 3; do
build_command "$group" "$rank"
running="$(root "$HOST" docker inspect --format '{{.State.Running}}' "$(name "$group" "$rank")")"
[[ "$running" == true ]] || { echo "server exited: $HOST" >&2; return 1; }
done
fi
checked=$SECONDS
fi
sleep 5
done
echo "health timeout: $host:$port" >&2
return 1
}
start() {
local group rank
[[ "$DRY_RUN" == 1 ]] || preflight
for group in p d; do
for rank in 1 2 3 0; do
build_command "$group" "$rank"
emit "${group}_${rank}" "$HOST" "${CMD[@]}"
done
if [[ "$group" == p ]]; then wait_health "${P_NODES[0]}" "$PORT"
else wait_health "${D_NODES[0]}" "$PORT"; fi
done
emit router "${P_NODES[0]}" docker run -d --name "$(name router 0)" --network host \
--entrypoint python3 "$PD_IMAGE" -m sglang_router.launch_router \
--pd-disaggregation --mini-lb \
--prefill "http://${P_NODES[0]}:${PORT}" "$BOOTSTRAP_PORT" \
--decode "http://${D_NODES[0]}:${PORT}" --host 0.0.0.0 --port "$ROUTER_PORT"
wait_health "${P_NODES[0]}" "$ROUTER_PORT"
}
stop() {
local group rank
root "${P_NODES[0]}" docker rm -f "$(name router 0)" >/dev/null 2>&1 || true
for group in d p; do
for rank in 0 1 2 3; do
build_command "$group" "$rank"
root "$HOST" docker rm -f "$(name "$group" "$rank")" >/dev/null 2>&1 || true
done
done
}
smoke() {
curl -fsS --max-time 600 -H 'Content-Type: application/json' \
-d '{"text":"Question: Janet has 3 apples and buys 2 more. How many apples does she have?\nAnswer:","sampling_params":{"temperature":0,"max_new_tokens":128}}' \
"http://${P_NODES[0]}:${ROUTER_PORT}/generate" >"${RESULT_ROOT}/bench/smoke.json"
python3 - "${RESULT_ROOT}/bench/smoke.json" <<'PY'
import json, sys
result = json.load(open(sys.argv[1]))
assert result.get("text"), result
assert result.get("meta_info", {}).get("completion_tokens", 0) > 0, result
print(json.dumps(result, ensure_ascii=False))
PY
logs
}
bench() {
local concurrency
for concurrency in 1 8; do
emit "gsm8k_c${concurrency}" "${P_NODES[0]}" docker run --rm --network host \
-v "${GSM8K}:${GSM8K}:ro" -v "${BENCH_CLIENT}:/bench.py:ro" \
-v "${RESULT_ROOT}:/results" --entrypoint python3 "$PD_IMAGE" /bench.py \
--data-path "$GSM8K" --num-questions 64 --num-shots 5 \
--max-new-tokens 512 --temperature 0 --top-p 1 --parallel "$concurrency" \
--speculative-algorithm DFLASH \
--host "${P_NODES[0]}" --port "$ROUTER_PORT" --backend srt \
--output-file "/results/bench/gsm8k_c${concurrency}.jsonl" \
--summary-file "/results/bench/gsm8k_c${concurrency}_summary.json" \
>"${RESULT_ROOT}/bench/gsm8k_c${concurrency}.log" 2>&1
done
[[ "$DRY_RUN" == 1 ]] || logs
}
on_error() {
local rc=$?
trap - ERR
logs || true
echo "FAILED rc=$rc; logs: $RESULT_ROOT (containers retained for diagnosis)" >&2
exit "$rc"
}
if [[ "$DRY_RUN" == 1 ]]; then
case "$ACTION" in start|all|bench) ;; *) echo 'DRY_RUN only supports start/all/bench' >&2; exit 2;; esac
else
ip -o -4 addr show | grep -q " ${P_NODES[0]}/" || {
echo 'Run this entry on Head 601 only' >&2; exit 2;
}
trap on_error ERR
fi
case "$ACTION" in
preflight) preflight ;;
start) start ;;
stop) stop ;;
smoke) smoke ;;
bench) bench ;;
logs) logs ;;
status)
for host in "${ALL_NODES[@]}"; do
printf '%s\n' "$host"
root "$host" docker ps --filter "name=${EXPERIMENT}" --format '{{.Names}} {{.Status}}'
done ;;
all)
start
if [[ "$DRY_RUN" != 1 ]]; then smoke; fi
bench
if [[ "$DRY_RUN" != 1 ]]; then logs; stop; fi ;;
*) echo 'Usage: deploy_pd_dflash.sh {preflight|start|stop|status|logs|smoke|bench|all}' >&2; exit 2 ;;
esac

View File

@ -0,0 +1,739 @@
From b460bc00cb373541102d2155aec35bd626e522ce Mon Sep 17 00:00:00 2001
From: Xuanyu Zhang <xuanyu.zhang@mistral.ai>
Date: Fri, 21 Aug 2026 20:39:35 +0100
Subject: [PATCH] feat(moe): add SiTU-GLU activation to the CUTLASS fused-MoE
backend (#4460)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
<!-- .github/pull_request_template.md -->
## 📌 Description
Adds SiTU-GLU activation support to the CUTLASS fused-MoE backend,
covering all SM variants (SM89/90/100/103/120) via the shared activation
kernel code.
- Adds `ActivationType::Situ = 10` enum value (consistent with the
TRT-LLM Gen path in #4180)
- Implements `SituAdaptor` with `beta` (default 4.0) and `linear_beta`
(default 25.0) per the SiTU paper (Kimi-K3)
- Uses `2·sigmoid(2z)1` for tanh (matching the CuTe-DSL path in #4009)
— avoids `tanh.approx.f32` error amplification at `linear_beta=25`
- Supports per-expert `situ_beta` / `situ_linear_beta` tensors
- Refactors per-expert activation param dispatch into
`setPerExpertActivationParams()` / `hasPerExpertActivationParams()`
helpers (reduces duplication across `doGatedActivationKernel` and
`doActivationKernel`)
- Tests both default and per-expert parameters in BF16 and FP8
## 🚀 Pull Request Checklist
Thank you for contributing to FlashInfer! Before we review your pull
request, please make sure the following items are complete.
### ✅ Pre-commit Checks
- [x] I have installed `pre-commit` by running `pip install pre-commit`
(or used your preferred method).
- [x] I have installed the hooks with `pre-commit install`.
- [x] I have run the hooks manually with `pre-commit run --all-files`
and fixed any reported issues.
> If you are unsure about how to set up `pre-commit`, see [the
pre-commit documentation](https://pre-commit.com/).
## 🧪 Tests
- [x] Tests have been added or updated as needed.
- [x] `pytest tests/moe/test_trtllm_cutlass_fused_moe.py` — SiTU cases
in both `test_moe` (BF16) and `test_moe_fp8`
## Reviewer Notes
<!-- Optional: anything you'd like reviewers to focus on, concerns, etc.
-->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added SiTU-GLU activation support for fused Mixture-of-Experts
operations.
- Added optional global or per-expert SiTU scaling parameters.
- Added support across standard, low-latency, and FP8 MoE execution
paths.
- Added default SiTU scaling values when custom parameters are not
provided.
- Added validation for per-expert scaling inputs.
- **Tests**
- Added coverage for default and per-expert SiTU scales, including FP8
execution.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mickael Seznec <mickael@mistral.ai>
Co-authored-by: Claude <noreply@anthropic.com>
---
benchmarks/routines/moe.py | 15 +--
.../cutlass_fused_moe_kernels.cuh | 92 ++++++++++--------
.../flashinfer_cutlass_fused_moe_binding.cu | 93 ++++++++-----------
.../kernels/cutlass_kernels/include/common.h | 1 +
.../include/moe_gemm_kernels.h | 2 +-
.../cutlass_kernels/include/moe_kernels.h | 10 +-
flashinfer/fused_moe/core.py | 19 ++++
flashinfer/tllm_enums.py | 5 +
tests/moe/test_trtllm_cutlass_fused_moe.py | 69 ++++++++++++--
9 files changed, 191 insertions(+), 115 deletions(-)
diff --git a/benchmarks/routines/moe.py b/benchmarks/routines/moe.py
index e0dae2a5f0..ba55597280 100644
--- a/benchmarks/routines/moe.py
+++ b/benchmarks/routines/moe.py
@@ -21,7 +21,7 @@
cutlass_fused_moe,
fused_topk_deepseek,
)
-from flashinfer.tllm_enums import RoutingMethodType
+from flashinfer.tllm_enums import RoutingMethodType, is_gated_activation
from flashinfer import fp4_quantize, mxfp8_quantize
from flashinfer.testing.utils import (
bench_gpu_time,
@@ -76,19 +76,6 @@ def _activation_kwarg(fn, activation_type: ActivationType) -> dict:
return {}
-def is_gated_activation(activation_type: ActivationType) -> bool:
- """Whether the activation splits FC1 output into gate/up halves (FC1 weight has 2*intermediate
- rows). SwigluStep's clamp limit defaults to 7.0 (the Step-3 model value) in the kernel, so no
- swiglu_limit tensor needs to be passed.
- """
- return activation_type in (
- ActivationType.Swiglu,
- ActivationType.Geglu,
- ActivationType.SwigluBias,
- ActivationType.SwigluStep,
- )
-
-
def run_moe_test(args):
"""
Run a MOE test.
diff --git a/csrc/fused_moe/cutlass_backend/cutlass_fused_moe_kernels.cuh b/csrc/fused_moe/cutlass_backend/cutlass_fused_moe_kernels.cuh
index 0b2ff69359..8fa79d09c0 100644
--- a/csrc/fused_moe/cutlass_backend/cutlass_fused_moe_kernels.cuh
+++ b/csrc/fused_moe/cutlass_backend/cutlass_fused_moe_kernels.cuh
@@ -2245,6 +2245,47 @@ struct SwigluStepAdaptor {
}
};
+// SiTU-GLU (Kimi-K3 / mistral ffn_activations.situ_glu). A gated activation that transforms both
+// branches, evaluated in fp32 (bf16 rounding is visible at the tanh saturation points):
+// out = (beta * tanh(gate / beta) * sigmoid(gate)) * (linear_beta * tanh(up / linear_beta))
+// Note the sigmoid reads the *uncapped* gate.
+struct SituAdaptor {
+ constexpr static bool IS_GLU = true;
+ float beta = 4.0f;
+ float linear_beta = 25.0f;
+
+ template <class T>
+ __device__ T operator()(T const& gate, T const& linear) const {
+ cutlass::epilogue::thread::Sigmoid<T> sigmoid{};
+ // tanh(z) == 2*sigmoid(2z) - 1. CUTLASS's Sigmoid uses ::expf, whereas its Tanh lowers to
+ // tanh.approx.f32 whose 2^-11 absolute error linear_beta=25 would amplify to ~1e-2.
+ // The `+ (-1.0f)` is because cutlass::Array has no operator-(Array, scalar).
+ auto tanh = [&](T const& z) { return sigmoid(z * 2.0f) * 2.0f + (-1.0f); };
+ return (tanh(gate * (1.0f / beta)) * sigmoid(gate) * beta) *
+ (tanh(linear * (1.0f / linear_beta)) * linear_beta);
+ }
+};
+
+__device__ inline bool hasPerExpertActivationParams(ActivationParams const& params) {
+ return params.swiglu_alpha || params.swiglu_beta || params.swiglu_limit || params.situ_beta ||
+ params.situ_linear_beta;
+}
+
+// Only assigns what the caller actually supplied, so each adaptor keeps its compile-time default
+// (e.g. SwigluStepAdaptor::limit == 7.0, SituAdaptor::beta == 4.0).
+template <class ActFn>
+__device__ void setPerExpertActivationParams(ActFn& fn, ActivationParams const& params,
+ int64_t expert) {
+ if constexpr (std::is_same_v<ActFn, SituAdaptor>) {
+ if (params.situ_beta) fn.beta = params.situ_beta[expert];
+ if (params.situ_linear_beta) fn.linear_beta = params.situ_linear_beta[expert];
+ } else {
+ if (params.swiglu_alpha) fn.alpha = params.swiglu_alpha[expert];
+ if (params.swiglu_beta) fn.beta = params.swiglu_beta[expert];
+ if (params.swiglu_limit) fn.limit = params.swiglu_limit[expert];
+ }
+}
+
// ============================== Gated Activation =================================
constexpr static int MAX_ACTIVATION_THREADS_PER_BLOCK = 256;
@@ -2276,26 +2317,12 @@ __global__ void doGatedActivationKernel(ActivationOutputType* output,
int64_t const num_elems_in_col = inter_size / ACTIVATION_ELEM_PER_THREAD;
int64_t const inter_size_vec = inter_size / ACTIVATION_ELEM_PER_THREAD;
- float gate_alpha = 1.0f;
- float gate_bias = 0.0f;
- float gate_limit = std::numeric_limits<float>::infinity();
- if (activation_type.swiglu_alpha || activation_type.swiglu_beta || activation_type.swiglu_limit) {
- int expert = findTotalEltsLessThanTarget(expert_first_token_offset, num_experts_per_node,
- (int64_t)token + 1) -
- 1;
- gate_alpha = activation_type.swiglu_alpha ? activation_type.swiglu_alpha[expert] : 1.0f;
- gate_bias = activation_type.swiglu_beta ? activation_type.swiglu_beta[expert] : 0.0f;
- gate_limit = activation_type.swiglu_limit ? activation_type.swiglu_limit[expert]
- : std::numeric_limits<float>::infinity();
- }
-
ActFn fn{};
- fn.alpha = gate_alpha;
- fn.beta = gate_bias;
- // Keep the activation's compile-time default limit (e.g. 7.0 for SwigluStep) unless the caller
- // supplied a per-expert swiglu_limit tensor.
- if (activation_type.swiglu_limit) {
- fn.limit = gate_limit;
+ if (hasPerExpertActivationParams(activation_type)) {
+ int64_t const expert = findTotalEltsLessThanTarget(expert_first_token_offset,
+ num_experts_per_node, (int64_t)token + 1) -
+ 1;
+ setPerExpertActivationParams(fn, activation_type, expert);
}
for (int64_t elem_index = start_offset; elem_index < num_elems_in_col; elem_index += stride) {
auto linear_value = arrayConvert<GemmResultElem, ComputeElem>(gemm_result_vec[elem_index]);
@@ -2328,6 +2355,8 @@ void doGatedActivation(ActivationOutputType* output, GemmOutputType const* gemm_
? &doGatedActivationKernel<ActivationOutputType, GemmOutputType, SwigluBiasAdaptor>
: activation_type == ActivationType::SwigluStep
? &doGatedActivationKernel<ActivationOutputType, GemmOutputType, SwigluStepAdaptor>
+ : activation_type == ActivationType::Situ
+ ? &doGatedActivationKernel<ActivationOutputType, GemmOutputType, SituAdaptor>
: nullptr;
TLLM_CHECK_WITH_INFO(fn != nullptr, "Invalid activation type");
fn<<<blocks, threads, 0, stream>>>(output, gemm_result, expert_first_token_offset, inter_size,
@@ -2391,22 +2420,13 @@ __global__ __launch_bounds__(MAX_ACTIVATION_THREADS_PER_BLOCK) void doActivation
size_t output_offset = token * inter_size;
int64_t expert = 0;
- float gate_alpha = 1.0f;
- float gate_beta = 0.0f;
- float gate_limit = std::numeric_limits<float>::infinity();
if (bias_ptr || IsNVFP4 || IsMXFP8 || use_per_expert_act_scale ||
- activation_params.swiglu_alpha || activation_params.swiglu_beta ||
- activation_params.swiglu_limit) {
+ hasPerExpertActivationParams(activation_params)) {
expert = permuted_token_selected_experts
? permuted_token_selected_experts[token]
: findTotalEltsLessThanTarget(expert_first_token_offset, num_experts_per_node,
token + 1) -
1;
-
- gate_alpha = activation_params.swiglu_alpha ? activation_params.swiglu_alpha[expert] : 1.0f;
- gate_beta = activation_params.swiglu_beta ? activation_params.swiglu_beta[expert] : 0.0f;
- gate_limit = activation_params.swiglu_limit ? activation_params.swiglu_limit[expert]
- : std::numeric_limits<float>::infinity();
}
size_t act_scale_idx = use_per_expert_act_scale ? expert : 0;
@@ -2444,13 +2464,7 @@ __global__ __launch_bounds__(MAX_ACTIVATION_THREADS_PER_BLOCK) void doActivation
int64_t const gated_off_vec = gated_off / ACTIVATION_ELEM_PER_THREAD;
ActFn fn{};
- fn.alpha = gate_alpha;
- fn.beta = gate_beta;
- // Keep the activation's compile-time default limit (e.g. 7.0 for SwigluStep) unless the caller
- // supplied a per-expert swiglu_limit tensor.
- if (activation_params.swiglu_limit) {
- fn.limit = gate_limit;
- }
+ setPerExpertActivationParams(fn, activation_params, expert);
auto compute_activation = [&](int64_t elem_index) {
GemmResultElem fc1_gemm_value;
cutlass::arch::global_load<GemmResultElem, sizeof(GemmResultElem)>(
@@ -2670,7 +2684,11 @@ void doActivation(T* output, GemmOutputType const* gemm_result, float const* fp8
IdentityAdaptor<cutlass::epilogue::thread::Identity>,
decltype(block_scaling_type)::value,
decltype(disableFP4QuantFastMathTag)::value,
- decltype(nvfp4_4over6_config_tag)> // Identity
+ decltype(nvfp4_4over6_config_tag)>, // Identity
+ &doActivationKernel<T, GemmOutputType, ScaleBiasType, SituAdaptor,
+ decltype(block_scaling_type)::value,
+ decltype(disableFP4QuantFastMathTag)::value,
+ decltype(nvfp4_4over6_config_tag)> // Situ
};
return fn_list[static_cast<int>(activation_type.activation_type)];
};
diff --git a/csrc/fused_moe/cutlass_backend/flashinfer_cutlass_fused_moe_binding.cu b/csrc/fused_moe/cutlass_backend/flashinfer_cutlass_fused_moe_binding.cu
index 79a7aa7757..46237da826 100644
--- a/csrc/fused_moe/cutlass_backend/flashinfer_cutlass_fused_moe_binding.cu
+++ b/csrc/fused_moe/cutlass_backend/flashinfer_cutlass_fused_moe_binding.cu
@@ -81,6 +81,17 @@ class DtypeUtils {
DtypeUtils() = default;
};
+// Validates one of the optional per-expert activation scale tensors (swiglu_alpha, situ_beta, ...)
+// and returns its data pointer, or nullptr when the caller did not supply it.
+inline float const* checkedPerExpertScale(Optional<TensorView> const& scale,
+ int num_experts_on_rank, char const* name) {
+ if (!scale.has_value()) return nullptr;
+ CHECK_INPUT_AND_TYPE(scale.value(), dl_float32);
+ TVM_FFI_ICHECK_EQ(scale.value().size(0), num_experts_on_rank)
+ << name << " must have num_experts_on_rank elements.";
+ return static_cast<float const*>(scale.value().data_ptr());
+}
+
class FusedMoeRunner : public tvm::ffi::ModuleObj {
public:
template <
@@ -302,6 +313,7 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
Optional<TensorView> fc2_expert_biases, Optional<Array<Tensor>> quant_scales,
Optional<TensorView> input_sf, Optional<TensorView> swiglu_alpha,
Optional<TensorView> swiglu_beta, Optional<TensorView> swiglu_limit,
+ Optional<TensorView> situ_beta, Optional<TensorView> situ_linear_beta,
bool swizzled_input_sf, int64_t tp_size, int64_t tp_rank, int64_t ep_size,
int64_t ep_rank, int64_t cluster_size, int64_t cluster_rank, bool enable_alltoall,
bool min_latency_mode, Optional<Array<int64_t>> profile_ids, bool enable_pdl,
@@ -397,21 +409,6 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
int const num_experts_on_rank = fc2_expert_weights.size(0);
auto const num_experts_total = static_cast<int>(num_experts_on_rank * ep_size);
auto parallelism_config = kernels::MOEParallelismConfig(tp_size, tp_rank, ep_size, ep_rank);
- if (swiglu_alpha.has_value()) {
- CHECK_INPUT_AND_TYPE(swiglu_alpha.value(), dl_float32);
- TVM_FFI_ICHECK_EQ(swiglu_alpha.value().size(0), num_experts_on_rank)
- << "swiglu_alpha must have num_experts_on_rank elements.";
- }
- if (swiglu_beta.has_value()) {
- CHECK_INPUT_AND_TYPE(swiglu_beta.value(), dl_float32);
- TVM_FFI_ICHECK_EQ(swiglu_beta.value().size(0), num_experts_on_rank)
- << "swiglu_beta must have num_experts_on_rank elements.";
- }
- if (swiglu_limit.has_value()) {
- CHECK_INPUT_AND_TYPE(swiglu_limit.value(), dl_float32);
- TVM_FFI_ICHECK_EQ(swiglu_limit.value().size(0), num_experts_on_rank)
- << "swiglu_limit must have num_experts_on_rank elements.";
- }
// Swiglu + swiglu_alpha/beta/limit selects the SwigluBias kernel; other gated activations
// (e.g. SwigluStep) keep their own kernel.
if (base_activation_type == ActivationType::Swiglu &&
@@ -420,12 +417,11 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
}
auto activation_params = ActivationParams(
base_activation_type,
- reinterpret_cast<float const*>(swiglu_alpha.has_value() ? swiglu_alpha.value().data_ptr()
- : nullptr),
- reinterpret_cast<float const*>(swiglu_beta.has_value() ? swiglu_beta.value().data_ptr()
- : nullptr),
- reinterpret_cast<float const*>(swiglu_limit.has_value() ? swiglu_limit.value().data_ptr()
- : nullptr));
+ checkedPerExpertScale(swiglu_alpha, num_experts_on_rank, "swiglu_alpha"),
+ checkedPerExpertScale(swiglu_beta, num_experts_on_rank, "swiglu_beta"),
+ checkedPerExpertScale(swiglu_limit, num_experts_on_rank, "swiglu_limit"),
+ checkedPerExpertScale(situ_beta, num_experts_on_rank, "situ_beta"),
+ checkedPerExpertScale(situ_linear_beta, num_experts_on_rank, "situ_linear_beta"));
setRunnerProfiles(profile_ids);
@@ -486,7 +482,8 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
Optional<TensorView> fc2_expert_biases,
Optional<Array<Tensor>> quant_scales, Optional<TensorView> input_sf,
Optional<TensorView> swiglu_alpha, Optional<TensorView> swiglu_beta,
- Optional<TensorView> swiglu_limit, bool swizzled_input_sf,
+ Optional<TensorView> swiglu_limit, Optional<TensorView> situ_beta,
+ Optional<TensorView> situ_linear_beta, bool swizzled_input_sf,
TensorView num_active_experts_per_node, TensorView experts_to_token_score,
TensorView active_expert_global_ids, int64_t tp_size, int64_t tp_rank,
int64_t ep_size, int64_t ep_rank, int64_t cluster_size,
@@ -567,21 +564,6 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
int const num_experts_on_rank = fc2_expert_weights.size(0);
auto const num_experts_total = static_cast<int>(num_experts_on_rank * ep_size);
auto parallelism_config = kernels::MOEParallelismConfig(tp_size, tp_rank, ep_size, ep_rank);
- if (swiglu_alpha.has_value()) {
- CHECK_INPUT_AND_TYPE(swiglu_alpha.value(), dl_float32);
- TVM_FFI_ICHECK_EQ(swiglu_alpha.value().size(0), num_experts_on_rank)
- << "swiglu_alpha must have num_experts_on_rank elements.";
- }
- if (swiglu_beta.has_value()) {
- CHECK_INPUT_AND_TYPE(swiglu_beta.value(), dl_float32);
- TVM_FFI_ICHECK_EQ(swiglu_beta.value().size(0), num_experts_on_rank)
- << "swiglu_beta must have num_experts_on_rank elements.";
- }
- if (swiglu_limit.has_value()) {
- CHECK_INPUT_AND_TYPE(swiglu_limit.value(), dl_float32);
- TVM_FFI_ICHECK_EQ(swiglu_limit.value().size(0), num_experts_on_rank)
- << "swiglu_limit must have num_experts_on_rank elements.";
- }
// Swiglu + swiglu_alpha/beta/limit selects the SwigluBias kernel; other gated activations
// (e.g. SwigluStep) keep their own kernel.
if (base_activation_type == ActivationType::Swiglu &&
@@ -590,12 +572,11 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
}
auto activation_params = ActivationParams(
base_activation_type,
- reinterpret_cast<float const*>(swiglu_alpha.has_value() ? swiglu_alpha.value().data_ptr()
- : nullptr),
- reinterpret_cast<float const*>(swiglu_beta.has_value() ? swiglu_beta.value().data_ptr()
- : nullptr),
- reinterpret_cast<float const*>(swiglu_limit.has_value() ? swiglu_limit.value().data_ptr()
- : nullptr));
+ checkedPerExpertScale(swiglu_alpha, num_experts_on_rank, "swiglu_alpha"),
+ checkedPerExpertScale(swiglu_beta, num_experts_on_rank, "swiglu_beta"),
+ checkedPerExpertScale(swiglu_limit, num_experts_on_rank, "swiglu_limit"),
+ checkedPerExpertScale(situ_beta, num_experts_on_rank, "situ_beta"),
+ checkedPerExpertScale(situ_linear_beta, num_experts_on_rank, "situ_linear_beta"));
setRunnerProfiles(profile_ids);
@@ -811,16 +792,17 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
Optional<TensorView> fc2_expert_biases, Optional<Array<Tensor>> quant_scales,
Optional<TensorView> input_sf, Optional<TensorView> swiglu_alpha,
Optional<TensorView> swiglu_beta, Optional<TensorView> swiglu_limit,
+ Optional<TensorView> situ_beta, Optional<TensorView> situ_linear_beta,
bool swizzled_input_sf, int64_t tp_size, int64_t tp_rank, int64_t ep_size,
int64_t ep_rank, int64_t cluster_size, int64_t cluster_rank, bool enable_alltoall,
bool min_latency_mode, Optional<Array<int64_t>> profile_ids, bool enable_pdl,
int64_t base_activation_type, Optional<TensorView> workspace_buffer) {
runMoe(output, input, token_selected_experts, token_final_scales, fc1_expert_weights,
fc1_expert_biases, fc2_expert_weights, fc2_expert_biases, quant_scales, input_sf,
- swiglu_alpha, swiglu_beta, swiglu_limit, swizzled_input_sf, tp_size, tp_rank,
- ep_size, ep_rank, cluster_size, cluster_rank, enable_alltoall, min_latency_mode,
- profile_ids, enable_pdl, static_cast<ActivationType>(base_activation_type),
- workspace_buffer);
+ swiglu_alpha, swiglu_beta, swiglu_limit, situ_beta, situ_linear_beta,
+ swizzled_input_sf, tp_size, tp_rank, ep_size, ep_rank, cluster_size,
+ cluster_rank, enable_alltoall, min_latency_mode, profile_ids, enable_pdl,
+ static_cast<ActivationType>(base_activation_type), workspace_buffer);
});
} else if (name == "run_moe_min_latency") {
return Function::FromTyped(
@@ -830,20 +812,21 @@ class FusedMoeRunner : public tvm::ffi::ModuleObj {
Optional<TensorView> fc2_expert_biases, Optional<Array<Tensor>> quant_scales,
Optional<TensorView> input_sf, Optional<TensorView> swiglu_alpha,
Optional<TensorView> swiglu_beta, Optional<TensorView> swiglu_limit,
+ Optional<TensorView> situ_beta, Optional<TensorView> situ_linear_beta,
bool swizzled_input_sf, TensorView num_active_experts_per_node,
TensorView experts_to_token_score, TensorView active_expert_global_ids,
int64_t tp_size, int64_t tp_rank, int64_t ep_size, int64_t ep_rank,
int64_t cluster_size, int64_t cluster_rank, bool enable_alltoall,
bool min_latency_mode, Optional<Array<int64_t>> profile_ids, bool enable_pdl,
int64_t base_activation_type, Optional<TensorView> workspace_buffer) {
- runMoeMinLantency(output, input, token_selected_experts, token_final_scales,
- fc1_expert_weights, fc1_expert_biases, fc2_expert_weights,
- fc2_expert_biases, quant_scales, input_sf, swiglu_alpha, swiglu_beta,
- swiglu_limit, swizzled_input_sf, num_active_experts_per_node,
- experts_to_token_score, active_expert_global_ids, tp_size, tp_rank,
- ep_size, ep_rank, cluster_size, cluster_rank, enable_alltoall,
- min_latency_mode, profile_ids, enable_pdl,
- static_cast<ActivationType>(base_activation_type), workspace_buffer);
+ runMoeMinLantency(
+ output, input, token_selected_experts, token_final_scales, fc1_expert_weights,
+ fc1_expert_biases, fc2_expert_weights, fc2_expert_biases, quant_scales, input_sf,
+ swiglu_alpha, swiglu_beta, swiglu_limit, situ_beta, situ_linear_beta,
+ swizzled_input_sf, num_active_experts_per_node, experts_to_token_score,
+ active_expert_global_ids, tp_size, tp_rank, ep_size, ep_rank, cluster_size,
+ cluster_rank, enable_alltoall, min_latency_mode, profile_ids, enable_pdl,
+ static_cast<ActivationType>(base_activation_type), workspace_buffer);
});
} else if (name == "get_workspace_size") {
return Function::FromTyped([this](int64_t num_rows, int64_t hidden_size, int64_t inter_size,
diff --git a/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/common.h b/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/common.h
index ce1c0df4e0..11c01a6860 100644
--- a/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/common.h
+++ b/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/common.h
@@ -30,6 +30,7 @@ enum class ActivationType {
SwigluStep,
GegluTanh,
Identity,
+ Situ,
InvalidType
};
diff --git a/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_gemm_kernels.h b/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_gemm_kernels.h
index 3761e32cf1..2be7043187 100644
--- a/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_gemm_kernels.h
+++ b/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_gemm_kernels.h
@@ -244,7 +244,7 @@ constexpr bool isGatedActivation(ActivationType activation_type) {
return activation_type == ActivationType::Swiglu || activation_type == ActivationType::Geglu ||
activation_type == ActivationType::SwigluBias ||
activation_type == ActivationType::SwigluStep ||
- activation_type == ActivationType::GegluTanh;
+ activation_type == ActivationType::GegluTanh || activation_type == ActivationType::Situ;
}
enum class Sm90Wfp4Afp8ScaleMode : uint8_t {
diff --git a/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_kernels.h b/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_kernels.h
index 01daea011b..dfd19e72c5 100644
--- a/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_kernels.h
+++ b/csrc/nv_internal/tensorrt_llm/kernels/cutlass_kernels/include/moe_kernels.h
@@ -118,6 +118,9 @@ struct ActivationParams {
float const* swiglu_alpha = nullptr;
float const* swiglu_beta = nullptr;
float const* swiglu_limit = nullptr;
+ // SiTU-GLU per-expert tanh scales; nullptr uses the SituAdaptor compile-time defaults.
+ float const* situ_beta = nullptr;
+ float const* situ_linear_beta = nullptr;
explicit ActivationParams(ActivationType activation_type) : activation_type(activation_type) {
TLLM_CHECK_WITH_INFO(
@@ -126,11 +129,14 @@ struct ActivationParams {
}
ActivationParams(ActivationType activation_type, float const* swiglu_alpha,
- float const* swiglu_beta, float const* swiglu_limit)
+ float const* swiglu_beta, float const* swiglu_limit,
+ float const* situ_beta = nullptr, float const* situ_linear_beta = nullptr)
: activation_type(activation_type),
swiglu_alpha(swiglu_alpha),
swiglu_beta(swiglu_beta),
- swiglu_limit(swiglu_limit) {}
+ swiglu_limit(swiglu_limit),
+ situ_beta(situ_beta),
+ situ_linear_beta(situ_linear_beta) {}
// TODO Port everything properly and get rid of these implicit conversions
operator ActivationType() const { return activation_type; }
diff --git a/flashinfer/fused_moe/core.py b/flashinfer/fused_moe/core.py
index 585ce94048..8a68e9f27b 100644
--- a/flashinfer/fused_moe/core.py
+++ b/flashinfer/fused_moe/core.py
@@ -884,6 +884,8 @@ def cutlass_fused_moe(
swiglu_alpha: Optional[torch.Tensor] = None,
swiglu_beta: Optional[torch.Tensor] = None,
swiglu_limit: Optional[torch.Tensor] = None,
+ situ_beta: Optional[torch.Tensor] = None,
+ situ_linear_beta: Optional[torch.Tensor] = None,
swizzled_input_sf: bool = True,
tp_size: int = 1,
tp_rank: int = 0,
@@ -1015,6 +1017,8 @@ def cutlass_fused_moe(
swiglu_alpha,
swiglu_beta,
swiglu_limit,
+ situ_beta,
+ situ_linear_beta,
swizzled_input_sf,
*min_latency_output,
tp_size,
@@ -1058,6 +1062,8 @@ def _fake_cutlass_fused_moe(
swiglu_alpha: Optional[torch.Tensor] = None,
swiglu_beta: Optional[torch.Tensor] = None,
swiglu_limit: Optional[torch.Tensor] = None,
+ situ_beta: Optional[torch.Tensor] = None,
+ situ_linear_beta: Optional[torch.Tensor] = None,
swizzled_input_sf: bool = True,
tp_size: int = 1,
tp_rank: int = 0,
@@ -1206,6 +1212,9 @@ def cutlass_fused_moe(
use_fused_finalize: bool = True,
profile_ids: Optional[List[int]] = None,
workspace_buffer: Optional[torch.Tensor] = None,
+ *,
+ situ_beta: Optional[torch.Tensor] = None,
+ situ_linear_beta: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Compute a Mixture of Experts (MoE) layer using CUTLASS backend.
@@ -1278,6 +1287,14 @@ def cutlass_fused_moe(
swiglu_limit : Optional[torch.Tensor]
Swiglu limit for swiglu activation.
+ situ_beta : Optional[torch.Tensor]
+ Per-expert ``beta`` tanh scale for the ``Situ`` activation (float32,
+ ``[num_experts_on_rank]``). ``None`` uses ``DEFAULT_SITU_BETA``.
+
+ situ_linear_beta : Optional[torch.Tensor]
+ Per-expert ``linear_beta`` tanh scale for the ``Situ`` activation (float32,
+ ``[num_experts_on_rank]``). ``None`` uses ``DEFAULT_SITU_LINEAR_BETA``.
+
tp_size : int = 1
Tensor parallelism size. Defaults to 1.
@@ -1447,6 +1464,8 @@ def cutlass_fused_moe(
swiglu_alpha,
swiglu_beta,
swiglu_limit,
+ situ_beta,
+ situ_linear_beta,
swizzled_input_sf,
tp_size,
tp_rank,
diff --git a/flashinfer/tllm_enums.py b/flashinfer/tllm_enums.py
index c0fad19ec4..0d6d783331 100644
--- a/flashinfer/tllm_enums.py
+++ b/flashinfer/tllm_enums.py
@@ -103,6 +103,11 @@ def is_gated(self) -> bool:
DEFAULT_SWIGLU_BETA = 0.0
DEFAULT_SWIGLU_LIMIT = torch.finfo(torch.float32).max
+# SiTU-GLU tanh scales. Must match the SituAdaptor defaults in
+# csrc/fused_moe/cutlass_backend/cutlass_fused_moe_kernels.cuh.
+DEFAULT_SITU_BETA = 4.0
+DEFAULT_SITU_LINEAR_BETA = 25.0
+
def normalize_activation_type(
activation_type: Union[int, ActivationType],
diff --git a/tests/moe/test_trtllm_cutlass_fused_moe.py b/tests/moe/test_trtllm_cutlass_fused_moe.py
index 3f58d5dbf7..e874c44810 100644
--- a/tests/moe/test_trtllm_cutlass_fused_moe.py
+++ b/tests/moe/test_trtllm_cutlass_fused_moe.py
@@ -20,6 +20,7 @@
import pytest
from flashinfer.fused_moe.core import ActivationType
+from flashinfer.tllm_enums import DEFAULT_SITU_BETA, DEFAULT_SITU_LINEAR_BETA
import torch
from torch.nn import functional as F
@@ -53,6 +54,17 @@
set_nvfp4_4over6_env = moe_utils.set_nvfp4_4over6_env
+def make_situ_scales(num_experts):
+ """Per-expert SiTU-GLU tanh scales, deliberately different from DEFAULT_SITU_BETA /
+ DEFAULT_SITU_LINEAR_BETA so a kernel silently falling back to those would fail."""
+ return {
+ "situ_beta": torch.full((num_experts,), 5.0, dtype=torch.float32).cuda(),
+ "situ_linear_beta": torch.full(
+ (num_experts,), 18.0, dtype=torch.float32
+ ).cuda(),
+ }
+
+
def dynamic_per_tensor_fp8_quant(x: torch.tensor) -> tuple[torch.tensor, torch.tensor]:
fp8_traits_max = FLOAT8_E4M3_MAX
fp8_traits_min = -FLOAT8_E4M3_MAX
@@ -323,6 +335,8 @@ def compute_with_experts(
beta=None,
limit=None,
activation_type=ActivationType.Swiglu,
+ situ_beta=DEFAULT_SITU_BETA,
+ situ_linear_beta=DEFAULT_SITU_LINEAR_BETA,
):
results = torch.zeros_like(x)
for expert_id in range(num_experts):
@@ -359,6 +373,22 @@ def compute_with_experts(
x2 = x2.clamp_(min=-limit, max=limit) + beta
inter = x1_scaled * x2
+ elif activation_type == ActivationType.Situ:
+ # SiTU-GLU, computed in fp32; see SituAdaptor in cutlass_fused_moe_kernels.cuh.
+ # situ_beta / situ_linear_beta are per-expert when given as a tensor/list.
+ sb = float(
+ situ_beta[expert_id] if hasattr(situ_beta, "__getitem__") else situ_beta
+ )
+ slb = float(
+ situ_linear_beta[expert_id]
+ if hasattr(situ_linear_beta, "__getitem__")
+ else situ_linear_beta
+ )
+ gate = (expert_inputs @ w1_expert.t()).float()
+ up = (expert_inputs @ w3_expert.t()).float()
+ out_glu = sb * torch.tanh(gate / sb) * torch.sigmoid(gate)
+ out_linear = slb * torch.tanh(up / slb)
+ inter = (out_glu * out_linear).to(x.dtype)
else:
inter = F.silu(expert_inputs @ w1_expert.t()) * (
expert_inputs @ w3_expert.t()
@@ -390,12 +420,23 @@ def compute_with_experts(
@pytest.mark.parametrize("top_k", TOP_K_VALUES)
@pytest.mark.parametrize("intermediate_size", INTERMEDIATE_SIZES)
@pytest.mark.parametrize(
- "activation_type",
- [ActivationType.Swiglu, ActivationType.SwigluStep],
- ids=["swiglu", "swiglustep"],
+ "activation_type, situ_per_expert",
+ [
+ (ActivationType.Swiglu, False),
+ (ActivationType.SwigluStep, False),
+ (ActivationType.Situ, False),
+ (ActivationType.Situ, True),
+ ],
+ ids=["swiglu", "swiglustep", "situ_default", "situ_per_expert"],
)
def test_moe(
- batch_size, hidden_size, num_experts, top_k, intermediate_size, activation_type
+ batch_size,
+ hidden_size,
+ num_experts,
+ top_k,
+ intermediate_size,
+ activation_type,
+ situ_per_expert,
):
# Skip invalid configurations
if top_k > num_experts:
@@ -425,6 +466,13 @@ def test_moe(
)
routing_weights, selected_experts = compute_routing(router_logits, top_k)
+
+ # When situ_per_expert is off the kernel must fall back to its compile-time defaults, which is
+ # what compute_with_experts() uses by default. The per-expert scales below are deliberately
+ # non-default so the test fails if the kernel ignores the tensors and falls back anyway.
+ situ_kwargs = make_situ_scales(num_experts) if situ_per_expert else {}
+ ref_situ_kwargs = {k: v.tolist() for k, v in situ_kwargs.items()}
+
ref_output = compute_with_experts(
num_experts,
x,
@@ -433,6 +481,7 @@ def test_moe(
selected_experts,
routing_weights,
activation_type=activation_type,
+ **ref_situ_kwargs,
)
flash_output = torch.empty_like(ref_output)
flash_output = fused_moe.cutlass_fused_moe(
@@ -445,6 +494,7 @@ def test_moe(
output=flash_output,
quant_scales=None,
activation_type=activation_type,
+ **situ_kwargs,
)
torch.testing.assert_close(ref_output, flash_output[0], rtol=1e-2, atol=1e-2)
@@ -613,8 +663,8 @@ def run_unfused():
@pytest.mark.parametrize("otype, wtype", [(torch.float16, torch.float8_e4m3fn)])
@pytest.mark.parametrize(
"activation_type",
- [ActivationType.Swiglu, ActivationType.SwigluStep],
- ids=["swiglu", "swiglustep"],
+ [ActivationType.Swiglu, ActivationType.SwigluStep, ActivationType.Situ],
+ ids=["swiglu", "swiglustep", "situ"],
)
def test_moe_fp8(
batch_size,
@@ -661,6 +711,11 @@ def test_moe_fp8(
w31_dequantized.data[expert_id].copy_(torch.mul(w31_quant.to(dtype=otype), s31))
w2_dequantized.data[expert_id].copy_(torch.mul(w2_quant.to(dtype=otype), s2))
+ situ_kwargs = (
+ make_situ_scales(num_experts) if activation_type == ActivationType.Situ else {}
+ )
+ ref_situ_kwargs = {k: v.tolist() for k, v in situ_kwargs.items()}
+
routing_weights, selected_experts = compute_routing(router_logits, top_k)
ref_output = compute_with_experts(
num_experts,
@@ -670,6 +725,7 @@ def test_moe_fp8(
selected_experts,
routing_weights,
activation_type=activation_type,
+ **ref_situ_kwargs,
)
flash_output = torch.empty_like(ref_output)
# For fp8, the hidden_state expects quantized.
@@ -693,6 +749,7 @@ def test_moe_fp8(
quant_scales=quant_scales,
output=flash_output,
activation_type=activation_type,
+ **situ_kwargs,
)
torch.testing.assert_close(ref_output, flash_output, rtol=1e-1, atol=1e-1)

View File

@ -0,0 +1,81 @@
{
"base": "6465a6f3d3b6c8b7fee40fba0fdc09cf5e9ca1c5",
"files": [
{
"path": "python/sglang/srt/arg_groups/speculative_hook.py",
"sha256": "26d656eba10219a5ff6bb4c2675ca15355f6b3d9f33639af9b3a21a8e1f8b2cb"
},
{
"path": "python/sglang/srt/arg_groups/validation_hook.py",
"sha256": "08151771718df1f17a0df91b005d17fd62055314a642c656d7964ff7c5b11b40"
},
{
"path": "python/sglang/srt/disaggregation/base/conn.py",
"sha256": "fbd2c0e0d8deee59f58a7a2dccb38e6137aae74a8e47fc40a23bb25d8b7e86e1"
},
{
"path": "python/sglang/srt/disaggregation/common/kv_entry_layout.py",
"sha256": "97f559279f1f87fb4769ef923e47b697476df85f324d7594a97f3364f9875042"
},
{
"path": "python/sglang/srt/disaggregation/decode.py",
"sha256": "b00e588cb3d0b6706a586ef4b488454834d4891b46c0679c2d41781b1a4f3e28"
},
{
"path": "python/sglang/srt/disaggregation/mooncake/conn.py",
"sha256": "08c8bf93e5c0c04e581b585fe355284e2967a623b5d99761d212a67c66500f49"
},
{
"path": "python/sglang/srt/disaggregation/prefill.py",
"sha256": "d0175b3df8eddd58fbfa41805d0928d614e412cf74055e57aade82578b174bfd"
},
{
"path": "python/sglang/srt/disaggregation/utils.py",
"sha256": "40a1b51fd9b549b4208f7dc4b72061f99d96fad9096bc9f270d88b6fd556512b"
},
{
"path": "python/sglang/srt/layers/moe/moe_runner/flashinfer_cutlass.py",
"sha256": "128bc0d46cc1c7b3c5258a423437a0d79b2f02c15ad2fcfc3cbf26b782921c86"
},
{
"path": "python/sglang/srt/layers/quantization/mxfp4.py",
"sha256": "bf072608ac84646c932c5dcbad3ee5f9cda7f2a73cbee97801be06aa64c2f2c7"
},
{
"path": "python/sglang/srt/managers/scheduler_pp_mixin.py",
"sha256": "46ae2313973ba3769382da4376c59961e547f8f7e6a204c27e593cc51ef712db"
},
{
"path": "python/sglang/srt/model_executor/runner/base_runner.py",
"sha256": "95aee38376e2cfc178e9bd3d675a3489268d4aa3c41934d22a27339f16810c7e"
},
{
"path": "python/sglang/srt/models/kimi_k3.py",
"sha256": "d4d1c13050ce11e63e05c6aa589f7d0a7431cb5994138a83846bfa1f57890ba4"
},
{
"path": "python/sglang/srt/speculative/dflash_pp.py",
"sha256": "efb9f02236c9c5eabe8e27c14eedffb1cbc297cc20a7abd8aca9d748e0096b3a"
},
{
"path": "python/sglang/srt/speculative/dflash_worker_v2.py",
"sha256": "73d9dd199605a58e3090c2b8f993b851089fd21d32cf78978061704569f7c80c"
},
{
"path": "python/sglang/srt/speculative/spec_info.py",
"sha256": "c188dfd0bf2abba18e24fee9a44897c3b564dffcfb228bd079ea900be6b1fc50"
},
{
"path": "test/registered/disaggregation/test_dflash_pp_context.py",
"sha256": "3f3022afa4acd7f66e14caf6bbbfb88b1f2e9320d087300aa78c9d9e20d3a321"
},
{
"path": "test/registered/disaggregation/test_flashinfer_kimi_merge.py",
"sha256": "0cdb173b8d073c3ba2ce5e07eee75f203bcb2313156c7e7af3c27bb24b4ea9e2"
},
{
"path": "test/registered/disaggregation/test_mixed_kv_entry_layout.py",
"sha256": "d0dabf551d27f5b80ffdb5129cec42c4fc628887e6faa73537981872705a1d8e"
}
]
}

View File

@ -0,0 +1,8 @@
{"host": "6kd-9", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-10", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-11", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-12", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-13", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-14", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-15", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}
{"host": "6kd-16", "models": {"Kimi-K3": {"config_sha256": "9710e121a58d03ac92c8d6da287a19541994319afbbe6d6202af001ffd379213", "file_count": 96, "total_bytes": 1560936091448, "sizes_sha256": "3cad8261dbb865df4ae950c50206b45126d8d14e57287e07c983d423b11b945f", "missing": [], "empty": []}, "Kimi-K3-DFlash": {"config_sha256": "92e2928e57f417921cd1c031a18840834c55ed13ed0d722acfa8f41b01080717", "file_count": 1, "total_bytes": 5196953912, "sizes_sha256": "10a50b801e091244c6c6febf02ccd3b01d63a9b7b1f68751de55f633e0ff2d58", "missing": [], "empty": []}}}

View File

@ -0,0 +1,8 @@
174.1.60.1 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.2 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.3 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.4 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.5 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.6 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.7 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78
174.1.60.8 sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78

View File

@ -0,0 +1,28 @@
test_capture_ownership_including_boundaries (test_dflash_pp_context.TestPPContext.test_capture_ownership_including_boundaries) ... ok
test_invalid_capture_configuration (test_dflash_pp_context.TestPPContext.test_invalid_capture_configuration) ... ok
test_kimi_boundary_uses_next_stage_weights (test_dflash_pp_context.TestPPContext.test_kimi_boundary_uses_next_stage_weights) ... ok
test_last_stage_without_capture_uses_incoming_context (test_dflash_pp_context.TestPPContext.test_last_stage_without_capture_uses_incoming_context) ... ok
test_missing_incoming_context_fails_before_kv_write (test_dflash_pp_context.TestPPContext.test_missing_incoming_context_fails_before_kv_write) ... ok
test_nonfinal_pool_is_minimal_without_mutating_target_config (test_dflash_pp_context.TestPPContext.test_nonfinal_pool_is_minimal_without_mutating_target_config) ... ok
test_only_prefill_skips_draft_graph_initialization (test_dflash_pp_context.TestPPContext.test_only_prefill_skips_draft_graph_initialization) ... ok
test_pd_input_builder_and_spec_dispatch (test_dflash_pp_context.TestPPContext.test_pd_input_builder_and_spec_dispatch) ... ok
test_pp8_boundary_capture (test_dflash_pp_context.TestPPContext.test_pp8_boundary_capture) ... ok
test_pp8_projection_empty_stages_float32_and_bf16 (test_dflash_pp_context.TestPPContext.test_pp8_projection_empty_stages_float32_and_bf16) ... ok
test_pp_proxy_is_consumed_once_even_on_forward_failure (test_dflash_pp_context.TestPPContext.test_pp_proxy_is_consumed_once_even_on_forward_failure) ... ok
test_prefill_dummy_forward_has_no_verify_metadata (test_dflash_pp_context.TestPPContext.test_prefill_dummy_forward_has_no_verify_metadata) ... ok
test_activation_selection_accepts_situ_and_legacy_enum (test_flashinfer_kimi_merge.TestFlashInferKimiMerge.test_activation_selection_accepts_situ_and_legacy_enum) ... ok
test_capability_requires_public_parameters (test_flashinfer_kimi_merge.TestFlashInferKimiMerge.test_capability_requires_public_parameters) ... ok
test_runner_preserves_swiglu_step_and_old_api (test_flashinfer_kimi_merge.TestFlashInferKimiMerge.test_runner_preserves_swiglu_step_and_old_api) ... ok
test_weight_layout_and_situ_parameters (test_flashinfer_kimi_merge.TestFlashInferKimiMerge.test_weight_layout_and_situ_parameters) ... ok
test_all_gqa_shards_and_replicas_byte_exact (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_all_gqa_shards_and_replicas_byte_exact) ... ok
test_flat_stride_mismatch_rejected (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_flat_stride_mismatch_rejected) ... ok
test_invalid_metadata_rejected_before_copy (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_invalid_metadata_rejected_before_copy) ... ok
test_mooncake_mixed_entries_match_layers_before_transfer (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_mooncake_mixed_entries_match_layers_before_transfer) ... ok
test_real_kimi_dflash_page64_tp4_to_tp32 (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_real_kimi_dflash_page64_tp4_to_tp32) ... ok
test_replicated_mla_is_flat_and_coalesced (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_replicated_mla_is_flat_and_coalesced) ... ok
test_wire_roundtrip (test_mixed_kv_entry_layout.TestMixedKVEntryLayout.test_wire_roundtrip) ... ok
----------------------------------------------------------------------
Ran 23 tests in 3.313s
OK

View File

@ -0,0 +1,185 @@
[
{
"Id": "sha256:281ccb2666a38acd539e6fbb5d55d3682eb2af9ac9089f67e9bf92a8ddd822eb",
"RepoTags": [
"local/sglang:kimi-k3-pp-dflash-33863-fi0618-situ4460-pwarm1"
],
"RepoDigests": [
"local/sglang@sha256:d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78"
],
"Comment": "buildkit.dockerfile.v0",
"Created": "2026-08-31T16:35:23.511383363+08:00",
"Config": {
"Env": [
"PATH=/root/.cargo/bin:/opt/sglang/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/nvidia/bin",
"NVARCH=x86_64",
"NVIDIA_REQUIRE_CUDA=cuda>=13.0 brand=unknown,driver>=535,driver<536 brand=grid,driver>=535,driver<536 brand=tesla,driver>=535,driver<536 brand=nvidia,driver>=535,driver<536 brand=quadro,driver>=535,driver<536 brand=quadrortx,driver>=535,driver<536 brand=nvidiartx,driver>=535,driver<536 brand=vapps,driver>=535,driver<536 brand=vpc,driver>=535,driver<536 brand=vcs,driver>=535,driver<536 brand=vws,driver>=535,driver<536 brand=cloudgaming,driver>=535,driver<536 brand=unknown,driver>=550,driver<551 brand=grid,driver>=550,driver<551 brand=tesla,driver>=550,driver<551 brand=nvidia,driver>=550,driver<551 brand=quadro,driver>=550,driver<551 brand=quadrortx,driver>=550,driver<551 brand=nvidiartx,driver>=550,driver<551 brand=vapps,driver>=550,driver<551 brand=vpc,driver>=550,driver<551 brand=vcs,driver>=550,driver<551 brand=vws,driver>=550,driver<551 brand=cloudgaming,driver>=550,driver<551 brand=unknown,driver>=565,driver<566 brand=grid,driver>=565,driver<566 brand=tesla,driver>=565,driver<566 brand=nvidia,driver>=565,driver<566 brand=quadro,driver>=565,driver<566 brand=quadrortx,driver>=565,driver<566 brand=nvidiartx,driver>=565,driver<566 brand=vapps,driver>=565,driver<566 brand=vpc,driver>=565,driver<566 brand=vcs,driver>=565,driver<566 brand=vws,driver>=565,driver<566 brand=cloudgaming,driver>=565,driver<566 brand=unknown,driver>=570,driver<571 brand=grid,driver>=570,driver<571 brand=tesla,driver>=570,driver<571 brand=nvidia,driver>=570,driver<571 brand=quadro,driver>=570,driver<571 brand=quadrortx,driver>=570,driver<571 brand=nvidiartx,driver>=570,driver<571 brand=vapps,driver>=570,driver<571 brand=vpc,driver>=570,driver<571 brand=vcs,driver>=570,driver<571 brand=vws,driver>=570,driver<571 brand=cloudgaming,driver>=570,driver<571 brand=unknown,driver>=575,driver<576 brand=grid,driver>=575,driver<576 brand=tesla,driver>=575,driver<576 brand=nvidia,driver>=575,driver<576 brand=quadro,driver>=575,driver<576 brand=quadrortx,driver>=575,driver<576 brand=nvidiartx,driver>=575,driver<576 brand=vapps,driver>=575,driver<576 brand=vpc,driver>=575,driver<576 brand=vcs,driver>=575,driver<576 brand=vws,driver>=575,driver<576 brand=cloudgaming,driver>=575,driver<576",
"NV_CUDA_CUDART_VERSION=13.0.96-1",
"CUDA_VERSION=13.0.3",
"LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/local/cuda/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64",
"NVIDIA_VISIBLE_DEVICES=all",
"NVIDIA_DRIVER_CAPABILITIES=compute,utility",
"NV_CUDA_LIB_VERSION=13.0.3-1",
"NV_NVTX_VERSION=13.0.85-1",
"NV_LIBNPP_VERSION=13.0.1.2-1",
"NV_LIBNPP_PACKAGE=libnpp-13-0=13.0.1.2-1",
"NV_LIBCUSPARSE_VERSION=12.6.3.3-1",
"NV_LIBCUBLAS_PACKAGE_NAME=libcublas-13-0",
"NV_LIBCUBLAS_VERSION=13.1.1.3-1",
"NV_LIBCUBLAS_PACKAGE=libcublas-13-0=13.1.1.3-1",
"NV_LIBNCCL_PACKAGE_NAME=libnccl2",
"NV_LIBNCCL_PACKAGE_VERSION=2.28.3-1",
"NCCL_VERSION=2.28.3-1",
"NV_LIBNCCL_PACKAGE=libnccl2=2.28.3-1+cuda13.0",
"NVIDIA_PRODUCT_NAME=CUDA",
"NV_CUDA_CUDART_DEV_VERSION=13.0.96-1",
"NV_NVML_DEV_VERSION=13.0.87-1",
"NV_LIBCUSPARSE_DEV_VERSION=12.6.3.3-1",
"NV_LIBNPP_DEV_VERSION=13.0.1.2-1",
"NV_LIBNPP_DEV_PACKAGE=libnpp-dev-13-0=13.0.1.2-1",
"NV_LIBCUBLAS_DEV_VERSION=13.1.1.3-1",
"NV_LIBCUBLAS_DEV_PACKAGE_NAME=libcublas-dev-13-0",
"NV_LIBCUBLAS_DEV_PACKAGE=libcublas-dev-13-0=13.1.1.3-1",
"NV_CUDA_NSIGHT_COMPUTE_VERSION=13.0.3-1",
"NV_CUDA_NSIGHT_COMPUTE_DEV_PACKAGE=cuda-nsight-compute-13-0=13.0.3-1",
"NV_LIBNCCL_DEV_PACKAGE_NAME=libnccl-dev",
"NV_LIBNCCL_DEV_PACKAGE_VERSION=2.28.3-1",
"NV_LIBNCCL_DEV_PACKAGE=libnccl-dev=2.28.3-1+cuda13.0",
"LIBRARY_PATH=/usr/local/cuda/lib64/stubs",
"NV_CUDNN_VERSION=9.14.0.64-1",
"NV_CUDNN_PACKAGE_NAME=libcudnn9-cuda-13",
"NV_CUDNN_PACKAGE=libcudnn9-cuda-13=9.14.0.64-1",
"NV_CUDNN_PACKAGE_DEV=libcudnn9-dev-cuda-13=9.14.0.64-1",
"NV_CUDNN_PACKAGE_DEV_HEADERS=libcudnn9-headers-cuda-13=9.14.0.64-1",
"DEBIAN_FRONTEND=noninteractive",
"CUDA_HOME=/usr/local/cuda",
"GDRCOPY_HOME=/usr/src/gdrdrv-2.5.1/",
"FLASHINFER_VERSION=0.6.17",
"LANG=en_US.UTF-8",
"LANGUAGE=en_US:en",
"LC_ALL=en_US.UTF-8",
"SGLANG_BUILD_COMMIT=daf631719690e18d13f67a20eb513fd48c712327",
"SGLANG_BUILD_URL=https://github.com/sgl-project/sglang/actions/runs/33137164725",
"SGLANG_IMAGE_TAG=lmsysorg/sglang:nightly-dev-20260828-daf63171",
"PYTHONPATH=/opt/kimi-dflash/python",
"PYTHONDONTWRITEBYTECODE=1",
"FLASHINFER_DISABLE_VERSION_CHECK=",
"SGLANG_SOURCE_ROOT=/opt/kimi-dflash"
],
"Entrypoint": [
"python3",
"-m",
"sglang.launch_server"
],
"WorkingDir": "/sgl-workspace/sglang",
"Labels": {
"ai.sglang.build.commit": "daf631719690e18d13f67a20eb513fd48c712327",
"ai.sglang.build.url": "https://github.com/sgl-project/sglang/actions/runs/33137164725",
"ai.sglang.image.tag": "lmsysorg/sglang:nightly-dev-20260828-daf63171",
"com.nvidia.cudnn.version": "9.14.0.64-1",
"maintainer": "NVIDIA CORPORATION <cudatools@nvidia.com>",
"org.opencontainers.image.revision": "daf631719690e18d13f67a20eb513fd48c712327",
"org.opencontainers.image.source": "https://github.com/sgl-project/sglang",
"org.opencontainers.image.url": "https://github.com/sgl-project/sglang/actions/runs/33137164725",
"org.opencontainers.image.version": "lmsysorg/sglang:nightly-dev-20260828-daf63171"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 14967226422,
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:5e732af9e7c568c9b41ecabc76ac93a58471934d5155070dfd64a9567667fd9d",
"sha256:f5b49b5386a3c18aca8dccc85784c57d64b182f621a632374c44daeb7822e9ca",
"sha256:2950e5ad5b560d8a4561ea596a8589f9be34eb485ad04ae521438c978d98a212",
"sha256:f56f6d7fecabd59c6ae0104489b7e42e0b1c538ba1246f0019b099a12cca8cd6",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:6756a6579040c1541966a48c3e4d3bac9500de08ee027795439141ee0ba0eecd",
"sha256:fdb5c9bcf16b58539209a7e6a469bea3a5b5434d2c4e9d4719968e22fe0ef1d7",
"sha256:c6340b3836ce7fea1a99cadff25d755971a2091ecc7815f7761cce83624961ca",
"sha256:6d6b5c3ac20f833a318cc28f64194bc3d50371b023199e420c641dd5d3264d5e",
"sha256:2dfea3ee7ecb9bf9eaf210231c0d8fc84706edea83c584300f86aef7eb0dfe1d",
"sha256:988d8769daf31ed246461f52c452d8b11248ba47e5b06fe8210915025327d393",
"sha256:cd905001042d6fb31a08ed1272f4b36b9bf1814c0e111355cc8725277cd4bfb7",
"sha256:ae8a69caad45e0cf5977673d59e9b3d444943e89e8eb503a7798f093c65162e8",
"sha256:3f83440160ca573ae240f1525e4e9d6c7ee9d055dfc7be61ac7af84ee1642313",
"sha256:72f31487cece23c9c9f79d1336cf0887726864ba145d967da1fb5d775e533d93",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:3cbf470cb28d2108aba6f0154ecc8a457dc588af7161b915474987bf7973eef2",
"sha256:a679dc7078c9cfa517d01828412d0a591707211483cb74e6313ae603a006f239",
"sha256:8d074d326c9d61118e25e27c432dac303839d3529df5b64a165438848cc2f950",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:7509e379739e5c54072504957c5e22be0cbfb8d9ca12d3b66450c2a725c1f2bb",
"sha256:15785f6df9bee4007ab28a370d83c300ac85ab056869609d1607f6e3c88a6b2c",
"sha256:ada9078922901f5e11dadf528356e717f1619f305c2e32bd8569f92ad76a08b0",
"sha256:a8ee45b1f77587a9ad6bfc8c28d98e2a928f02442251442b5e38bd2a89c480bb",
"sha256:4efe4144ff056f4e35ab86371e2b6905e238d4752e41c0a793821a6469864e3f",
"sha256:10007f71c41cfc3a88da7b29b4dd9edc5d417515b7f63126527bf0b6c1f546fe",
"sha256:c648315cc3944840ae4661ad11397d0acde62110459f7b3b178d1e6f0c3d4079",
"sha256:a1cf5e134ae7bbba0d8002a8deecda067a440170fd9c90318b3be18c25f15c61",
"sha256:b064bfce42d6545b7c7e4c191abc9997e2cd43b96efcf14e56cc342b12201011",
"sha256:f985ef7df34872310bb3c00367c23a55c12def9692698bd2820b9c377e83013b",
"sha256:a1a57562b488e2fdc164abe1045170ac864ddc9417995966034f839058813eac",
"sha256:2258726d23a32a4d5c468c0b1bbe985a8537c47cf34db06ebece8b4d4daa74b1",
"sha256:faa84dbafd41fa49b0b648cb6557e7343849b389d93fdf5556f6e2decaf550a1",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:e8706d16624fb04f6a2dfeb067da4254f54a550decc54267915e26cccb4c0fed",
"sha256:d324fa1e96e663f204caea0ac5e1be0cf5b3a8a67a3bc931a484f134dcfa6a6d",
"sha256:853adfa25cad926899088fd81ace2a3eaecb0b64815ada56c016dc20e17c02e4",
"sha256:81e9c64c1f5b93dfa25081071a7d1744344fbf41ae9233270bf4ea6db59ddd33",
"sha256:c4274c717b4e908fc996bfbee932682d08233f52424ab7954aff5f4014931500",
"sha256:8876e61557f92352e0fa2e79f835d2a2617cd44bdd5cfe72b4ee5deb66645da2",
"sha256:cd60d9eff385b6ff80d2e285a57914c5dc921861ea69a3ce7d7fe3d0bb2c05d0",
"sha256:3cf3641ca559478f4b9316177739b72e159dafd7d0c163d4d08a2b999a034c27",
"sha256:28f200a4f493abe3b5531e85ad3423f72bde68df2b3b61a2417e0c7d9b6177a8",
"sha256:9029cbfb4b4e3bdef2574ec2af6c9240208af42ad47326c038f23acb802f843d",
"sha256:81ce6120dddf6397bdc20e75911d99c8ea891891ecd84a585f28ebe26134061b",
"sha256:f9c2555ebfec8d41e60e4323a8a46a2e7d1b17e8f8ab5a823e9513387b4eac7a",
"sha256:ffabea8dc4f4987995b8a0ff313ac920cd77e534103ad19e800de02d00c210fb",
"sha256:372d209365d371ad6864e432126bec3403add2a274eb5c4d72c09a891fe6c773",
"sha256:74f3ccaf8aa1c45cf376811caaa8cd70da8d349ff8b7c34624570a50c8813c1d",
"sha256:f3cb350e69a5b6c4e176f428401faaadb539c1afc8e891baf1a077fdc6f7df9f",
"sha256:cae7c313be69dccbed4a034062338e1e4e6d92090e9c4c7a38308c4ff261231d",
"sha256:e9ad469189345e9bc779fb888594205c7eb5b997e50d4cc7a33559e39de48a86",
"sha256:817e9f83523ce8b5289b76165dcadf14a21eb45cda7fcd8dc3ac7f7480757bda",
"sha256:4c6d2f48bbc68fe34f554017e18166ad2628d203d435414af7facdba57ba6bc1",
"sha256:82381ac149748e9cd4bfecedd26c6808e4e4e8ff251dfa7c36c6eec115e01408",
"sha256:df5778a62653618e7d7a55efbb2002b8eea2a455da4fab1aa57714fac72e8354",
"sha256:de669107068ddbc9a7ae7bdc4c83e11b7fd17e2a75f93f5384de8d3bcd937073",
"sha256:b185c4deee75530ce0ad0088a587b33c48f6a217d1f13f894e73eea735d76d5a",
"sha256:1fa7159b375ca9c6fbf5b1f61b7d9aaf88583c53bfe52933cc3799a7de2e2b7d",
"sha256:57611659260d363d32f15cee45f01a836a5df931ccd21546e03e965690afd697",
"sha256:e5c5a0f5e39c9e1de42eeea1e198142925fa4a533a956f316fa785c69b6c9a56",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:bd1946dd19d617f0a8a0ebf2a88e7cdab07a77f9fa070a35a605396dbdcaaed2",
"sha256:647babc16cef2877883c9a4276e9b800011130b4a921a1c58dc2d90db912221d",
"sha256:d03dfaade251e784281d5e6cc3d35cecf809e0994e67c9c170d9e0c869df8408",
"sha256:4ba4ee5654a71c370d25e571934ad0d1a03211fcf36a94ae7318d13fcb5b671d",
"sha256:c39e8c43807472b24f161f29d6feb422dfb949fe7100d69f1ef7eadedc14c0fc",
"sha256:bc97787ac190f68c2cc3aa5e08cd2862ea83ddd224796401bfc2f084990c308d",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:5a8a3022261ca98b6ecb6309d3faa376daa5d819c8a1c3bbfeba389ffce6272b",
"sha256:e6fda71a3f6320ed1295de878c8c1367cef2f616ba1d84cd371f895f0e47a2ba",
"sha256:ba942b61f6a46ad0c35de1c7c63ff5ecd00befac92b56d8cc56146af616f69c4",
"sha256:aa65adc2c641830ccc13c37bb23c7658aeecea9c495d858a52d53141c34a8969",
"sha256:7c448cf35d32b08e4e9c1faba519b3bed1d81043ada7bb1f9834968fc2f06786",
"sha256:311055521e8a3fcc512490f0ff1f602db67dd536a01b62c984a97070fe8f7911",
"sha256:de65b09749fec355f64308704feb09b837cfb4ea9bc6e553c9261c73275b7cb8",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
]
},
"Metadata": {
"LastTagTime": "2026-08-31T08:44:45.57613455Z"
},
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:281ccb2666a38acd539e6fbb5d55d3682eb2af9ac9089f67e9bf92a8ddd822eb",
"size": 15020,
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
}
]

View File

@ -0,0 +1,93 @@
{
"required_base_image": "sha256:6f998f448dd3545423e2bd73000c8bce991b4dbc9be66aff329b978b303c5987",
"image": "sha256:8ab5eee9902556bcba2a2b439a9fa1b14d93e0554503754fb7ea74dad6c3cf79",
"archive": "sglang-kimi-pp-dflash-8ab5eee-pwarm1.delta.oci.tar",
"bytes": 50759680,
"sha256": "8920c7a66a903a0653cd0f1cc087f626d241557bd7b63214db044eca89b768d5",
"included": [
"blobs",
"blobs/sha256",
"blobs/sha256/108c859dc864e31043ddf1c3fa387c8397d6495939e11227e0a162fbbdba2023",
"blobs/sha256/281ccb2666a38acd539e6fbb5d55d3682eb2af9ac9089f67e9bf92a8ddd822eb",
"blobs/sha256/2ec8cdb54d91b2a0c9bf3aaf8855ab9319c5a07776cca449d6a5b26c9f721d15",
"blobs/sha256/38fca1f6908e11bd0945eff79c3f0fe8175c812bd88d2a3e0d9cfb20d81c1d83",
"blobs/sha256/3d0e896ac992404d479d6a73d4cc65bcb8506bebb982a415d90d15aa46503795",
"blobs/sha256/5e60539501edb70ef0ccd153dc5ba783117d1e916379fd44e116f5e5fd1b9d37",
"blobs/sha256/605208809bbedf1c51355c52df881abfd3ae8dbbfef94567e65b837a876dd319",
"blobs/sha256/8ab5eee9902556bcba2a2b439a9fa1b14d93e0554503754fb7ea74dad6c3cf79",
"blobs/sha256/9446f6f72966bb53dcea092aec81b887153fc8e024da73d3073d390c2e0938a8",
"blobs/sha256/a2d38d45b3b09b273eaa72ebcb7e1c30dc568fac72008492cdf53fd4f4e69f9e",
"blobs/sha256/d30d68757014b973c2edd5d061cc3fd55660a4c68cc3d0af9050fcb7e64c4a78",
"index.json",
"manifest.json",
"oci-layout"
],
"preexisting_blobs": [
"blobs/sha256/04ebfffe153ff264a394da45dd64c3e830c5f16c2e285959f72d49982b8330b2",
"blobs/sha256/088360b17cced9ae058a1342b9ab050b50bc7cfb72dfdcf7d04233d0d5a140b6",
"blobs/sha256/2154f8da8e6a860abe32529e59350d6da38d60205e956686560a68878f0f4949",
"blobs/sha256/216bf0c7a62ce24763d96e3f79789c7091108aa1ed05f5311c21dd887b054605",
"blobs/sha256/21e0ed254c8bac8e7e21e80b250a5dc4a92211bbc2f658f9f81ef93c7c623f03",
"blobs/sha256/25367c7aad83c96fda41bf8f039bb2fe57d9b2a475b3d5d7fdb5945278935ea4",
"blobs/sha256/257c5743ada16f22123bd0b28e4a8cd4280a3f72f2c75058a04b7117a9507f31",
"blobs/sha256/2628d54d17a882758e620e3a8b07e9181ff253dce5946bee42d77c8f34065d6d",
"blobs/sha256/2f59ed97b933ab02bc8c208f9bfa5cbd2f2b203c1c972be713196987c61f8e68",
"blobs/sha256/30fb6218a3a4c7ea900128f10ef45e0e33b7df8b19c48f1e91cce984586cdc3e",
"blobs/sha256/3537474cb776983ae719c5a4a141d940777320e985371a4f88887117a64d5108",
"blobs/sha256/3a0d5962c5fcd07ccaf39e4a12985c440536eb2e0768f6f0c08fbc71bf699cfb",
"blobs/sha256/3ff483a4017c9c0d5c5ce8c57df85996144da7a2cdb440d4010914e6e6d37153",
"blobs/sha256/400821fd86ee1a17c460a7addf3892121cfb660a274b37e6a23cf36e7eaa931c",
"blobs/sha256/41aa8951d381527892cc220ff0c1d6e1ddd5527f3b8612066b37be7abcbfa81f",
"blobs/sha256/43f0f6265ae934400a0bd140cca733929de5026ae47360c2608cbc6c99508d89",
"blobs/sha256/44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"blobs/sha256/4477ccaea26652af48319688a16221ebb55a7a0de91c09ac8117cf4a88d203ad",
"blobs/sha256/4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1",
"blobs/sha256/5109ac5cb09b4c1eb33e1af8e806e34d0cd2f99375ff9c503de47f85e5611e83",
"blobs/sha256/527294152c9b07684d4d1f02b0afe6609d176282aa61d8b8968867c833481c56",
"blobs/sha256/5347e3e9b03fcfe4c347eb536fb743b5655e2ee0efc286719c930707784dab34",
"blobs/sha256/58d2172ebde0f9fecf755ac29d213f92adaa11806d6bb09d5ba7eee68ca4d341",
"blobs/sha256/5aa2bdef1d0c2fc3cbc86b86d351369901a24126f22e974e914c4c15bb01be0c",
"blobs/sha256/5bec02c16746b1fe15687b8df421f93fa2638f05ca2cd423d5be3c7979979d65",
"blobs/sha256/5bfec0e8bb11ecc202d0ca16cdb1f0e3390ad25705bd6a4b59284f04c85a940c",
"blobs/sha256/5e25946ba40dcbc2410bf1852d135a46cb31cc7f89c05b9ef1ab12a6ef988aeb",
"blobs/sha256/5fe493bec4795a3b68752f0b0f987d20efc48388fce5c5f7fad65e2011d31733",
"blobs/sha256/689b91d88a0f4086057ec826027b128902ecf2b516be510371c115bc55da19a6",
"blobs/sha256/730c8029606bf4b4533d7a7159458cf5e3f348ea956ccfb10ce5da3e20adac8f",
"blobs/sha256/753fe1c8b50013fccd0c156fb7091fe949b926876af6602c0a2e037d049ed14e",
"blobs/sha256/7723c0339d4ff66ed471c2c7b5e900e877a2477efa33b17cba42092ec5ef248b",
"blobs/sha256/79f971bb1a784b1a29ad3ae7e1376f146545dfe9a798ae600feb2eaaadb5fd81",
"blobs/sha256/848e634a564c2ca96ad2ce7a12bc0956e50c8186548a3aceac273afa7387a377",
"blobs/sha256/88d0092c6f752e77b376e7a0e50aa9547d66f8eb8b5e32b6f2e0aa3e1dd51a44",
"blobs/sha256/8b7f3999bbb358a5d5bc445380aba87aec6725bcbb41882d33ef9346ca105881",
"blobs/sha256/8bd080c2e4b22c71c5058be60551a2735c1bead7341fe005313ca704578d9fa5",
"blobs/sha256/92d6eafe91c933626ee8d9d9530de26ded162a5c81e3e5030c89384c98774c99",
"blobs/sha256/95e35692d3cc347d712fd236fd2af3b1c697783518182b1ae716722f694ed616",
"blobs/sha256/9681265a10ff460cc05d28f0bf5a56356b18a7d595f94d66f18ee2fea2ee82a8",
"blobs/sha256/9da825116641fadfcf4f55e849aabf92994ce1ba50760a68a1647f2df9347e86",
"blobs/sha256/a073d6f2f59b8e347d00cf592bb1f62da9f5eee3d25462dabab3f473abbc0204",
"blobs/sha256/a30ad5edf82cd178710efe9eaeac43d1e78bbcca4ab2fd20dac0cc3eb6bf1bba",
"blobs/sha256/a30da298bda6986d68697bc361b9204f189616a3b7cc748c91846ecddbb873aa",
"blobs/sha256/a496798fdd1a6ed0f8df3ca91bbbad569c7a8a5e3ad6f28e06fd237bbfe6f6c5",
"blobs/sha256/adebc1576f3c07100011ce7679aef5e7bb1e4aaca050e6d8e729273d22a2442a",
"blobs/sha256/b2848d797b1413db0b192a69782d4786ce9226cbf6be47154f06f7675f11bab6",
"blobs/sha256/b533a7368b7da8141f98b9a2442f84b5aa5d32f2d286c2611a32f725361f84b6",
"blobs/sha256/b80baf68b599275411a988ae77891a2782b66425a216fa07ef080d2efc6197d8",
"blobs/sha256/be7e2f489592134bebe19820b8233d5ba1da985c43f1fb46133741dbd4b3b272",
"blobs/sha256/cb3db0ad5ae089b6ae0c5b39b73e73cac40a558df052e602f8b0f24972b003b4",
"blobs/sha256/cc689184d8c0977f56d2da63b3a3d225dc9c7fadb9375338768cf4909b016b32",
"blobs/sha256/ccf9c70a85fc6158d617c85f3f719f669efb00c28fd45fa292575d351435bd2f",
"blobs/sha256/d103ce79450cbe8e275382ca45943531c3d08058f5c5fdd1d66f01acefac3a7f",
"blobs/sha256/d2dceafa44338ead1244a6542f284631554823289d552b98df574537fd0cc91a",
"blobs/sha256/d9f0d064333ffda4221fc5ebb606f9c7881ed90a6d8f0edf241f6f03c9cf6c6a",
"blobs/sha256/df898601d93cec8523eff57f3ca1cf20d2cf92793ce98d0c5e9885dd2a9c53d1",
"blobs/sha256/df998f8e25976466ca0e2aef4aff971125a81762b52c5b12446151ad8a24accb",
"blobs/sha256/e1f60ff4d853e5d51dfd06c483771ff1a24cf7e175af54203b4ce3bf831214d4",
"blobs/sha256/e3cd2362e641503f07d2ce339ee172131701b1a127f19d5a32561df9cd03d375",
"blobs/sha256/e4be11be2ac9f8e5786b81aee8b31ed8a210ac8a60c8ef6ec5e16057fb6cd702",
"blobs/sha256/ea972dfc554b3236f553b8b2e34c1c46df152889bfd037bc16d63bd8ceb92bd1",
"blobs/sha256/f07a09afcd4d724fe3068ef61532517a6962269f8dff5675ca221defcb678d34",
"blobs/sha256/f0af354daeda18f18684b23520969ef6bb3de82bb267936f867b12769be9125d",
"blobs/sha256/f3a41fe51ac1d40a35d538a321c4ff1c36911ba9eec5cd39ea0c168491d7385e",
"blobs/sha256/fcb0cc52852695975c6478e1df44c074260fa1004c497e2abe54c9cabe6e5ab1"
]
}