我有以下功能:
代码示例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];
有人可以提供直观的例子或解释吗?
答案 0 :(得分:2)
在main函数中,索引大于blockDim.x*(gridDim.x-1)+(blockDim.x-1)
的元素将被视为计算,而在您提供的方法中,它不会发生。
假设你有N=1024
,并且你用一个网格调用你的函数,每个网格有8个块,每个块有32个线程。在您的main函数中,线程i
将收集并添加属于*input
,i
,i+8*32
,i+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不会。