CUDA循环展开

时间:2014-06-22 06:12:12

标签: cuda

我在CUDA中循环展开时遇到了一些问题。

在普通的串行代码中:

//serial basic:
for(int i = 0; i < n; i++){
    c[i] = a[i] + b[i];}

//serial loop unroll:
for(int i = 0; i < n/4; i++){
    c[i] = a[i] + b[i];
    c[i+1] = a[i+1] + b[i+1];
    c[i+2] = a[i+2] + b[i+2];
    c[i+3] = a[i+3] + b[i+3];} 

所以我认为CUDA循环展开看起来像这样:

int i = 2*(threadIdx.x + blockIdx.x * gridDim.x);
a[i+0] = b[i+0] + c[i+0];
a[i+1] = b[i+1] + c[i+1];

但在CUDA手册中展开的例子我无法理解

这是一个普通的GlobalWrite内核:

__global__ void GlobalWrites( T *out, T value, size_t N )
{
for(size_t i = blockIdx.x*blockDim.x+threadIdx.x;
    i < N;
    i += blockDim.x*gridDim.x ) {
    out[i] = value;
    } 
 }

展开内核:

template<class T, const int n> __global__ void Global_write(T* out, T value, size_t N){
size_t i;
for(i = n*blockDim.x*blockIdx.x + threadIdx.x;
    i < N - n*blockDim.x*blockIdx.x;
    i += n*gridDim.x*blockDim.x;)
    for(int j = 0; j < n; i++){
        size_t index = i + j * blockDim.x;
        outp[index] = value;
    }
for ( int j = 0; j < n; j++ ) {
    size_t index = i+j*blockDim.x;
    if ( index<N ) out[index] = value;
}}

我知道这个内核使用更少的块但可能有人解释为什么它更好地工作(n = 4,10%加速)。

2 个答案:

答案 0 :(得分:6)

如果不明显,因为n是模板参数,所以它在编译时是常量。这意味着编译器可以通过展开自由地优化常量跳闸计数循环。因此,删除模板魔术并手动展开循环以获得您提到的n = 4案例是有益的:

template<class T> 
__global__ void Global_write(T* out, T value, size_t N)
{
    size_t i;
    for(i = 4*blockDim.x*blockIdx.x + threadIdx.x;
        i < N - 4*blockDim.x*blockIdx.x;
        i += 4*gridDim.x*blockDim.x;) {
            out[i + 0 * blockDim.x] = value;
            out[i + 1 * blockDim.x] = value;
            out[i + 2 * blockDim.x] = value;
            out[i + 3 * blockDim.x] = value;
    }
    if ( i+0*blockDim.x < N ) out[i+0*blockDim.x] = value;
    if ( i+1*blockDim.x < N ) out[i+1*blockDim.x] = value;
    if ( i+2*blockDim.x < N ) out[i+2*blockDim.x] = value;
    if ( i+3*blockDim.x < N ) out[i+3*blockDim.x] = value;
}

展开的内部循环产生四个完全独立的写入,这些写入被合并。正是这种指令级并行性使代码具有更高的指令吞吐量和更高的性能。如果您还没有看过,我强烈推荐几年前GTC会议上的Vasily Volkov Unrolling Parallel Loops。他的演讲列出了为什么这种类型的循环展开是CUDA优化的理论背景。

答案 1 :(得分:3)

在模板化内核中,const int n在编译时是已知的,允许编译器实际展开for(int j = 0; j < n; i++)循环,从而删除该循环上的条件检查。如果在编译时未知循环大小,则编译器无法展开循环。就这么简单。

相关问题