Prhub

#51770 [XPU] Fix UVA weight offloading (non-pinned-tensor views and static Triton launcher)

原始 PR 作者 chaojun-zhang 合并时间 2026-08-11 21:48 文件变更 2 提交数 2 评论 2 代码增减 +33 / -1

执行摘要

修复 XPU 权重卸载两处启动崩溃并回退静态 launcher

PR body 明确说明 --cpu-offload-gb 在 XPU 上无法启动:量化 checkpoint 常包含零元素 tensor,pin_memory() 对空 tensor 是 no-op,且 VLLM_WEIGHT_OFFLOADING_DISABLE_PIN_MEMORY=1 会直接触发 “CPU tensor must be pinned” 断言;修复断言后,UVA 卸载的 host USM 指针又会被 Inductor 静态 launcher 以 “Pointer argument doesn't reference XPU device memory” 拒绝。两个问题都阻塞了 XPU 上的权重卸载路径。

值得精读,尤其适合关注 XPU 平台适配和跨层 workaround 写法的工程师。要点包括:如何用 setdefault 保留用户配置优先级、如何在不改内核的前提下处理空 tensor 与非 pinned 输入、以及如何用注释锚定上游修复 PR 来管理临时 workaround 的生命周期。

讨论亮点

该 PR 没有实质性的技术 review 讨论:claude[bot] 自动提示 fork 仓库禁用自动 review;jikunshang 直接批准(APPROVED),随后触发 Buildkite CI。技术权衡主要体现在 PR body 和提交信息中——两处修复都被明确标注为临时 workaround,并给出了移除条件(上游 kernel 与 torch 修复发布)。

实现拆解

