Skip to content

fix(layout): validate SF tensors are CUDA; add MXFP4 (1, 32) SF transform test - #407

Open
qqtang-code wants to merge 2 commits into
deepseek-ai:mainfrom
qqtang-code:feat/sf-layout-device-guard
Open

fix(layout): validate SF tensors are CUDA; add MXFP4 (1, 32) SF transform test#407
qqtang-code wants to merge 2 commits into
deepseek-ai:mainfrom
qqtang-code:feat/sf-layout-device-guard

Conversation

@qqtang-code

Copy link
Copy Markdown

Summary

Two small hardening changes for the scale-factor (SF) layout APIs, shared with the SGLang fork (sgl-project#75):

  1. preprocess_sf device validation — the layout-transform functions feed .data_ptr() straight into JIT-launched device kernels (or into the torch fallback). A CPU tensor reaches the kernel launch with host pointers and segfaults the process (illegal device address) instead of failing cleanly. preprocess_sf now asserts sf.is_cuda() up front, covering both get_mn_major_tma_aligned_tensor and get_mn_major_tma_aligned_packed_ue8m0_tensor.

  2. Regression test for the MXFP4 (1, 32) recipe — mirrors the exact call SGLang makes during Kimi-K3 / DeepSeek-V4 weight loading (transform_sf_into_required_layout(sf, mn=..., k=..., recipe=(1, 32), num_groups=..., disable_ue8m0_cast=False)), asserting the packed-UE8M0 output matches the torch reference (values, shape, strides). Skipped on SM90 (which uses the (1, 128) FP32 TMA layout) and on SM120 (upstream main has no arch-12 branch; SM120 support lives on the sgl-project fork).

Context

The device assert turns a silent process crash (CPU tensor into a device kernel) into a clean assertion error. The regression test locks in the MXFP4 weight-prep path that SGLang's MoE runner relies on (validated end-to-end on 4× RTX 6000D / SM120 with the sgl fork: sgl-project/sglang#34827).

preprocess_sf feeds .data_ptr() straight into device kernels; a CPU
tensor segfaults the process at launch (illegal device address) instead
of failing cleanly, so assert the device up front.

Also add a regression test covering transform_sf_into_required_layout
with the MXFP4 (1, 32) recipe used by SGLang's Kimi-K3 / DeepSeek-V4
weight prep (packed-UE8M0 output). SM90 uses a different (1, 128) FP32
layout and upstream main has no SM120 branch (SM120 support lives on the
sgl-project fork), so the test skips both.
Comment thread tests/test_layout.py
# exists on SM100 (SM90 uses the (1, 128) FP32 TMA layout; SM120 support
# lives on the sgl-project fork, see sgl-project/DeepGEMM).
if get_arch_major() in (9, 12):
print(' > Skipped ((1, 32) UE8M0 layout transform is SM100-only upstream)')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion: 跳过分支在打印 'Testing transform_sf_into_required_layout ...' 标题之前就输出 ' > Skipped ...',与同文件 test_k_grouped_psum_sf_layout_kernels(先打印标题、再输出跳过信息)的风格不一致。建议将 print('Testing ...') 移到跳过判断之前以保持日志风格统一;纯输出格式问题,不阻塞合入。

🤖 v5

// `.data_ptr()` on the JIT launch path); a CPU tensor would crash the
// process at launch time (illegal device address) instead of failing
// cleanly. Validate the device up front.
DG_HOST_ASSERT(sf.is_cuda());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion: 新增的 DG_HOST_ASSERT(sf.is_cuda()) 与下一行 get_shape<3>(batched_sf) 中已有的 DG_HOST_ASSERT(t.is_cuda())(csrc/utils/layout.hpp)重复:preprocess_sf 的两个调用方在把 data_ptr 传给 JIT 内核之前都会先经过 get_shape<3>,CPU 张量在那里就已经抛出 DGException,并不会真的以主机指针进入内核导致进程 segfault。因此注释中 CPU 张量会崩溃进程的说法不准确,该断言属于冗余,仅让失败更早、报错更明确。建议修正注释表述,或直接删除此冗余断言。

🤖 v4p

@ds-review-bot

Copy link
Copy Markdown
Collaborator

🤖 ds-review-bot Code Review

v6

未发现会破坏现有功能或测试的缺陷。CUDA 设备校验位置合理,新增测试与当前 SM100 实现及关联仓库契约一致。

v5

本 MR 的两处变更均已正确落地且与对端 MR(sgl-project#75)契约一致,可以合入。1) csrc/jit_kernels/impls/smxx_layout.hpp 在 preprocess_sf 中新增 DG_HOST_ASSERT(sf.is_cuda()):位置正确(在 dim/dtype 检查之后、任何 .data_ptr()/设备 kernel 使用之前),且 preprocess_sf 是 get_mn_major_tma_aligned_tensor 与 get_mn_major_tma_aligned_packed_ue8m0_tensor 的唯一入口,torch 回退实现 get_mn_major_tma_aligned_packed_ue8m0_tensor_torch 只从后者内部(L206/L231)可达,因此也被断言覆盖,把 CPU 张量导致的进程级 segfault(illegal device address)变为干净的断言错误。2) tests/test_layout.py 新增 MXFP4 (1, 32) recipe 回归测试:调用契约与 pybind 签名(csrc/apis/layout.hpp L126-131)匹配,传 2 元组 recipe 且不传 is_sfa 满足 DG_HOST_ASSERT(not is_sfa.has_value())(L31);0.5 (0x3f000000) 是符号/尾数为零的合法 UE8M0 载荷,pack kernel 断言不会误触发;对值/shape/stride 均与 torch 参考实现 get_mn_major_tma_aligned_packed_ue8m0_tensor_torch_impl 比对。架构跳过逻辑与上游 layout.hpp 门控一致:(FP32, gran_k==32) 分支上游仅 arch_major==10(L49),SM90 走 (1,128) FP32 TMA 路径、SM120 会落到 DG_HOST_UNREACHABLE,故跳过 (9, 12) 必要且正确。跨仓一致性核对:C++ hunk 在两仓逐字节相同;测试差异为有意为之且与各自代码匹配——对端 fork 的 layout.hpp L49/L57 为 'arch_major == 10 or arch_major == 12' 故其测试只跳过 SM90,上游无 arch-12 分支故本 MR 额外跳过 SM120,测试注释也如实说明 SM120 支持位于 sgl fork;两侧测试的调用参数、参考实现、断言完全一致,未发现接口/协议/数据格式/调用约定不一致。仅有一处非阻塞的输出格式小建议(见 comment)。

v4p

本 MR 为 SF 布局 API 增加设备校验,并新增 MXFP4 (1, 32) recipe 的回归测试,覆盖 SGLang 权重加载时调用 transform_sf_into_required_layout 的路径。整体上变更安全、测试逻辑正确(形状、stride 与值与 torch 参考实现一致,SM90/SM120 的跳过条件合理),跨仓与 sgl-project fork 的契约一致。唯一需要注意的是新增的 CUDA 断言与既有 get_shape 中的设备校验重复,注释中对崩溃原因的描述并不准确。

Files reviewed: 2
配对 MR checkout: 1
⚠️ 关联仓库拉取失败: sgl-project/sglang#34827
Issues found: 🔵 2 suggestion
Inline comments posted: 2

- preprocess_sf: clarify that the device check is an early explicit
  validation at the SF-layout entry (get_shape re-validates downstream),
  rather than claiming CPU tensors would otherwise reach kernel launch.
- test: print the section title before the arch skip for log-style
  consistency with test_k_grouped_psum_sf_layout_kernels.
@qqtang-code

Copy link
Copy Markdown
Author

Thanks for the thorough review — both suggestions addressed in 73ccae7:

  1. preprocess_sf comment — you're right that get_shape (csrc/utils/layout.hpp) already asserts t.is_cuda() upstream, so a CPU tensor never actually reaches a kernel launch here. Kept the assert (it makes the SF-layout entry points fail earlier and more explicitly) but corrected the comment to say exactly that: early validation at the entry point, with get_shape re-validating downstream. Worth noting the sgl-project fork's get_shape dropped the is_cuda check during its SM120 work, so there this assert is the primary device guard — keeping the C++ hunk byte-identical across both repos (fix(layout): validate SF tensors are CUDA; add MXFP4 (1, 32) SF transform test sgl-project/DeepGEMM#75) is intentional.

  2. Test print order — moved the section title before the arch-skip, matching test_k_grouped_psum_sf_layout_kernels. Applied the same style to the fork's copy of the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants