Prhub

#35051 [XPU][Fix] Pack device-pointer tables as uint64 to avoid 64-bit address overflow

原始 PR 作者 dayanandav 合并时间 2026-09-10 10:12 文件变更 11 提交数 8 评论 8 代码增减 +346 / -23

执行摘要

修复 XPU 上设备指针表因 int64 溢出导致 Mamba 模型崩溃的问题。

根据 Issue #35047 描述,Intel XPU 的 Level Zero / SYCL USM 设备地址最高位被设置(例如 0xffff85abd4e00000)。当使用 torch.tensor() 将这些地址打包为 dtype=torch.int64 时,PyTorch 在主机端通过 long long 解包会抛出溢出错误,阻止任何内核启动。CUDA 和 HIP 设备地址保持在低位部分,因此该问题被掩盖。此 bug 阻塞了 Mamba/GDN 模型在 XPU 上的运行。

此 PR 值得精读。它解决了一个影响特定硬件平台(XPU)的关键 bug,修复方案(uint64 构建 + int64 视图)设计巧妙且影响面小。更值得关注的是其配套的测试改进工作:

  1. 引入了一种通过伪造 data_ptr() 在任意后端测试高位地址的优雅方法。
  2. 系统性地将多个测试从“仅 CUDA”扩展到“支持 XPU”,提升了测试矩阵的覆盖范围。
  3. 处理了仓库测试分类法(taxonomy)的例外情况,为厂商特定测试创建了更灵活的结构。这些改进对于维护一个多硬件后端的大型项目具有借鉴意义。
讨论亮点

核心讨论围绕测试文件的组织结构展开。审查者 mingfeima 指出:

  1. 初始版本中对 test/registered/kernels/... 路径下测试文件的注册不符合仓库的测试分类法(taxonomy),即必须位于 test/registered/<kind>/<subsystem>/ 下。
  2. 审查者要求移除一个与 PR 主题无关的 test_unified_radix_cache_unittest.py 变更,并指出 XPU CI 未注册这些测试,导致它们成为死代码。结论:作者遵循建议,将测试拆分并移动到正确位置:CPU 伪造地址测试放入 test/registered/unit/memory/,真实 XPU 设备内存测试放入 test/registered/xpu/。为支持此结构,还修改了 lint 脚本以允许厂商目录。此外,另一条评论讨论了为何需要更新 test/README.md,最终确认是为了文档化厂商目录的例外规则。

