
Eval bug: CUDA crash on tensor copy
快速结论:该报错通常发生在使用 llama.cpp 的多 GPU 推理场景(如双 RTX 5070 Ti)或 CUDA 图模式(CUDA graph)下,报错 cudaMemcpyPeerAsync 超时或 cudaGraphExecUpdateFailure。优先排查 CUDA 驱动版本(590)与 llama.cpp 的兼容性,以及较长的上下文长度(-c 160000)是否导致设备间张量拷贝超时。
问题场景
用户运行 llama-server 进行多卡(2× NVIDIA RTX 5070 Ti)推理,使用 -c 160000(长上下文)和 -ctk q8_0 -ctv q8_0(量化缓存),并在升级到 NVIDIA 驱动 590 和 CUDA 13.1 后触发。同时,运行 test-backend-ops 时也会失败,涉及 SOFT_MAX 操作以及 CUDA 图更新失败(cudaGraphExecUpdateFailure)。
报错原文
/devel/tools/llama.cpp/ggml/src/ggml-cuda/ggml-cuda.cu:97: CUDA error
CUDA error: the launch timed out and was terminated
current device: 1, in function ggml_backend_cuda_cpy_tensor_async at /devel/tools/llama.cpp/ggml/src/ggml-cuda/ggml-cuda.cu:2836
cudaMemcpyPeerAsync(dst->data, cuda_ctx_dst->device, src->data, cuda_ctx_src->device, ggml_nbytes(dst), cuda_ctx_src->stream())
除主报错外,compute-sanitizer 中还观察到:
Program hit cudaErrorGraphExecUpdateFailure (error 910) due to "the graph update was not performed because it included changes which violated constraints specific to instantiated graph update"
kernel log 中的 GPU 锁定信息:
NVRM: krcWatchdog_IMPL: RC watchdog: GPU is probably locked! Notify Timeout Seconds: 7
NVRM: Xid (PCI:0000:06:00): 8, pid=4307, name=llama-server, channel 0x00000008
原因分析
可能原因:
- CUDA 图更新冲突:当 llama.cpp 使用 CUDA graph 加速时,图捕获后的参数变化(如 tensor shape 或数据类型)可能导致
cudaGraphExecUpdateFailure(error 910),进而破坏后端状态,最终在异步张量拷贝时表现为超时。 - 多 GPU 间 Peer-to-Peer 超时:长上下文(
-c 160000)导致张量尺寸过大,cudaMemcpyPeerAsync在设备间拷贝时被 GPU watchdog 打断(从 dmesg 中可确认 watchog 主动超时)。 - 驱动/CUDA 版本变化:用户明确提到升级到驱动 590 和 CUDA 13.1 后首次出现。虽然其他用户在相同版本下未遇到问题(I’ve been using 590 with 13.1 for quite a while without issues),但驱动或 CUDA 版本的变化可能改变调度行为,与特定硬件组合(RTX 5070 Ti + 双卡)交互时暴露缺陷。
环境排查
- llama.cpp 版本:确认当前 commit 是否包含 2cd20b72ed3565ac6935911ca0d9b5d73ae70d0d。
- CUDA 驱动版本:检查当前驱动是否为 590,CUDA 工具包是否 13.1。
- 显卡型号及数量:双 NVIDIA RTX 5070 Ti,compute capability 12.0。
- 上下文长度:
-c 160000是否过大导致多 GPU 数据传输量超过限制。 - 后端启动日志:确认
ggml_cuda_init是否成功识别全部 GPU,且VMM: yes。
解决步骤
- 更新 llama.cpp 到包含特定 commit 的版本:Issue 中提及了一个可能的修复 commit:
2cd20b72ed3565ac6935911ca0d9b5d73ae70d0d。但用户指出即使包含了该 commit 问题依然复现,说明该 commit 未完全修复此问题。但仍建议确保代码为最新主分支或包含最新 CUDA 相关修复。 - 缩短上下文长度:可优先尝试将所有上下文长度参数(如
-c从 160000)降低,例如 32768 或更低,以减小单次cudaMemcpyPeerAsync的数据量,避免 GPU watchdog 超时。 - 关闭 CUDA graph:如 SDL 日志中频繁出现
cudaGraphExecUpdateFailure,可尝试在启动时关闭 CUDA Graph 优化(如果 llama.cpp 支持,例如通过环境变量GGML_CUDA_DISABLE_GRAPHS=1或在代码中关闭),避免图更新失败导致的后端不一致。 - 回滚驱动与 CUDA 版本:如果问题仅在驱动 590 + CUDA 13.1 下出现,优先回滚到已知稳定的驱动版本(例如 550)和 CUDA 12.x(如 12.4)。该步骤在 Issue 中虽然未直接给出解决方案,但用户日志明确将版本升级列为变量。
- 排查单一 GPU 模式:若条件允许,可改为单 GPU 运行(如通过
--main-gpu或--tensor-split将全部 tensor 分配到一个 GPU),确认是否与多 GPU 张量拷贝逻辑相关。 - 运行 compute-sanitizer(备选):使用
compute-sanitizer test-backend-ops检查 SOFT_MAX 等特定操作的失败是否与 CUDA 图或张量操作有关。如果 SOFT_MAX 测试始终失败,可能涉及算数逻辑问题而非单纯的超时。
验证方法
- 再次启动
llama-server,观察是否在启动后短时间内复现cudaMemcpyPeerAsync超时报错。 - 检查 dmesg 不再出现
NVRM: krcWatchdog_IMPL: RC watchdog: GPU is probably locked!条目。 - 运行
test-backend-ops确保所有测试通过(至少 CUDA 后端不报 FAIL)。



