如何确定CUDA的哪些行使用最多寄存器?
我有一个有以下统计信息的有点复杂的内核:如何确定CUDA的哪些行使用最多寄存器?,cuda,Cuda,我有一个有以下统计信息的有点复杂的内核: ptxas info : Compiling entry function 'my_kernel' for 'sm_21' ptxas info : Function properties for my_kernel 32 bytes stack frame, 64 bytes spill stores, 40 bytes spill loads ptxas info : Used 62 registers, 120 bytes
ptxas info : Compiling entry function 'my_kernel' for 'sm_21'
ptxas info : Function properties for my_kernel
32 bytes stack frame, 64 bytes spill stores, 40 bytes spill loads
ptxas info : Used 62 registers, 120 bytes cmem[0], 128 bytes cmem[2], 8 bytes cmem[14], 4 bytes cmem[16]
就寄存器使用而言,我不清楚内核的哪个部分是“高水位线”。内核的本质是,为常量值去掉各个部分会导致优化器对后面的部分进行常量折叠,等等(至少看起来是这样的,因为我这样做时得到的数字没有多大意义)
CUDA探查器同样毫无帮助,只是告诉我我有注册压力
有没有办法获得有关寄存器使用的更多信息?我更喜欢某种工具,但如果需要的话,我也会有兴趣听到直接挖掘已编译的二进制文件
编辑:我当然可以采用自下而上的方法(即进行实验性代码更改,检查对寄存器使用的影响等),但我更愿意从自上而下开始,或者至少获得一些关于从何处开始自下而上调查的指导。通过编译到带注释的PTX,您可以感受到编译器输出的复杂性,如下所示:
nvcc -ptx -Xopencc="-LIST:source=on" branching.cu
它将发出一个PTX汇编程序文件,其中包含原始C代码作为注释:
.entry _Z11branchTest0PfS_S_ (
.param .u64 __cudaparm__Z11branchTest0PfS_S__a,
.param .u64 __cudaparm__Z11branchTest0PfS_S__b,
.param .u64 __cudaparm__Z11branchTest0PfS_S__d)
{
.reg .u16 %rh<4>;
.reg .u32 %r<5>;
.reg .u64 %rd<10>;
.reg .f32 %f<5>;
.loc 16 1 0
// 1 __global__ void branchTest0(float *a, float *b, float *d)
$LDWbegin__Z11branchTest0PfS_S_:
.loc 16 7 0
// 3 unsigned int tidx = threadIdx.x + blockDim.x*blockIdx.x;
// 4 float aval = a[tidx], bval = b[tidx];
// 5 float z0 = (aval > bval) ? aval : bval;
// 6
// 7 d[tidx] = z0;
mov.u16 %rh1, %ctaid.x;
mov.u16 %rh2, %ntid.x;
mul.wide.u16 %r1, %rh1, %rh2;
cvt.u32.u16 %r2, %tid.x;
add.u32 %r3, %r2, %r1;
cvt.u64.u32 %rd1, %r3;
mul.wide.u32 %rd2, %r3, 4;
ld.param.u64 %rd3, [__cudaparm__Z11branchTest0PfS_S__a];
add.u64 %rd4, %rd3, %rd2;
ld.global.f32 %f1, [%rd4+0];
ld.param.u64 %rd5, [__cudaparm__Z11branchTest0PfS_S__b];
add.u64 %rd6, %rd5, %rd2;
ld.global.f32 %f2, [%rd6+0];
max.f32 %f3, %f1, %f2;
ld.param.u64 %rd7, [__cudaparm__Z11branchTest0PfS_S__d];
add.u64 %rd8, %rd7, %rd2;
st.global.f32 [%rd8+0], %f3;
.loc 16 8 0
// 8 }
exit;
$LDWend__Z11branchTest0PfS_S_:
} // _Z11branchTest0PfS_S_
并使用cuobjdump
实用程序反汇编程序生成的机器代码
$ cuobjdump -sass branching.cubin
code for sm_20
Function : _Z11branchTest0PfS_S_
/*0000*/ /*0x00005de428004404*/ MOV R1, c [0x1] [0x100];
/*0008*/ /*0x94001c042c000000*/ S2R R0, SR_CTAid_X;
/*0010*/ /*0x84009c042c000000*/ S2R R2, SR_Tid_X;
/*0018*/ /*0x10015de218000000*/ MOV32I R5, 0x4;
/*0020*/ /*0x2000dc0320044000*/ IMAD.U32.U32 R3, R0, c [0x0] [0x8], R2;
/*0028*/ /*0x10311c435000c000*/ IMUL.U32.U32.HI R4, R3, 0x4;
/*0030*/ /*0x80319c03200b8000*/ IMAD.U32.U32 R6.CC, R3, R5, c [0x0] [0x20];
/*0038*/ /*0x9041dc4348004000*/ IADD.X R7, R4, c [0x0] [0x24];
/*0040*/ /*0xa0321c03200b8000*/ IMAD.U32.U32 R8.CC, R3, R5, c [0x0] [0x28];
/*0048*/ /*0x00609c8584000000*/ LD.E R2, [R6];
/*0050*/ /*0xb0425c4348004000*/ IADD.X R9, R4, c [0x0] [0x2c];
/*0058*/ /*0xc0329c03200b8000*/ IMAD.U32.U32 R10.CC, R3, R5, c [0x0] [0x30];
/*0060*/ /*0x00801c8584000000*/ LD.E R0, [R8];
/*0068*/ /*0xd042dc4348004000*/ IADD.X R11, R4, c [0x0] [0x34];
/*0070*/ /*0x00201c00081e0000*/ FMNMX R0, R2, R0, !pt;
/*0078*/ /*0x00a01c8594000000*/ ST.E [R10], R0;
/*0080*/ /*0x00001de780000000*/ EXIT;
......................................
通常可以从汇编程序追溯到PTX,并至少大致了解“贪婪”代码段的位置。话虽如此,管理注册压力是目前CUDA编程中比较困难的方面之一。如果/当NVIDIA记录设备代码的ELF格式时,我认为一个合适的代码分析工具对某人来说是一个伟大的项目。在使用nvcc编译时,您是否特别禁用设备优化?默认情况下,设备优化处于启用状态。你必须直接告诉nvcc-O0。在我看来,如果你特别禁用优化,编译器根本不应该做任何代码转换。。。所以你应该通过存根得到你想要的。尽管这可能会给您提供与优化版本不同的寄存器,但“高水位线”的位置可能在正确的位置……不,我将继续优化;使用中的寄存器数量只有在优化后我才感兴趣(我不想花费大量精力手工复制寄存器缩减,因为如果我没有优化的话,编译器本可以为我完成这项工作)。您是如何理解nvcc-ptx-Xopencc=“-LIST:source=on”命令行的对于基于llvm版本的CUDA@marina.k:是的,但是这个答案写于大约1年前,在CUDA中存在基于LLVM的工具链之前。
$ cuobjdump -sass branching.cubin
code for sm_20
Function : _Z11branchTest0PfS_S_
/*0000*/ /*0x00005de428004404*/ MOV R1, c [0x1] [0x100];
/*0008*/ /*0x94001c042c000000*/ S2R R0, SR_CTAid_X;
/*0010*/ /*0x84009c042c000000*/ S2R R2, SR_Tid_X;
/*0018*/ /*0x10015de218000000*/ MOV32I R5, 0x4;
/*0020*/ /*0x2000dc0320044000*/ IMAD.U32.U32 R3, R0, c [0x0] [0x8], R2;
/*0028*/ /*0x10311c435000c000*/ IMUL.U32.U32.HI R4, R3, 0x4;
/*0030*/ /*0x80319c03200b8000*/ IMAD.U32.U32 R6.CC, R3, R5, c [0x0] [0x20];
/*0038*/ /*0x9041dc4348004000*/ IADD.X R7, R4, c [0x0] [0x24];
/*0040*/ /*0xa0321c03200b8000*/ IMAD.U32.U32 R8.CC, R3, R5, c [0x0] [0x28];
/*0048*/ /*0x00609c8584000000*/ LD.E R2, [R6];
/*0050*/ /*0xb0425c4348004000*/ IADD.X R9, R4, c [0x0] [0x2c];
/*0058*/ /*0xc0329c03200b8000*/ IMAD.U32.U32 R10.CC, R3, R5, c [0x0] [0x30];
/*0060*/ /*0x00801c8584000000*/ LD.E R0, [R8];
/*0068*/ /*0xd042dc4348004000*/ IADD.X R11, R4, c [0x0] [0x34];
/*0070*/ /*0x00201c00081e0000*/ FMNMX R0, R2, R0, !pt;
/*0078*/ /*0x00a01c8594000000*/ ST.E [R10], R0;
/*0080*/ /*0x00001de780000000*/ EXIT;
......................................