正确使用CUDA共享内存进行2D非连续数据访问

时间:2014-01-07 00:38:32

标签: cuda

我有一个与二维线程访问相关的基本问题。 我想将非连续数据复制到连续缓冲区中,使用cuda memcopy可以说明如下:

void pack_cuda(float *dstbuf, IOV *srciov, int num_iov)
{
  int i;
  float *ptr;
  ptr = buf;
  for (i = 0; i < num_iov; i++) {
    cudaMemcpy(ptr, srciov[i].bufaddr, srciov[i].len, cudaMemcpyDefault);
  ptr = (char *)ptr + srciov[i].len;
  }
}

* srciov将每个非连续数据的起始内存地址和长度存储在结构数组中。

* dstbuf将在函数完成后存储打包的连续数据。

现在,我想使用CUDA内核实现它。

__global__ void pack_cuda(float *dstbuf, IOV *srciov, int num_iov)
{
  int i = blockIdx.x * blockDim.x + threadIdx.x;
  int j = blockIdx.y * blockDim.y + threadIdx.y;
  int k;
  extern __shared__ size_t tmpdbuflen[16*3]; //suppose num_iov is 16

  if ( j == 0 ){
    if ( i < 16 ){
     tmpdbuflen[i] = (srciov[i].len);   //store length to calculate presum
     tmpdbuflen[i+16] = tmpdbuflen[i];  //store length
     tmpdbuflen[i+32] = ((srciov+i)->bufaddr) - (srciov->bufaddr); //store addr difference
    }
    __syncthreads();


    for ( k = 0; k < i; k++)
      tmpdbuflen[i] += srciov[k].len;
  }

  __syncthreads();

  if ( i < 16 && j < srciov[i].len ){  //wondering whether this is correct use
    dst[tmpdbuflen[i] + j] = *(src + tmpdbuflen[i+32] + j);
  }

  __syncthreads();
}

内核调用部分:

dim3 dimblock(16, 16);  //the length of each non-contiguous data is less than 16 
dim3 dimgrid(1,1);
const unsigned int shm_size = sizeof(size_t) * 16 * 3;
pack_cuda<<<dimgrid, dimblock, shm_size, 0>>>(dstbuf, srciov, num_iov);
cudaDeviceSynchronize();

然而,似乎我无法将所有需要的数据打包到dst缓冲区中。 有时只有j = 0和1(对应的各种i)被打包。 我认为主要问题是共享内存的使用。我只使用第0列线程(threadIdx.y == 0)将信息复制到共享内存中。然后所有线程(对threadIdx.y没有限制)将访问和读取共享内存中的信息。 如何修改代码启用这样的设计?

如果有人能解决我的问题,我会很感激。

感谢。

1 个答案:

答案 0 :(得分:1)

您的代码的一些提示:

__global__ void pack_cuda(float *dstbuf, IOV *srciov, int num_iov)
{
  int i = blockIdx.x * blockDim.x + threadIdx.x;
  int j = blockIdx.y * blockDim.y + threadIdx.y;
  int k;
  extern __shared__ size_t tmpdbuflen[16*3]; //suppose num_iov is 16

这里的这个块只能由一个线程执行,因为保护j==0只允许线程bid*bdim+tid = 0*0+0,块0中的ergo线程0,这对你来说是不可取的。我想你想把j < 16放在那里

  if ( j == 0 ){
    if ( i < 16 ){
     tmpdbuflen[i] = (srciov[i].len);   //store length to calculate presum
     tmpdbuflen[i+16] = tmpdbuflen[i];  //store length
     tmpdbuflen[i+32] = ((srciov+i)->bufaddr) - (srciov->bufaddr); //store addr difference
    }
    __syncthreads();


    for ( k = 0; k < i; k++)
      tmpdbuflen[i] += srciov[k].len;
  }