【问题标题】:What does #pragma unroll do exactly? Does it affect the number of threads?#pragma unroll 到底是做什么的?它会影响线程数吗?
【发布时间】:2014-04-12 06:50:26
【问题描述】:

我是 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 个吗?

【问题讨论】:

  • 没有。这意味着您调用了一个带有一个块的 CUDA 内核,并且一个块有 100 个活动线程。您将 size 作为第二个函数参数传递给内核。在您的内核中,这 100 个线程中的每一个都执行 for 循环 100 次。我建议你从基础开始学习 CUDA,然后循序渐进,而不是跳到更高级或更不重要的材料,如循环展开。
  • @Farsad,谢谢,您能解释一下#pragma unroll 的作用吗?我认为我可以在不使用 pragma 的情况下执行 for 循环?

标签: cuda nvidia pragma loop-unrolling


【解决方案1】:

没有。这意味着您调用了一个带有一个块的 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&lt;5 6 次和递增i 5 次。而在第二种情况下,它只涉及归档b 数组内容(如果稍后使用i,可能加上int i=5;)。循环展开的另一个好处是增强了指令级并行性 (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)。

【讨论】:

  • #pragma unroll 也包含在programming guide 中。
  • 这主要是因为它会扼杀您的并行计算性能。因为当这是一个分支条件时,线程的扭曲不是并行的,这使块中的任何线程都偏离了不同的指令路径,并且使 SIMT 架构无效,它是 1 条指令(寄存器?)仅由扭曲 @ 中的所有线程执行同一时间同一地点又名平行
  • @RobertCrovella 为什么我们需要显式添加这个编译指示?编译器不能自己识别这样的循环吗?
  • 我没有在任何地方说您必须明确添加此编译指示。我只是链接到文档中的相关部分,以便其他人可能有文档参考。如果您单击该链接并阅读第一句话,您就会得到问题的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多