实现拆解

  1. 核心修复 - 新增 make_ptr_table 工具函数:在 python/sglang/kernels/ops/memory/ptr_table.py 中创建了一个新的通用函数。该函数接收地址列表和设备,先构建 dtype=torch.uint64 的张量(唯一能容纳完整 64 位地址的数据类型),然后通过 .view(torch.int64) 将其重新解释为有符号整数。这种‘视图转换’不移动任何比特位,因此内核侧代码可以继续使用其现有的有符号元素类型,无需任何修改。该函数设计用于处理一维地址列表或包含地址及伴随列(如步长)的二维表格。
  2. 应用修复到受影响的调用点:
    a. python/sglang/srt/mem_cache/mamba_slot_fused.py 中的 build_conv_slot_descriptor 函数:将其构建 ptr 列的代码从 to_i64(ptr) 替换为 make_ptr_table(ptr, device=device)。这修复了 ConvSlotDescriptor.ptr 字段的构建。
    b. python/sglang/kernels/ops/mamba/mamba_state_scatter_triton.py 中的 _conv_multi_build_meta 函数:通过相同的机制修复了多类型 conv-window scatter 的元数据表构建。由于该文件修改很小(仅导入和调用变更),未单独列出。

  3. 修复 MambaPool 中的设备硬编码:在 python/sglang/srt/mem_cache/memory_pool.py 中,将三处 device="cuda" 的硬编码分配替换为 device=self.device 或 device=device,使内存池分配与实际设备匹配,这是 XPU 兼容性的必要补充。

  4. 扩展测试覆盖范围以支持非 CUDA 后端:
    a. 修改了 test/registered/unit/layers/test_mamba_state_scatter_triton.py 和 test/registered/layers/mamba/test_mamba_slot_fused.py,引入 _triton_device() 辅助函数和 TRITON_DEVICES 列表,将测试条件从 torch.cuda.is_available() 改为检测任何支持 Triton 的加速器(包括 XPU)。
    b. 在上述测试中,将所有 device = "cuda" 替换为 device = DEVICE,将 torch.cuda.synchronize() 替换为 get_device_module().synchronize()。
    c. 新增 TestFusedConvWindowScatterMulti 测试类,覆盖之前没有测试的 fused_conv_window_scatter_multi 内核路径。

  5. 新增针对性的回归测试:
    a. 创建 test/registered/unit/memory/test_ptr_table.py:包含 TestMakePtrTable(测试完整地址范围)和 TestPtrTableCallSites(使用伪造的高位 data_ptr() 测试两个调用点的表构建,确保地址列正确而伴随列与真实地址构建匹配)。这些测试通过伪造 CPU 张量的 data_ptr() 在任何后端运行。
    b. 创建 test/registered/xpu/test_ptr_table.py:包含 TestPtrTableOnDeviceMemory,在真实 XPU 设备内存上测试指针表的往返。

  6. 调整测试注册和 CI 脚手架:
    a. 在修改的测试文件和 test/registered/layers/mamba/test_mamba2_mixer.py、test/registered/unit/mem_cache/test_mamba_unittest.py 中添加了 register_xpu_ci 调用,将测试注册到相应的 XPU CI 套件(如 stage-b-test-1-gpu-xpu 和 nightly-xpu-2-gpu)。
    b. 修改了 scripts/lint/check_registered_tests.py,引入了 _VENDOR_DIRS 集合,使测试文件分类器(taxonomy checker)允许 test/registered/xpu/ 等厂商目录下的测试文件通过,而不强制其符合 <kind>/<subsystem> 的结构。

文件 模块 状态 重要度
python/sglang/kernels/ops/memory/ptr_table.py 指针表工具 added 6.43
python/sglang/srt/mem_cache/mamba_slot_fused.py Mamba 槽融合 modified 6.19
test/registered/unit/memory/test_ptr_table.py 指针表单元测试 added 7.81
python/sglang/srt/mem_cache/memory_pool.py 内存池 modified 5.73
test/registered/unit/layers/test_mamba_state_scatter_triton.py Mamba 状态散射测试 modified 7.19

关键符号

make_ptr_table build_conv_slot_descriptor _conv_multi_build_meta _triton_device TestPtrTableCallSites.test_conv_multi_meta_table TestPtrTableCallSites.test_conv_slot_descriptor TestFusedConvWindowScatterMulti._run

关键源码片段

python/sglang/kernels/ops/memory/ptr_table.py infrastructure

引入核心修复函数 `make_ptr_table`,用于安全构建设备指针表。

"""Device-pointer tables for kernels that address several tensors per launch."""
​
from __future__ import annotations
​
from typing import Sequence, Union
​
import torch
​
​
def make_ptr_table(
    rows: Union[Sequence[int], Sequence[Sequence[int]]],
    device: Union[torch.device, str],
) -> torch.Tensor:
    """Pack ``data_ptr()`` values -- flat, or 2-D with companion columns such as
    strides -- into an ``int64`` table a kernel bitcasts back to pointers.
​
    Built unsigned because XPU USM addresses set the top bit, which
    ``dtype=torch.int64`` rejects while unpacking through ``long long``;
    ``view`` moves no bits, so kernels keep their signed element type.
    Values must be in ``[0, 2**64)``.
    """
    # 核心逻辑:先构建 uint64 张量(唯一能容纳完整 64 位地址的类型),
    # 然后通过 view 将其重新解释为 int64。view 不移动比特位,因此内核侧
    # 代码无需修改,继续使用其现有的有符号元素类型。
    return torch.tensor(rows, dtype=torch.uint64, device=device).view(torch.int64)
test/registered/unit/memory/test_ptr_table.py test-coverage

新增的回归测试,通过伪造高位 `data_ptr()` 在 CPU 上测试指针表和调用点,覆盖完整的地址范围。

