coredump调试cuda kernel

coredump调试cuda kernel
gogongxtcoredump使用方式
首先新建test_coredump.py脚本,脚本内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import os
import socket
import torch
from torch.utils.cpp_extension import load_inline
# 提前获取 hostname 和 pid,方便打印出触发 coredump 的准确命令
hostname = socket.gethostname()
pid = os.getpid()
pipe_path = f"/tmp/cuda_pipe_{hostname}_{pid}"
dump_path = f"/tmp/cuda_coredump_full_{hostname}_{pid}"
cuda_source = """
__global__ void hang_kernel(int* dummy) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx == 0) {
volatile int counter = 0;
// 死循环,让 GPU 彻底卡在这里
while(true) {
counter++; // 使用 volatile 变量防止循环被 NVCC 优化掉
}
}
}
void run_hang_kernel(torch::Tensor dummy) {
hang_kernel<<<1, 1>>>(dummy.data_ptr<int>());
}
"""
cpp_source = """
void run_hang_kernel(torch::Tensor dummy);
"""
print("=> 正在编译 CUDA Kernel (可能需要几秒钟)...")
module = load_inline(
name='cuda_hang_ext',
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=['run_hang_kernel'],
verbose=False,
)
print("\n=> 编译完成!")
print(f"=> 当前 Hostname: {hostname}")
print(f"=> 当前 PID: {pid}")
print("\n" + "="*60)
print("请保留当前终端卡住,打开另一个新终端,执行以下命令触发 coredump:")
print(f"echo 1 > {pipe_path}")
print("="*60 + "\n")
# 分配一个 dummy tensor,触发 CUDA 上下文初始化
dummy_tensor = torch.zeros(1, dtype=torch.int32, device='cuda')
# 启动 kernel
module.run_hang_kernel(dummy_tensor)
print("=> Kernel 已下发!正在等待 torch.cuda.synchronize() ... (预期会永远卡在此处)")
torch.cuda.synchronize()然后执行下面的命令
1
2
3
4
5
6
7
export CUDA_ENABLE_USER_TRIGGERED_COREDUMP=1
export CUDA_COREDUMP_PIPE="/tmp/cuda_pipe_%h_%p"
export CUDA_COREDUMP_FILE="/tmp/cuda_coredump_full_%h_%p"
export CUDA_COREDUMP_SHOW_PROGRESS=1
export CUDA_COREDUMP_GENERATION_FLAGS='skip_global_memory,skip_shared_memory,skip_local_memory,skip_constbank_memory'
python test_coredump.py这里的CUDA_COREDUMP_GENERATION_FLAGS参数简单解释一下:
- skip_global_memory:跳过全局显存(Global Memory)。如果不加这个参数,每次触发 coredump 都会把完整显存的数据全部通过 PCIe 读回并写入磁盘,这会瞬间写爆磁盘,期间进程完全卡死。加上这个 flag 后,直接跳过显存拷贝,只抓取指令和状态。
- skip_shared_memory: 跳过共享内存(Shared Memory,SRAM)。虽然 Shared Memory 不大,但在排查单纯的“卡死”或死锁问题时,我们通常只关心指令跑到哪了,不需要看 Shared Memory 里的矩阵块。
- skip_local_memory & skip_constbank_memory: 跳过线程局部内存和常量内存。同样是为了极限压缩体积和提升 dump 速度。
执行后可以看到日志:
1
2
3
4
============================================================
请保留当前终端卡住,打开另一个新终端,执行以下命令触发 coredump:
echo 1 > /tmp/cuda_pipe_yourhostname_12345
============================================================然后我们就可以出发coredump了:
1
echo 1 > /tmp/cuda_pipe_<your_hostname>_<pid>预期结果
Coredump 文件生成:你应该能在 /tmp/ 目录下找到生成的
cudacoredump_full
进度显示:因为你设置了 CUDA_COREDUMP_SHOW_PROGRESS=1,在运行脚本的第一个终端中,你应该能看到 stderr 打印出 coredump 写入的进度信息。
使用cuda-gdb查看coredump信息:
1
cuda-gdb --batch -ex "target cudacore cuda_coredump_full_<hostname>_<pid>" -ex "info cuda kernels" -ex "bt"就可以看到具体卡在哪个kernel,状态是什么了,例如打印信息如下:
1
2
3
4
5
6
7
8
9
10
11
Opening GPU coredump: /tmp/cuda_coredump_full_ml-h800-ser029.qsh01_46280
[Current focus set to CUDA kernel 0, grid 2, block (0,0,0), thread (0,0,0), device 0, sm 124, warp 1, lane 0]
#0 0x00007fa55dba0580 in hang_kernel(int*)<<<(1,1,1),(1,1,1)>>> ()
Kernel Parent Dev Grid Status SMs Mask GridDim BlockDim Invocation
* 0 - 0 2 Active 0x0010000000000000000000000000000000 (1,1,1) (1,1,1) hang_kernel()
#0 0x00007fa55dba0580 in hang_kernel(int*)<<<(1,1,1),(1,1,1)>>> () 评论
匿名评论隐私政策




