Cuda PTX 寄存器声明和使用
Cuda PTX registers declaration and using
我试图减少内核中使用寄存器的数量,所以我决定尝试内联 PTX。
这个内核:
#define Feedback(a, b, c, d, e) d^e^(a&c)^(a&e)^(b&c)^(b&e)^(c&d)^(d&e)^(a&d&e)^(a&c&e)^(a&b&d)^(a&b&c)
__global__ void Test(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e, unsigned long f, unsigned long j, unsigned long h, unsigned long* res)
{
res[0] = Feedback( a, b, c, d, e );
res[1] = Feedback( b, c, d, e, f );
res[2] = Feedback( c, d, e, f, j );
res[3] = Feedback( d, e, f, j, h );
}
使用 14 个寄存器,我认为这超出了需要,所以我写了 Inline PTX:
__global__ void Feedback_ASM(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e, unsigned long f, unsigned long j, unsigned long h, unsigned long* res)
{
asm(".reg .u32 %r<10>;\n");
// 1
asm("ld.param.u32 %r1, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_a];\n"
"ld.param.u32 %r2, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_b];\n"
"ld.param.u32 %r3, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_c];\n"
"ld.param.u32 %r4, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_d];\n"
"ld.param.u32 %r5, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_e];\n");
asm("and.b32 %r7, %r1, %r3;\n"
"xor.b32 %r8, %r7, %r4;\n"
"xor.b32 %r7, %r8, %r5;\n"
"and.b32 %r8, %r1, %r5;\n"
"xor.b32 %r9, %r7, %r8;\n"
.............................
"xor.b32 %r8, %r7, %r9;\n"
"and.b32 %r6, %r1, %r2;\n"
"and.b32 %r7, %r6, %r3;\n"
"xor.b32 %r9, %r7, %r8;\n");
asm("ld.param.u32 %r8, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_res];\n"
"st.global.u32 [%r8+0], %r9;");
// 2
...
// 3
...
// 4
...
}
但是这个内核也用了14个寄存器!我有点困惑。我只声明了 10 个寄存器,在 ptx 文件中没有其他变量。我该如何解决这种情况?
如前所述,PTX 是一个中间代码。 PTX "registers" 是虚拟寄存器,不一定反映实际的设备寄存器使用情况。
要了解实际的设备寄存器使用情况,请使用 ptxas verbose 选项进行编译:
nvcc -Xptxas -v ...
或使用其中一个分析器。您还可以直接使用以下命令检查机器代码:
cuobjdump -sass myexe
(其中 myexe
替换为您的可执行文件的名称)。
要控制寄存器的使用,可以使用nvcc编译选项:
nvcc -maxrregcount 10 ...
(其中 10 替换为您希望代码中的所有内核限制为每个线程的寄存器数)或者您可以在代码中使用 launch bounds 指令,它可以控制寄存器在逐个内核。
我试图减少内核中使用寄存器的数量,所以我决定尝试内联 PTX。
这个内核:
#define Feedback(a, b, c, d, e) d^e^(a&c)^(a&e)^(b&c)^(b&e)^(c&d)^(d&e)^(a&d&e)^(a&c&e)^(a&b&d)^(a&b&c)
__global__ void Test(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e, unsigned long f, unsigned long j, unsigned long h, unsigned long* res)
{
res[0] = Feedback( a, b, c, d, e );
res[1] = Feedback( b, c, d, e, f );
res[2] = Feedback( c, d, e, f, j );
res[3] = Feedback( d, e, f, j, h );
}
使用 14 个寄存器,我认为这超出了需要,所以我写了 Inline PTX:
__global__ void Feedback_ASM(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long e, unsigned long f, unsigned long j, unsigned long h, unsigned long* res)
{
asm(".reg .u32 %r<10>;\n");
// 1
asm("ld.param.u32 %r1, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_a];\n"
"ld.param.u32 %r2, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_b];\n"
"ld.param.u32 %r3, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_c];\n"
"ld.param.u32 %r4, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_d];\n"
"ld.param.u32 %r5, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_e];\n");
asm("and.b32 %r7, %r1, %r3;\n"
"xor.b32 %r8, %r7, %r4;\n"
"xor.b32 %r7, %r8, %r5;\n"
"and.b32 %r8, %r1, %r5;\n"
"xor.b32 %r9, %r7, %r8;\n"
.............................
"xor.b32 %r8, %r7, %r9;\n"
"and.b32 %r6, %r1, %r2;\n"
"and.b32 %r7, %r6, %r3;\n"
"xor.b32 %r9, %r7, %r8;\n");
asm("ld.param.u32 %r8, [__cudaparm__Z7Feedback_ASMmmmmmmmmPm_res];\n"
"st.global.u32 [%r8+0], %r9;");
// 2
...
// 3
...
// 4
...
}
但是这个内核也用了14个寄存器!我有点困惑。我只声明了 10 个寄存器,在 ptx 文件中没有其他变量。我该如何解决这种情况?
如前所述,PTX 是一个中间代码。 PTX "registers" 是虚拟寄存器,不一定反映实际的设备寄存器使用情况。
要了解实际的设备寄存器使用情况,请使用 ptxas verbose 选项进行编译:
nvcc -Xptxas -v ...
或使用其中一个分析器。您还可以直接使用以下命令检查机器代码:
cuobjdump -sass myexe
(其中 myexe
替换为您的可执行文件的名称)。
要控制寄存器的使用,可以使用nvcc编译选项:
nvcc -maxrregcount 10 ...
(其中 10 替换为您希望代码中的所有内核限制为每个线程的寄存器数)或者您可以在代码中使用 launch bounds 指令,它可以控制寄存器在逐个内核。