我已经在各个地方读过,__device__
函数几乎总是由CUDA编译器内联。那么说,当我将代码从内核移动到内核调用的__device__
函数时,通常没有增加寄存器的数量吗?
例如,以下代码段使用相同数量的寄存器吗?它们同样有效吗?
SNIPPET 1
__global__ void manuallyInlined(float *A,float *B,float *C,float *D,float *E) {
// code that manipulates A,B,C,D and E
}
SNIPPET 2
__device__ void fn(float *A,float *B,float *C,float *D,float *E) {
// code that manipulates A,B,C,D and E
}
__global__ void manuallyInlined(float *A,float *B,float *C,float *D,float *E) {
fn(A,B,C,D,E);
}
答案 0 :(得分:3)
最终答案只能通过使用工具(使用-Xptxas -v
编译,或使用其中一个分析器)来确定,但一般的答案是调用__device__
函数可以< / em>影响使用的寄存器数量(以及性能和效率)。
根据您的文件组织以及编译代码的方式,__device__
功能可能为inlined。如果它是内联的,这通常会给优化编译器(主要是ptxas)提供最适合调整寄存器使用的机会。 (注意,至少在理论上,这个&#34;适应&#34;可能会导致 或多或少使用。但是,内联案例通常会导致编译器使用较少的寄存器和可能性能更高。但编译器主要优化以获得更高的性能,而不是更少的寄存器使用。)
另一方面,如果它没有内联,则必须将其作为普通函数调用处理。与许多其他计算机体系结构一样,函数调用涉及设置堆栈帧以传递变量,然后将控制转移到函数。在这种情况下,编译器受到更多限制,因为:
__device__
函数必须由编译器以独立方式处理。因此,如果函数可以内联,那么两种方法之间应该没有太大区别。如果无法内联函数,那么上述两种方法中的寄存器使用通常会有明显的差异。
可能影响编译器是否会尝试内联__device__
函数的一些明显因素是:
如果__device__
函数与调用它的__global__
或其他__device__
函数位于单独的编译单元中。在这种情况下,唯一可行的方法是通过CUDA separate compilation and linking,也称为设备链接。在这种情况下,编译器不会(不能)内联函数。
如果指定了__noinline__
compiler directive。请注意,这只是编译器的一个提示;它可能会被忽略。