我的问题是:CUDA硬件是否有故障,或者可能有其他解释?我有一个内核,它已经使用了大约一年,没有修改。最近,我开始以不规则的间隔出现分割错误,即它可以被复制,有时在几分钟后,有时在执行数小时后。这导致了该程序的最低版本仍然再现了segfault。以及从stackoverflow的帖子中学到的很多东西。
当在重复bash循环中运行时,cuda memcheck最终将报告:
========= Invalid __global__ read of size 4
========= at 0x000048f0 in SegFault.cu:157:SegFault( float* )
========= by thread (128,0,0) in block (3706,0,0)
========= Address 0x003400e8 is out of bounds
通常导致指针操作错误的罪魁祸首被排除在外。另一条线索是非法寻址在代码中的位置不一致;对于全局数组的任何索引,在整个内核中,这种情况都是不规则发生的。
在我的问题中,最有可能的解释是错误代码。让我相信硬件有故障的原因来自cuda gdb:
cuda-gdb ./SegFaultTest
(cuda-gdb) set cuda memcheck on
(cuda-gdb) run
Illegal access to address (@global)0x245684 detected.
Program received signal CUDA_EXCEPTION_1, Lane Illegal Address.
[Switching focus to CUDA kernel 0, grid 1, block (5537,0,0), thread (0,0,0), device 0, sm 22, warp 28, lane 0]
0x00000000004f1ff8 in kernel( float * @global )<<<(33480,1,1),(512,1,1)>>> ( c=0x250000 ) at SegFault.cu:37
37 c[ix] += share_c[0];
(cuda-gdb) print &c[ix]
$2 = (@global float *) 0x255684
索引"ix"为:
int ix = blockIdx.x + blockIdx.y*gridDim.x;
并且在实例化后不进行修改。实际上,0x245684
低于c=0x250000
的起始地址。然而,当我查询print &c[ix]
时,它返回0x255684
,这是这个数组可以接受的地址。再现需要执行10-50次才能再次弹出,但非法地址总是与print &c[ix]
返回的地址相差一位0x010000
我无法解释错误消息和打印之间的地址差异。再加上一个比特的差异,我怀疑硬件有故障。FWIW、0x010000
等于该特斯拉C1060的最大电网尺寸。
最后,我今天用一个新的型号替换了CUDA卡。在执行了100次死刑之后,我一直无法再现。
如果启用memcheck的cuda gdb报告非法地址访问,如:
Illegal access to address (@global)0x245684 detected.
Program received signal CUDA_EXCEPTION_1, Lane Illegal Address.
[Switching focus to CUDA kernel 0, grid 1, block (5537,0,0), thread (0,0,0), device 0, sm 22, warp 28, lane 0]
0x00000000004f1ff8 in kernel( float * @global )<<<(33480,1,1),(512,1,1)>>> ( c=0x250000 ) at SegFault.cu:37
37 c[ix] += share_c[0];
查询该地址会返回不同的值:
(cuda-gdb) print &c[ix]
$2 = (@global float *) 0x255684
然后硬件坏了。