Prhub

#43020 [Bugfix] Make CuMemAllocator free callback stream-aware

原始 PR 作者 zixi-qi 合并时间 2026-05-22 11:36 文件变更 1 提交数 2 评论 4 代码增减 +6 / -0

执行摘要

修复 CuMemAllocator 释放回调未同步流导致的 IMA

运行 DeepSeek V4 时启用 sleep mode 会出现 IMA(非法内存访问),根本原因是 pool-backed tensor 释放后 cuMemUnmap 立即执行,而之前的异步内核(如权重加载中的量化辅助 tensor 写入)尚未完成,导致竞争。PR body 提供了可复现的测试用例:在 CuMemAllocator 的 memory pool 中连续分配 tensor,触发 IMA。

此 PR 值得精读,是一个典型的“一行修复”案例,展示了 CUDA pluggable allocator 与传统 caching allocator 在延迟回收行为上的核心差异。设计决策(指定 device index 同步)也值得学习。

讨论亮点

Review 中 gemini-code-assist[bot] 建议将 torch.cuda.synchronize() 改为 torch.cuda.synchronize(data.handle[0]) 以指定设备索引,避免多 GPU 下的竞争。开发者采纳该建议并在最终提交中体现。没有未解决的分歧。

实现拆解

  1. 定位修复点:在 vllm/device_allocator/cumem.py 的 _python_free_callback 方法中,在调用 C 扩展的 unmap_and_release(通过返回 handle 触发)之前插入流同步。
  2. 同步方式:使用 torch.cuda.synchronize(data.handle[0]) 而非无参版本。data.handle[0] 存储了分配时 CUDA 设备索引,确保在多 GPU 环境中同步正确的设备。
  3. 变更影响:仅增加一行有效代码(+1 核心逻辑,其余为注释),不改变任何 API 或数据结构。释放路径增加同步开销,但避免了数据竞争导致的严重崩溃。
文件 模块 状态 重要度
vllm/device_allocator/cumem.py 设备分配器 modified 5.71

关键符号

_python_free_callback

关键源码片段

vllm/device_allocator/cumem.py core-logic

唯一变更文件,在 `_python_free_callback` 中增加 `torch.cuda.synchronize(data.handle[0])` 调用,解决 CUDA pluggable allocator 释放时与未完成内核的竞争问题。

    def _python_free_callback(self, ptr: int) -> HandleType:
        """
        Internal method to look up the allocation data
        when memory is freed in the memory pool."""
        data = self.pointer_to_data.pop(ptr)
        if data.cpu_backup_tensor is not None:
            data.cpu_backup_tensor = None
        # Drain pending kernels before the C extension's cuMemUnmap.
        # The pluggable allocator path doesn't defer reclaim like the
        # regular caching allocator, so without this, in-flight work
        # (e.g. quant helpers' transient tensors during weight loading)
        # races the unmap and surfaces as CUDA_ERROR_ILLEGAL_ADDRESS.
        # Use stream from handle to correctly synchronize multi-GPU.
        torch.cuda.synchronize(data.handle[0])
        logger.debug(
            "Freed %s bytes for %s with address %s from cumem allocator",
            data.handle[1],
            data.tag,
            ptr,
        )
        return data.handle

评论区精华

多 GPU 环境下 synchronize 应指定设备 正确性

`gemini-code-assist[bot]` 指出 `torch.cuda.synchronize()` 无参数时同步的是调用线程的当前设备,若释放的内存属于其他 GPU,竞争仍存在。建议改为 `torch.cuda.synchronize(data.handle[0])`,`data.handle[0]` 包含关联的 CUDA device index。

结论:开发者采纳建议,最终提交使用 `torch.cuda.synchronize(data.handle[0])`。 · 已解决

风险与影响

性能风险:释放路径增加 torch.cuda.synchronize 调用,可能阻塞 host 线程直到所有流上待处理内核完成。对于高频分配/释放场景(如动态 batch 内部 tensor 重建)会引入额外延迟。但这是正确性的必要代价。回归风险低:仅添加一行同步调用,不改变语义。

影响范围窄:仅修复 CuMemAllocator sleep mode 下的 IMA 问题,用户无感知。对于使用 sleep mode(主要面向 DeepSeek V4 等大型模型)的用户,消除了运行时崩溃风险。影响程度高:修复的是可能造成服务中断的严重 bug。

核心路径变更 缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论