CUDA racecheck、共享内存阵列和cudaDeviceSynchronize()
我最近发现了cuda memcheck的racecheck工具,可在cuda 5.0中找到(CUDA racecheck、共享内存阵列和cudaDeviceSynchronize(),cuda,race-condition,memcheck,Cuda,Race Condition,Memcheck,我最近发现了cuda memcheck的racecheck工具,可在cuda 5.0中找到(cuda memcheck--tool racecheck,请参阅)。此工具可以检测CUDA内核中共享内存的竞争条件 在调试模式下,此工具不会检测到任何东西,这显然是正常的。然而,在释放模式(-O3)中,我会根据问题的参数得到错误 下面是一个错误示例(第22行共享内存初始化,第119行分配): ======错误:在块(35,0,0)中的共享0x0处检测到潜在WAW危险: =======在0x0000089
cuda memcheck--tool racecheck
,请参阅)。此工具可以检测CUDA内核中共享内存的竞争条件
在调试模式下,此工具不会检测到任何东西,这显然是正常的。然而,在释放模式(-O3)中,我会根据问题的参数得到错误
下面是一个错误示例(第22行共享内存初始化,第119行分配):
======错误:在块(35,0,0)中的共享0x0处检测到潜在WAW危险:
=======在0x00000890处写入线程(32,0,0)…h:119:void kernel_test3(数据*)
=======在0x00000048处写入线程(0,0,0)…h:22:void kernel_test3(Data*)=======当前值:13,传入值:0
threadIdx.x
上添加了一个额外的检查,但这并没有改变什么\uuuuuu shared\uuuuuu float arr[SIZE\u 1][SIZE\u 2][NB u THREADS\u PER\u BLOCK]
。我真的不明白为什么会有竞争条件,因为每个线程都处理自己的共享内存部分SIZE\ux*SIZE\uy*NTHREADS*sizeof(float)
B的共享内存,我可以在每个SM中使用48KB的共享内存
测试.cu
template <unsigned int NTHREADS>
__global__ void kernel_test()
{
const int SIZE_X = 4;
const int SIZE_Y = 4;
__shared__ float tmp[SIZE_X][SIZE_Y][NTHREADS];
for (unsigned int i = 0; i < SIZE_X; i++)
for (unsigned int j = 0; j < SIZE_Y; j++)
tmp[i][j][threadIdx.x] = threadIdx.x;
}
int main()
{
const unsigned int NTHREADS = 32;
//kernel_test<NTHREADS><<<32, NTHREADS>>>(); // ---> works fine
kernel_test<NTHREADS><<<64, NTHREADS>>>();
cudaDeviceSynchronize(); // ---> gives racecheck errors if NBLOCKS > 32
}
模板
__全局无效内核测试()
{
常数int SIZE_X=4;
常数int SIZE_Y=4;
__共享浮动tmp[SIZE\u X][SIZE\u Y][NTHREADS];
for(无符号整数i=0;i工作正常
内核_测试();
cudaDeviceSynchronize();//-->如果NBLOCKS>32,则提供racecheck错误
}
汇编:
nvcc test.cu--ptxas选项=-v-o测试
如果我们运行内核:
cuda memcheck——刀具轨迹检查测试
kernel_test()代码>:32个块,32个线程=>不会导致任何明显的racecheck错误
kernel_test()代码>:64个块,32个线程=>导致WAW危险(threadId.x=32?!)和错误
=======在0x00000048处写入线程(0,0,0)…h:403:void kernel\u test(void)
=======在0x00000048处写入线程(1,0,0)…h:403:void kernel\u test(void)
=======当前值:0,传入值:128 ======信息:(正在写入相同数据)在块(47,0,0)中的共享0x0处检测到潜在WAW危险:
=======在0x00000048处写入线程(32,0,0)…h:403:void kernel\u test(void)
=======在0x00000048处写入线程(0,0,0)…h:403:void kernel\u test(void)
=======当前值:0,传入值:0 那么我在这里错过了什么?我在共享内存方面做错了什么吗?(这方面我还是个初学者) **更新**
问题似乎来自
cudaDeviceSynchronize()
当NBLOCKS>32
时。为什么会发生这种情况?首先,cudaDeviceSynchronize()不是原因;内核是原因,但它是一个异步调用,因此在调用cudaDeviceSynchronize()时会捕获错误
至于内核,您的共享内存的大小为X*size*Y*NTHREADS(在本例中转换为每个块512个元素)。在嵌套循环中,使用[i*blockDim.x*SIZE_Y+j*blockDim.x+threadIdx.x]对其进行索引——这就是问题所在
更具体地说,i和j值的范围是[0,4],threadIdx.x的范围是[0,32],SIZE_{x|Y}的值是4。
当blockDim.x为64时,循环中使用的最大索引将为991(从3*64*4+3*64+31)。当blockDim.x为32时,最大索引将为511
根据您的代码,每当Nblock超过NTHREADS时,您应该会得到错误
注意:我最初将此发布到了这显然是NVIDIA Linux驱动程序中的一个bug。该bug在313.18发布后消失了。Hi BenC,你能发布一个完整的重新编写案例吗?另外,你在哪个GPU上运行此程序,CUDA驱动程序和工具包版本是什么?Hi Vyas,通常我提供的最小代码足以重新编写请说明问题。您缺少什么信息?我有一个Geforce GT 650M、CUDA 5.0、CC 3.0和驱动程序304.64。Hi BenC,您能发布整个主机代码、设备代码以及您使用的确切生成行吗?这使得重现问题更容易。@marina.k:NTHREADS是每个块的线程数,这里是32。@Vyas:我更新了我的帖子,我发现这实际上是由于
cudaDeviceSynchronize()
对于特定数量的块造成的。我相应地更新了代码。这确实是一个错误,因为我粘贴了(错误的)重新编译代码。但修复程序仍然存在问题。@BenC well这有点复杂。您是如何编译代码的?在SM 1.x或3.5中不支持racecheck工具。我使用GT 650M,因此使用SM 3.0。但是,我再试了一次