变更入口是 XPUPlatform.check_and_update_config()vllm/platforms/xpu.py)与 get_accelerator_view_from_cpu_tensor()vllm/utils/torch_utils.py),共两步:

  1. 放宽 UVA 视图创建的输入约束(vllm/utils/torch_utils.py):删除 assert cpu_tensor.is_pinned() 断言。对 numel() == 0 的空 tensor 直接返回 torch.empty(..., device="xpu"),避免走 pin 路径;对非 pinned tensor,先取 contiguous() 再创建 pinned 副本并 copy_,最后基于副本调用 torch.ops._C.get_xpu_view_from_cpu_tensor(),让视图的分配器持有 pinned 缓冲的生命周期。该行为与 CUDA 视图内核保持一致。
  2. 检测 UVA 卸载并回退 Inductor 静态 Triton launcher(vllm/platforms/xpu.py):在 check_and_update_config() 中计算 uva_offloading = offload_backend == "uva",或 autoprefetch.offload_group_size == 0uva.cpu_offload_gb > 0;当 UVA 卸载启用、未设置 VLLM_WEIGHT_OFFLOADING_DISABLE_UVA 且编译模式非 NONE 时,通过 compilation_config.inductor_compile_config.setdefault("use_static_cuda_launcher", False) 回退到普通 Triton launcher,setdefault 确保用户显式配置优先。
  3. workaround 生命周期管理:两处代码都内联注释标记了对应的上游修复 PR(vllm-xpu-kernels#513pytorch#188240),便于后续清除。
  4. 测试配套:本次没有新增自动化测试,PR body 仅提供了手动 E2E 验证(JackFram/llama-160m + torch.compile + cpu_offload_gb=0.1),修复前报 AssertionError,修复后正常输出 ' Paris...'
文件 模块 状态 重要度
vllm/platforms/xpu.py 平台层 modified 6.2
vllm/utils/torch_utils.py 工具层 modified 5.51

关键符号

get_accelerator_view_from_cpu_tensor check_and_update_config

关键源码片段

vllm/platforms/xpu.py core-logic

在 XPU 平台配置入口检测 UVA 权重卸载,并自动禁用 Inductor 静态 Triton launcher,解决 host USM 指针被拒绝导致的启动崩溃 / 编译失败。

# UVA 卸载的权重是 host USM 分配,Inductor 的静态 Triton launcher 会拒绝
# 这类指针(报错 "Pointer argument doesn't reference XPU device memory")。
# 这里检测 UVA 卸载是否生效,并回退到 Triton 自己的 launcher。
# 等含 pytorch/pytorch#188240 的 torch 发布后,可移除该 workaround。
offload_config = vllm_config.offload_config
uva_offloading = offload_config.offload_backend == "uva" or (
    offload_config.offload_backend == "auto"
    and offload_config.prefetch.offload_group_size == 0
    and offload_config.uva.cpu_offload_gb > 0
)
if (
    uva_offloading
    and not envs.VLLM_WEIGHT_OFFLOADING_DISABLE_UVA
    and compilation_config.mode != CompilationMode.NONE
):
    # setdefault 保证用户显式传入的配置优先,不被平台默认值覆盖。
    compilation_config.inductor_compile_config.setdefault(
        "use_static_cuda_launcher", False
    )
    logger.info_once(
        "Disabling Inductor's static Triton launcher because UVA "
        "weight offloading is enabled."
    )
vllm/utils/torch_utils.py core-logic

修改 UVA 视图创建工具,处理空 tensor 与非 pinned CPU tensor,避免量化 checkpoint 或禁用 pin 内存时的断言崩溃。

def get_accelerator_view_from_cpu_tensor(cpu_tensor: torch.Tensor) -> torch.Tensor:
    """
    Get an accelerator view of a CPU tensor using Unified Virtual Addressing (UVA).
    """
    from vllm.platforms import current_platform
​
    if current_platform.is_xpu():
        # workaround:XPU view kernel 要求 pinned 输入,但 pin_memory() 对空
        # tensor 是 no-op,且 pin 可能被 VLLM_WEIGHT_OFFLOADING_DISABLE_PIN_MEMORY 关闭。
        # 上游修复见 vllm-xpu-kernels#513,发布后可移除以下两个分支。
        if cpu_tensor.numel() == 0:
            # 空 tensor 无实际数据,直接返回空 XPU 张量,避免走 pin 路径。
            return torch.empty(cpu_tensor.shape, dtype=cpu_tensor.dtype, device="xpu")
        if not cpu_tensor.is_pinned():
            # 先复制到 contiguous 的 pinned 缓冲,再基于该缓冲创建 UVA view,
            # 保证 view 的底层分配器持有 pinned 内存、不会提前释放。
            contiguous_cpu = cpu_tensor.contiguous()
            pinned = torch.empty_like(contiguous_cpu, pin_memory=True)
            pinned.copy_(contiguous_cpu)
            cpu_tensor = pinned
        return torch.ops._C.get_xpu_view_from_cpu_tensor(cpu_tensor)
    elif current_platform.is_cuda_alike():
        return torch.ops._C.get_cuda_view_from_cpu_tensor(cpu_tensor)
    else:
        raise ValueError(
            f"`get_accelerator_view_from_cpu_tensor` is currently "
            f"not supported in: {current_platform.device_name}"
        )

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  1. 空 tensor 分支改变语义:vllm/utils/torch_utils.py 对空 tensor 返回独立的 torch.empty(...) 而不是 UVA 视图,若调用方依赖与原始 CPU 缓冲的地址映射关系,可能会产生不一致;但空 tensor 无数据,实际影响通常可忽略(材料未提供调用方细节,存在不确定性)。
  2. 非 pinned 输入的额外拷贝:contiguous() + pin_memory copy 会引入一次完整拷贝,在 CPU offload 大量权重时会增加启动时间和峰值内存(pinned 缓冲)。
  3. 静态 launcher 关闭的影响:vllm/platforms/xpu.py 在 UVA 卸载启用且未显式配置时,会全局关闭 use_static_cuda_launcher,可能降低 torch.compile 内核的启动性能;该改动通过 setdefault 允许用户覆盖,但默认值对 UVA 用户是性能回退。
  4. workaround 依赖上游版本:若维护者在 vllm-xpu-kernels#513pytorch#188240 尚未进入发布版本时移除 workaround,会重新引入崩溃;反之若长期保留,可能掩盖上游新行为。
  5. 新引用符号的不确定性:xpu.py 依赖 envs.VLLM_WEIGHT_OFFLOADING_DISABLE_UVAoffload_config.prefetchoffload_config.uva 属性,材料未展示这些定义,若属性不存在会抛 AttributeError(通常应已存在,但值得确认)。

影响范围集中在 Intel XPU + --cpu-offload-gb + torch.compile 的用户路径,修复后权重卸载可以正常启动并产出正确结果;对 CUDA/ROCm 等其他平台无影响(get_accelerator_view_from_cpu_tensor 的 XPU 分支仅在 current_platform.is_xpu() 时走新逻辑)。对团队而言,两处 workaround 注释点明了上游依赖跟踪项,后续需要在上游发布后清理。整体影响中等偏低。

缺少自动化测试 workaround 依赖上游版本 torch.compile 性能回退

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论