使用volatile限定符在CUDA中声明寄存器数组是什么意思?
当我尝试使用带有寄存器数组的volatile关键字时,它将溢出的寄存器内存数量删除到本地内存。 (即强制CUDA使用寄存器而不是本地存储器)这是预期的行为吗?
在CUDA文档中,我没有找到任何关于寄存器数组的volatile用法的信息。
以下是两个版本的ptxas -v输出
使用volatile限定符
__volatile__ float array[32];
ptxas -v输出
ptxas info : Compiling entry function '_Z2swPcS_PfiiiiS0_' for 'sm_20'
ptxas info : Function properties for _Z2swPcS_PfiiiiS0_
88 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 47 registers, 16640 bytes smem, 80 bytes cmem[0], 8 bytes cmem[16]
没有挥发性限定符
float array[32];
ptxas -v输出
ptxas info : Compiling entry function '_Z2swPcS_PfiiiiS0_' for 'sm_20'
ptxas info : Function properties for _Z2swPcS_PfiiiiS0_
96 bytes stack frame, 100 bytes spill stores, 108 bytes spill loads
ptxas info : Used 51 registers, 16640 bytes smem, 80 bytes cmem[0], 8 bytes cmem[16]
答案 0 :(得分:5)
volatile
限定符指定编译器对变量(读或写)的所有引用都应该生成内存引用,并且这些引用必须按程序中指定的顺序排列。 Shane Cook书中的第12章“CUDA编程”中说明了volatile
限定符的使用。
volatile
的使用将避免编译器可以做的一些优化,因此改变使用的寄存器的数量。了解volatile
实际执行的操作的最佳方法是使用和不使用限定符来反汇编相关的__global__
函数。
确实考虑以下内核函数
__global__ void volatile_test() {
volatile float a[3];
for (int i=0; i<3; i++) a[i] = (float)i;
}
__global__ void no_volatile_test() {
float a[3];
for (int i=0; i<3; i++) a[i] = (float)i;
}
反汇编上面的内核函数
code for sm_20
Function : _Z16no_volatile_testv
.headerflags @"EF_CUDA_SM20 EF_CUDA_PTX_SM(EF_CUDA_SM20)"
/*0000*/ MOV R1, c[0x1][0x100]; /* 0x2800440400005de4 */
/*0008*/ EXIT ; /* 0x8000000000001de7 */
Function : _Z13volatile_testv
.headerflags @"EF_CUDA_SM20 EF_CUDA_PTX_SM(EF_CUDA_SM20)"
/*0000*/ MOV R1, c[0x1][0x100]; /* 0x2800440400005de4 */
/*0008*/ ISUB R1, R1, 0x10; /* 0x4800c00040105d03 */ R1 = address of a[0]
/*0010*/ MOV32I R2, 0x3f800000; /* 0x18fe000000009de2 */ R2 = 1
/*0018*/ MOV32I R0, 0x40000000; /* 0x1900000000001de2 */ R0 = 2
/*0020*/ STL [R1], RZ; /* 0xc8000000001fdc85 */
/*0028*/ STL [R1+0x4], R2; /* 0xc800000010109c85 */ a[0] = 0;
/*0030*/ STL [R1+0x8], R0; /* 0xc800000020101c85 */ a[1] = R2 = 1;
/*0038*/ EXIT ; /* 0x8000000000001de7 */ a[2] = R0 = 2;
如您所见,当不使用volatile
关键字时,编译器意识到a
已设置但从未使用过(实际上,编译器返回以下警告:变量“a”已设置但从未使用)并且几乎没有反汇编代码。
与此相反,当使用volatile
关键字时,对a
的所有引用都将转换为内存引用(在本例中为write)。