Mag*_*yev 24 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;
}
Run Code Online (Sandbox Code Playgroud)
以上是我的核心功能.在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;
}
Run Code Online (Sandbox Code Playgroud)
这是否意味着我有size*size= 10000个线程运行来执行程序?在展开循环时是否创建了100个?
Far*_*zad 33
不.这意味着你已经用一个块调用了一个CUDA内核,并且一个块有100个活动线程.您将size作为第二个函数参数传递给内核.在你的内核中,这100个线程中的每一个都执行for循环100次.
#pragma unroll 是一个编译器优化,可以,例如,替换一段代码,如
for ( int i = 0; i < 5; i++ )
b[i] = i;
Run Code Online (Sandbox Code Playgroud)
同
b[0] = 0;
b[1] = 1;
b[2] = 2;
b[3] = 3;
b[4] = 4;
Run Code Online (Sandbox Code Playgroud)
通过#pragma unroll在循环之前放置指令.展开版本的好处是它可以减少处理器的处理负担.在的情况下for循环版本,处理,除了分配每个i到b[i],涉及i初始化,评价i<5为6次,并且递增i为5次.而在第二种情况下,它只涉及归档b数组内容(int i=5;如果i稍后使用,可能加上).循环展开的另一个好处是增强了指令级并行(ILP).在展开版本中,处理器可能会有更多操作进入处理管道而不必担心for每次迭代中的循环条件.
像这样的帖子解释了CUDA不会发生运行时循环展开.在您的情况下,CUDA编译器没有任何线索,size因此不会发生编译时循环展开,因此如果您强行展开,最终可能会损害性能.
如果你确定size所有执行都是100,你可以像下面那样展开你的循环:
#pragma unroll
for(int i=0;i<SIZE;i++) //or simply for(int i=0;i<100;i++)
b[i]=i;
Run Code Online (Sandbox Code Playgroud)
其中SIZE在编译时已知#define SIZE 100.
我还建议您在代码中进行适当的CUDA错误检查(在此处说明).