启动适当数量的还原内核的一般方法是什么?

时间:2013-12-08 17:39:16

标签: cuda

正如我从此链接http://www.cuvilib.com/Reduction.pdf中的NVIDIA指令中读到的,对于大于blockSize的数组,我应该启动多个简化内核来实现全局同步。确定启动还原内核的次数的一般方法是什么?我尝试如下,但我需要Malloc 2额外的指针,这需要大量的处理时间。

我的工作是将数组d_logLuminance简化为一个最小值min_logLum

void your_histogram_and_prefixsum(const float* const d_logLuminance,
                              float &min_logLum,
                              const size_t numRows,
                              const size_t numCols)
{
const dim3 blockSize(512);
unsigned int pixel = numRows*numCols;
const dim3 gridSize(pixel/blockSize.x+1);

//Reduction kernels to find max and min value
float *d_tempMin, *d_min;
checkCudaErrors(cudaMalloc((void**) &d_tempMin, sizeof(float)*pixel));
checkCudaErrors(cudaMalloc((void**) &d_min, sizeof(float)*pixel));
checkCudaErrors(cudaMemcpy(d_min, d_logLuminance, sizeof(float)*pixel, cudaMemcpyDeviceToDevice));

dim3 subGrid = gridSize;
for(int reduceLevel = pixel; reduceLevel > 0; reduceLevel /= blockSize.x) {
    checkCudaErrors(cudaMemcpy(d_tempMin, d_min, sizeof(float)*pixel, cudaMemcpyDeviceToDevice));
    reduceMin<<<subGrid,blockSize,blockSize.x*sizeof(float)>>>(d_tempMin, d_min);
    cudaDeviceSynchronize(); checkCudaErrors(cudaGetLastError());
    subGrid.x = subGrid.x / blockSize.x + 1;
}

checkCudaErrors(cudaMemcpy(&min_logLum, d_min, sizeof(float), cudaMemcpyDeviceToHost));

std::cout<< "Min value = " << min_logLum << std::endl;

checkCudaErrors(cudaFree(d_tempMin));
checkCudaErrors(cudaFree(d_min));

}

如果你好奇,这是我的缩减内核:

__global__
void reduceMin(const float* const g_inputRange,
                 float* g_outputRange)
{
extern __shared__ float sdata[];
unsigned int tid = threadIdx.x;    
unsigned int i = blockDim.x * blockIdx.x + threadIdx.x;
sdata[tid] = g_inputRange[i];
__syncthreads();

for(unsigned int s = blockDim.x/2; s > 0; s >>= 1){
    if (tid < s){
        sdata[tid] = min(sdata[tid],sdata[tid+s]);
    }
    __syncthreads();
}

if(tid == 0){
  g_outputRange[blockIdx.x] = sdata[0];
} 
}

1 个答案:

答案 0 :(得分:0)

有很多方法可以对猫进行换肤,但是如果你想最小化内核启动,最多只需要两次内核启动就可以完成。

第一个内核启动由多个块组成,这些块对应于设备支持的每个块的线程数。较新的设备将支持1024个旧设备,512。

第一个内核中的每个(最多512或1024个)块都将参与全局内存中所有数据元素的网格循环求和。

然后,这些块中的每一个都将进行部分缩减并将部分结果写入全局内存。这些部分结果将有512或1024个。

第二个内核启动将由一个块中的512或1024个线程组成。每个线程将从全局内存中获取一个部分结果,然后该单个块中的线程将协同地将部分结果减少为单个最终结果,并将其写回全局内存。

“网格循环和”在简化#7 here中描述为“多个添加/线程”。本文档中描述的所有减少都可以在NVIDIA reduction sample code

中找到