CUDA racecheck、共享内存阵列和cudaDeviceSynchronize()

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的racecheck工具,可在cuda 5.0中找到(
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

  • 让我吃惊的第一件事是线程ID。当我第一次遇到错误时,每个块包含32个线程(ID 0到31)。那么为什么线程id 32有问题呢?我甚至在
    threadIdx.x
    上添加了一个额外的检查,但这并没有改变什么
  • 我使用共享内存作为临时缓冲区,每个线程处理多维数组中自己的参数,例如
    \uuuuuu shared\uuuuuu float arr[SIZE\u 1][SIZE\u 2][NB u THREADS\u PER\u BLOCK]
    。我真的不明白为什么会有竞争条件,因为每个线程都处理自己的共享内存部分
  • 将网格大小从64个块减少到32个块似乎可以解决这个问题(每个块有32个线程)。我不明白为什么
  • 为了了解发生了什么,我用一些更简单的内核进行了测试。 让我向您展示一个内核示例,它会创建这种错误。基本上,这个内核使用
    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?!)和错误
    ======错误:在块(57,0,0)中的共享0x6处检测到潜在WAW危险:
    =======在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。但是,我再试了一次