要求写一个reduceKernel 要求给出Kerne的完整调用:
// 简单的实现,使用一个block完成Reduce操作 好蠢好蠢的代码
template
__global__ void BlockReduce(const T* input, T* output, int num) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
for(int i = idx; i < num; i+= blockDim.x + gridDim.x) {
atomicAdd(output, input +i);
}
}
# 一个block完成reduce操作 使用sharemem blockSize = 256
__global__ void BlockReduceSharemem(const T* input, T* output, int num) {
int idx = threadIdx.x;
__share__ int sharemem[ThreadPerBlock];
sharemem[threadIdx.x] = 0;
__syncthreads();
for(int index = idx; index < num; index+=blockDim.x) {
sharemem[threadIdx.x] += input[index];
}
__syncthreads();
for(int i = blockDim.x /2 ; i > 0; i >> 1) {
if (threadIdx < i) {
sharemem[threadIdx.x] += sharemem[threadIdx.x + i];
}
syncthread();
}
if (threadIdx.x == 0)
output[0] = sharemem[0];
}
# 一个block完成reduce操作 使用shuffle指令 blockSize = WarpSize
# shfl指令只能完成一个warp内的操作,因此如果是进行一个block内的数据操作需要先,分步进行
__global__ void BlockReduceSharemem(const T* input, T* output, int num) {
int idx = threadIdx.x;
T sum = 0;
for(int index = idx; index < num; index+=blockDim.x) {
sum += input[index];
}
for(int i = WarpSize /2; i > 0; i >> 1) {
sum+=__shfl_down(sum, i);
}
if (threadIdx.x == 0)
output[0] = sum;
}
# 一个block完成reduce操作 使用shuffle指令 blockSize % WarpSize = 0
# shfl指令只能完成一个warp内的操作,因此如果是进行一个block内的数据操作需要先,分步进行
__global__ void BlockReduceSharemem(const T* input, T* output, int num) {
int idx = threadIdx.x;
T sum = 0;
for(int index = idx; index < num; index+=blockDim.x) {
sum += input[index];
}
__share__ T data[BlockSize];
data[idx] = 0;
__syncthreads();
# 先使用sharemem完成warp_size 以外的数据处理
for(int i = blockDim.x/ 2 i > WarpSize; i>>1) {
if (idx < i){
data[idx] += data[idx + i];
data[idx + i] = 0;
}
}
__syncthreads();
sum = data[idx];
__syncthreads();
for(int i = WarpSize /2; i > 0; i >> 1) {
sum+=__shfl_down(sum, i);
}
if (threadIdx.x == 0)
output[0] = sum;
}
所谓而维Reduce是指当输入in[h, l] 两维时,对h进行Reduce操作,这个时候就需要考虑到线程映射问题了。
方法一: 如果将threadIdx.x 映射到I维度,threadIdx.y 映射到 h维, 则在进行数据读取时候就能实现连续读取,但是则无法进行blockX内的Reduce操作
方法二: 如果将threadIdx.x 映射到h维度,threadIdx.y 映射到 l 维, 能够进行block内的数据读取,但是访存不连续。
补充优化:在进行Reduce index计算时 可以考虑更加高效的index方法