CUDA在给出的实例程序中出现了不少次的 #prama unroll 的用法,搜集到资料整理如下:
1. 官方文档 CUDA C PROGRAMMING GUIDE v6.5 中给出的说明:
By default, the compiler unrolls small loops with a known trip count. The #pragma unroll directive however can be used to control unrolling of any given loop. It must be placed immediately before the loop and only applies to that loop. It is optionally followed by a number that specifies how many times the loop must be unrolled. For example, in this code sample:
#pragma unroll 5
for (int i = 0; i < n; ++i)
the loop will be unrolled 5 times. The compiler will also insert code to ensure correctness (in the example above, to ensure that there will only be n iterations if n is less than 5, for example). It is up to the programmer to make sure that the specified unroll number gives the best performance.
#pragma unroll 1 will prevent the compiler from ever unrolling a loop. If no number is specified after #pragma unroll, the loop is completely unrolled if its trip count is constant, otherwise it is not unrolled at all.
在默认情形下,编译器对已知次数的小循环进行展开,#pragma unroll 可以用来控制任意一个给定的循环。但 #pragma unroll必须放在被控制的循环的前面,后面可以带展开次数选项。
编译器编译时保证正确性,而性能则是由程序员决定。
后跟参数1则编译器不会展开循环。如果没有参数,并且循环次数是一常数时编译器会将循环完全展开,如果不是常数就根本不会展开。
#pragma宏命令主要是改变编译器的编译行为,其他的参数网上资料比较多,我只想简单说下#pragma unroll的用法,因为网上的资料比较少,而且说的比较笼统,请看下面的一段代码
int main()
{
int a[100];
#pragma unroll 4
for(int i=0;i<100;i++)
{
a[i]=i;
}
return 0;
}
循环是一个程序运行时间的主要展现形式,通过使用#pragma unroll命令,编译器在进行编译时,遇到该命令就会对循环进行展开,比如对一些循环次数比较少的循环
for(int i=0;i<4;i++)
cout<<"hello world"<<endl;
可以展开为:
cout<<"hello world"<<endl;
cout<<"hello world"<<endl;
cout<<"hello world"<<endl;
cout<<"hello world"<<endl;
这样程序的运行效率会更好,当然,现在大多数编译器都会自动这样优化,而通过使用#pragma unroll命令就可以控制编译器的对循环的展开程度。还是回到最开始那个程序,他的循环展开形式为:
for(int i=0;i<100;i+=4)
{
a[i]=i;
a[i+1]=i+1;
a[i+2]=i+2;
a[i+3]=i+3;
}
3. CUDA的编译
CUDA的编译器为nvcc,nvcc将各种编译工具集成起来,这些编译工具实现了编译的不同阶段。nvcc的基本工作流是将device代码从host代码中分离出来,然后将其编译成二进制或者cubin工程。在执行过程中,将忽略host代码,而将device代码加载并通过CUDA的设备API来执行。
CUDA源代码在编译器前端是基于c++语法的。host代码中能够全部支持C++,但是在device中只能支持c++中的C部分。在kernel中不允许有C++的类、继承以及在基本块中定义变量等语法。C++中的void类型指针不能在没有类型转化的前提下赋值给一个非void的指针。
nvcc的更多介绍请见:http://download.youkuaiyun.com/source/1173428
__noinline__
__device__函数在默认情况下是内联的,通过__noinline__限定符能够提示编译器不要将指定的函数内联。编译器不支持指针参数和大量参数的函数使用__noinline__
#pragma unroll
编译器默认情况下将循环展开小的次数,#pragma unroll 能够指定循环以多少次展开(程序员必须保证按这个展开是正确的),例如
#pragma unroll 5
for()
pragma unroll 后必须紧接着处理的循环。
#pragmatic unroll 1 禁止编译器将循环展开。
如果没指定次数,对于常数次的循环,循环将完全展开,对于不确定次数的循环,循环将不会被展开。