一个block中的threadIdx 只在这个block中有效
元素个数 size=4096,kernel launch 配置 blocksPerGrid=(32,1,1),threadsPerBlock=(128,1,1),总线程数 32 × 128 = 4096。
__global__ void reduce(float* d_input, float* d_output, int size) {
// 每个线程处理一个元素计算全局 thread id
int idx = blockIdx.x * blockDim.x + threadIdx.x;
extern __shared__ float shared_data[]; // 动态分配共享内存,大小会是 thread per block * sizeof(float)
// 1. 计算每个 block 中的局部最大值,所以与blockIdx 无关,这里的scope是一个block
float max_val = -INFINITY;
for (int i = threadIdx.x; i < size; i += blockDim.x) {
if (i < size && d_input[i] > max_val) max_val = d_input[i];
}
shared_data[threadIdx.x] = max_val;
__syncthreads();
...
}
上述 code 的目的是将 block 对应的 128 个元素写入这个 block 的 shared memory。而且 i += blockDim.x 永远不会发生,因为 这样做thread的ID 就超过了 0~127 ,所以这个for循环并不会循环,他是多于的。
循环让线程访问超出 block 范围的数据。threadIdx.x 在这个case下是 0~127,i 不会大于127。
上述表达错误!threadIdx.x 不会超过127,但是 i 可以!所以这里的逻辑是正确的(但是冗余)。每个 block 的 128 个线程通过 stride (blockDim.x)访问了所有 4096 个元素,这个 block 内的归约结果实际上是全局总和。
code应该改为:
__global__ void reduce(float* d_input, float* d_output, int size) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
extern __shared__ float shared_data[]; // 动态分配共享内存,大小会是 thread per block * sizeof(float)
// 每个 block 将对应元素写入自己的 shared memory
float max_val = (idx < size) ? d_input[idx] : -INFINITY;
shared_data[threadIdx.x] = max_val;
__syncthreads();
...
}
诶,改成这样就错了,计算得到的 max_val 是block内的值,而非全局max。