# 测试核心:伪造一个高位地址(来自 Issue #35047),验证指针表能正确处理。
_HIGH_BASE = 0xFFFF85ABD4E00000
​
class _SpoofedPtrTensor(torch.Tensor):
    # 仅伪造 data_ptr();形状、步长、dtype 和设备保持真实。
    _spoofed_ptr = None
​
    def data_ptr(self) -> int:
        if self._spoofed_ptr is None:
            return super().data_ptr()
        return self._spoofed_ptr
​
def _spoof(t: torch.Tensor, offset: int) -> torch.Tensor:
    """创建一个 data_ptr() 返回伪造高位地址的张量子类实例。"""
    spoofed = t.as_subclass(_SpoofedPtrTensor)
    spoofed._spoofed_ptr = _HIGH_BASE + offset
    return spoofed

评论区精华

测试文件路径不符合仓库分类法(taxonomy) 设计

审查者 mingfeima 指出,`test/registered/kernels/ops/memory/test_ptr_table.py` 路径不符合注册测试必须位于 `test/registered/<kind>/<subsystem>/` 下的要求。作者回复解释了拆分策略。

结论:作者将测试拆分到正确位置:CPU 测试放入 `test/registered/unit/memory/`,XPU 设备测试放入 `test/registered/xpu/`。同时修改了 lint 脚本以允许厂商目录。 · 已解决

XPU CI 注册缺失 测试

审查者 mingfeima 在评论中要求为测试添加 `register_xpu_ci`,否则它们不会在 XPU CI 上运行,成为死代码。

结论:作者在后续提交中为所有受影响的测试文件添加了 `register_xpu_ci` 调用,将它们注册到 `stage-b-test-1-gpu-xpu` 或 `nightly-xpu-2-gpu`。 · 已解决

与 PR 主题无关的变更 other

审查者 mingfeima 要求移除对 `test_unified_radix_cache_unittest.py` 的无关修改。

结论:作者在提交 `2a56ffce` 中移除了该无关变更。 · 已解决

风险与影响

  1. 回归风险:make_ptr_table 使用 view 进行类型重解释。虽然 view 不移动比特位,但依赖于底层张量的内存布局。在 PyTorch 的常规操作下这是安全的,但理论上任何破坏张量连续性或布局的操作都可能引入问题。风险较低,因为这是标准 PyTorch 模式。
  2. 兼容性风险:此修复针对 XPU,但通过 uint64 构建然后 view 为 int64 的方式对 CUDA/HIP 也是无害的(它们的地址值不变)。因此,不会对其他后端引入回归。
  3. 测试覆盖风险:虽然新增了广泛的测试,包括伪造地址和真实设备测试,但伪造测试在 CPU 上运行,无法完全模拟 XPU 设备上内核执行时的地址空间。真实设备测试仅覆盖了 XPU。
  4. CI 失败风险:PR 在提交时经历了 CI 失败(PR Test 和 PR Test Extra 均失败),部分原因是 lint 问题(测试路径不符合分类法),部分原因可能是其他不相关的 CI 环境问题。最终通过调整解决了 lint 问题。

用户影响:直接影响使用 Intel XPU 后端运行 Mamba 或 GDN 模型的用户。修复前,这些用户会遇到立即的崩溃;修复后,模型应能正常运行。对 CUDA/HIP 用户无影响。
系统影响:修复了内存池(MambaPool)和状态散射内核中设备指针表的构建逻辑,这是 Mamba 模型推理路径的核心部分。还修复了 MambaPool 中设备硬编码的次要问题,提升了内存分配的通用性。
团队影响:引入了一个可复用的 make_ptr_table 工具函数,标准化了将来构建设备指针表的方式,有助于避免类似问题的再次发生。同时,改进的测试基础设施(支持非 CUDA 设备)使团队能更容易地为多种硬件后端维护测试。

核心路径变更 跨硬件兼容性 测试覆盖依赖伪造数据

关联 Issue

#35047 [Bug] Triton device-pointer tables use int64 and overflow on Intel XPU USM addresses

完整报告

参与讨论