【问题标题】:CUDA atomic function usage with volatile shared memory使用易失性共享内存的 CUDA 原子函数
【发布时间】:2013-04-04 21:12:39
【问题描述】:

我有一个 CUDA 内核,它需要在 volatile 共享整数内存上使用原子函数。但是,当我尝试将共享内存声明为 volatile 并在原子函数中使用它时,我收到一条错误消息。

下面是一些重现错误的极简代码。请注意,下面的内核什么都不做,并且严重滥用了为什么您想将共享内存声明为易失性(甚至根本不使用共享内存)。但它确实重现了错误。

代码在共享内存上使用原子函数,因此,要运行它,您可能需要使用“arch12”或更高版本进行编译(在 Visual Studio 2010 中,右键单击您的项目并转到“属性 -> 配置属性 - > CUDA C/C++ -> Device”并在“Code Generation”行输入“compute_12,sm_12”)。否则代码应按原样编译。

#include <cstdlib>
#include <cuda_runtime.h>

static int const X_THRDS_PER_BLK = 32;
static int const Y_THRDS_PER_BLK = 8;

__global__ void KernelWithSharedMemoryAndAtomicFunction(int * d_array, int numTotX, int numTotY)
{
              __shared__ int s_blk[Y_THRDS_PER_BLK][X_THRDS_PER_BLK]; // compiles
   //volatile __shared__ int s_blk[Y_THRDS_PER_BLK][X_THRDS_PER_BLK]; // will not compile

   int tx = threadIdx.x;
   int ty = threadIdx.y;

   int mx = blockIdx.x*blockDim.x + threadIdx.x;
   int my = blockIdx.y*blockDim.y + threadIdx.y;
   int mi = my*numTotX + mx;

   if (mx < numTotX && my < numTotY)
   {
      s_blk[ty][tx] = d_array[mi];

      __syncthreads();

      atomicMin(&s_blk[ty][tx], 4); // will compile with volatile shared memory only if this line is commented out

      __syncthreads();

      d_array[mi] = s_blk[ty][tx];
   }
}

int main(void)
{
   // Declare and initialize some array on host
   int const NUM_TOT_X = 4*X_THRDS_PER_BLK;
   int const NUM_TOT_Y = 6*Y_THRDS_PER_BLK;

   int * h_array = (int *)malloc(NUM_TOT_X*NUM_TOT_Y*sizeof(int));

   for (int i = 0; i < NUM_TOT_X*NUM_TOT_Y; ++i) h_array[i] = i;

   // Copy array to device
   int * d_array;
   cudaMalloc((void **)&d_array, NUM_TOT_X*NUM_TOT_Y*sizeof(int));

   cudaMemcpy(d_array, h_array, NUM_TOT_X*NUM_TOT_Y*sizeof(int), cudaMemcpyHostToDevice);

   // Declare block and thread variables
   dim3 thdsPerBlk;
   dim3 blks;

   thdsPerBlk.x = X_THRDS_PER_BLK;
   thdsPerBlk.y = Y_THRDS_PER_BLK;
   thdsPerBlk.z = 1;

   blks.x = (NUM_TOT_X + X_THRDS_PER_BLK - 1)/X_THRDS_PER_BLK;
   blks.y = (NUM_TOT_Y + Y_THRDS_PER_BLK - 1)/Y_THRDS_PER_BLK;
   blks.z = 1;

   // Run kernel
   KernelWithSharedMemoryAndAtomicFunction<<<blks, thdsPerBlk>>>(d_array, NUM_TOT_X, NUM_TOT_Y);

   // Cleanup
   free    (h_array);
   cudaFree(d_array);

   return 0;
}

无论如何,如果您注释掉内核顶部的“s_blk”声明并取消注释紧随其后的注释掉的声明,那么您应该得到以下错误:

error : no instance of overloaded function "atomicMin" matches the argument list

我不明白为什么将共享内存声明为 volatile 会影响其类型,因为(我认为)此错误消息表明,也不明白为什么它不能与原子操作一起使用。

谁能提供任何见解?

谢谢,

亚伦

【问题讨论】:

  • 作为一种解决方法,您可以在原子调用中对指针进行类型转换 (int *)。原子具有将位置视为易失性的效果。
  • talonmies,感谢您指出该链接。不知怎的,我自己没有找到它...

标签: cuda atomic shared volatile


【解决方案1】:

只需替换
atomicMin(&amp;s_blk[ty][tx], 4);

atomicMin((int *)&amp;s_blk[ty][tx], 4);.

它对&amp;s_blk[ty][tx] 进行类型转换,因此它与atomicMin(..) 的参数相匹配。

【讨论】:

  • 是的,这行得通。谢谢你。我想我更想知道这样的演员阵容是否是解决这个问题的预期方法。对我来说,原子需要这样的解决方法似乎很奇怪。但是 talonmies 指向我的链接似乎也同意。
  • @Aaron 欢迎您。正如罗伯特已经提到的那样,指针的目标位置被视为无论如何都是易变的,因此没有理由担心,但我也不知道这种“解决方法”的原因。
猜你喜欢
  • 2013-09-08
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多