【问题标题】:CUDA thread execution in moving data in shared memoty在共享内存中移动数据时的 CUDA 线程执行
【发布时间】:2016-02-22 01:43:03
【问题描述】:

我有以下功能:

代码示例 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

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

代码示例 2:

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

谁能给出一个直观的例子或解释?

【问题讨论】:

    标签: cuda gpu


    【解决方案1】:

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

    假设您有N=1024,并且您使用一个网格调用您的函数,该网格有 8 个块,每个块有 32 个线程。在您的主函数中,线程i 将在元素ii+8*32i+2*(8*32)i+3*(8*32) 处收集并累加属于*input 的数据。另一方面,您的代码仅在元素 i 处收集数据。换句话说,它仅将*input 的第一个元素32*8 相加,而忽略1024-32*8 其余元素。

    更详细:

    代码示例 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]
    

    代码示例 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 数组的所有元素,但第二个代码示例没有。

    【讨论】:

    • 当您说blockDim.x*(gridDim.x-1)+(blockDim.x-1) 时,您指的是代码的哪一部分?你能给出更详细的解释吗? (这部分代码来自一本书)你是说我给的例子不对还是代码不对?
    • 在主代码中,for循环中每个线程的i初始化为blockIdx.x*blockDim.x + threadIdx.xblockDim.x 的最大值可以是 gridDim.x-1threadIdx.x 的最大值可以是 blockDim.x-1。如果N 大于blockDim.x*(gridDim.x-1)+(blockDim.x-1),您提供的最后一段代码将无法正常工作。
    • 如果你指的是 代码示例 2 说最后一段代码我想我理解你如果你的意思是我们选择 for 循环因为线程局限性。我只是发现使用for 循环有点奇怪,它只有一次执行。换句话说,如果我们有很多元素,那么 for 循环是否有意义?只有这样它才被执行多次?抱歉我的无知我是 cuda 领域的新手。
    • 是的,当我说最后一段代码时,我指的是代码示例 2。是的。如果我们有很多元素并且我们的块数量有限且大小有限,则使用“for”循环可能是一种解决方案。
    猜你喜欢
    • 2011-12-31
    • 1970-01-01
    • 2012-11-18
    • 2012-09-21
    • 2014-09-16
    • 2022-01-06
    • 2011-06-29
    • 2013-03-27
    • 2012-05-04
    相关资源
    最近更新 更多