#pragma unroll做了什么?它会影响线程数吗?

时间:2014-03-09 05:05:10

标签: cuda nvidia pragma loop-unrolling

我是CUDA的新手,我无法理解循环展开。我写了一段代码来理解这项技术

__global__ void kernel(float *b, int size)
{
    int tid = blockDim.x * blockIdx.x + threadIdx.x;
 #pragma unroll
    for(int i=0;i<size;i++)
        b[i]=i;
}

以上是我的核心功能。在main我称之为

int main()
{
    float * a; //host array
    float * b; //device array
    int size=100;

    a=(float*)malloc(size*sizeof(float));
    cudaMalloc((float**)&b,size);
    cudaMemcpy(b, a, size, cudaMemcpyHostToDevice);

    kernel<<<1,size>>>(b,size); //size=100

    cudaMemcpy(a, b, size, cudaMemcpyDeviceToHost);

    for(int i=0;i<size;i++)
        cout<<a[i]<<"\t";

    _getch();

    return 0;
}

这是否意味着我有size * size = 10000个线程运行来执行程序?在展开循环时是否创建了100个?

1 个答案:

答案 0 :(得分:29)

没有。这意味着您已经使用一个块调用了CUDA内核,并且一个块具有100个活动线程。您将size作为第二个函数参数传递给内核。在你的内核中,这100个线程中的每一个都执行for循环100次。

#pragma unroll是一种编译器优化,例如,可以替换像

这样的代码
for ( int i = 0; i < 5; i++ )
    b[i] = i;

b[0] = 0;
b[1] = 1;
b[2] = 2;
b[3] = 3;
b[4] = 4;

#pragma unroll指令放在循环之前。展开版本的好处是它可以减少处理器的处理负担。对于for循环版本,除了将每个i分配给b[i]之外,处理还包括i初始化,评估i<5 6次,以及递增i 5次。在第二种情况下,它只涉及归档b数组内容(如果稍后使用int i=5;,则可能加上i。循环展开的另一个好处是增强了指令级并行(ILP)。在展开版本中,处理器可能会有更多操作进入处理管道而不必担心每次迭代中的for循环条件。

this这样的帖子解释说,CUDA不会发生运行时循环展开。在你的情况下,CUDA编译器没有size将为100的任何线索,因此不会发生编译时循环展开,因此如果强制展开,最终可能会损害性能。

如果你确定所有执行的size都是100,你可以像下面那样展开你的循环:

#pragma unroll
for(int i=0;i<SIZE;i++)  //or simply for(int i=0;i<100;i++)
    b[i]=i;

其中SIZE在编译时已知#define SIZE 100

我还建议您在代码中进行适当的CUDA错误检查(解释here)。