CUDA线程在共享内存中移动数据时的执行

时间:2013-11-29 18:57:01

标签: cuda gpu

我有以下功能:

代码示例1:

__global__ void func(const int *input, int N){

  extern __shared__int buffer[];
  int temp = 0;

  for(int i = blockIdx.x*blockDim.x + threadIdx.x; i < N; i += blockDim.x*gridDim.x; ){
     temp += input[i];
  }

  buffer[threadIdx.x] = temp;
  __syncthreads();

} 

它是并行缩减功能的一部分。据我所知,它从全局内容复制到共享内存。

我试图通过一个简单的例子来理解它。例如,我有一个大小为20的一维数组 元素(N = 20)。我想象执行如下。纠正我如果我错了。对于5个块,每个4个线程。

执行第一个块的所有线程:

blockIdx.x=0
threadIdx.x=0
for(i=0; i<18; i+= 4*5){ temp= in[0] /i wrote the sums intuitively/}        
buffer[threadIdx.x] = temp

blockIdx.x=0
threadIdx.x=1
for(i=1; i<18; i+= 4*5){ temp= in[1] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

blockIdx.x=0
threadIdx.x=2
for(i=2; i<18; i+= 4*5){ temp= in[2] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

blockIdx.x=0
threadIdx.x=3
for(i=3; i<18; i+= 4*5){ temp= in[3] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

执行第二个块的所有线程:

blockIdx.x=1
threadIdx.x=0
for(i=1*4; i<18; i+= 4*5){ temp= in[4] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

blockIdx.x=1
threadIdx.x=1
for(i=1*4+1; i<18; i+= 4*5){ temp = in[5] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

blockIdx.x=1
threadIdx.x=2
for(i=1*4+2; i<18; i+= 4*5){ temp = in[6] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

blockIdx.x=1
threadIdx.x=3
for(i=1*4+3; i<18; i+= 4*5){ temp = in[7] /i wrote the sums intuitively/}
buffer[threadIdx.x] = temp

e.t.c。

为什么我们有一个for循环而不只是写:

代码示例2:

unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
buffer[threadIdx.x] = input[i]; 

有人可以提供直观的例子或解释吗?

1 个答案:

答案 0 :(得分:2)

在main函数中,索引大于blockDim.x*(gridDim.x-1)+(blockDim.x-1)的元素将被视为计算,而在您提供的方法中,它不会发生。

假设你有N=1024,并且你用一个网格调用你的函数,每个网格有8个块,每个块有32个线程。在您的main函数中,线程i将收集并添加属于*inputii+8*32i+2*(8*32)的数据i+3*(8*32)。另一方面,您的代码仅在元素i处收集数据。换句话说,它只会32*8 *input的{​​{1}}首要元素,而忽略1024-32*8休息。

更详细:

代码exmaple 1的工作原理如下:

blockIdx.x=0
threadIdx.x=0
for ( i = 0; i < 1024; i += 32*8 )
    temp += input[i]; // temp= input[0]+input[256]+input[512]+input[768]
buffer[0] = temp; //=input[0]+input[256]+input[512]+input[768]

blockIdx.x=0
threadIdx.x=1
for ( i = 1; i < 1024; i += 32*8 )
    temp += input[i]; // temp= input[1]+input[257]+input[513]+input[769]
buffer[1] = temp; //=input[1]+input[257]+input[513]+input[769]

blockIdx.x=0
threadIdx.x=2
for ( i = 2; i < 1024; i += 32*8 )
    temp += input[i]; // temp= input[2]+input[258]+input[514]+input[770]
buffer[2] = temp; //=input[2]+input[258]+input[514]+input[770]

...

//last thread
blockIdx.x=7
threadIdx.x=31
for ( i = 7*32+31; i < 1024; i += 32*8 )
    temp += input[i]; // temp= input[255]+input[511]+input[767]+input[1023]
buffer[255] = temp; //=input[255]+input[511]+input[767]+input[1023]

代码exmaple 2的工作原理如下:

blockIdx.x=0
threadIdx.x=0
i = 0*32+0; //=0
buffer[0] = input[0];

blockIdx.x=0
threadIdx.x=1
i = 0*32+1; //=1
buffer[1] = input[1];

...

//last thread
blockIdx.x=7
threadIdx.x=31
i = 7*32+31; //=255
buffer[255] = input[255];

正如您可以看到第一个代码示例,遍历input数组的所有元素,但第二个代码exmaple不会。