我一直在编写一些基本的CUDA Fortran代码。我希望能够确定我的程序每个线程块使用的共享内存量(用于占用率计算)。我一直在编译-Mcuda = ptxinfo以期找到这些信息。编译输出以
结尾ptxas info:device_procedures_main_kernel_的函数属性 432字节堆栈帧,1128字节溢出存储,604字节溢出加载 ptxas info:使用了63个寄存器,96个字节的smem,320个字节的cmem [0]
这是输出中唯一提到smem的地方。全局子例程main_kernel中有一个具有shared属性的数组。如果我删除共享属性,那么我得到
ptxas info:device_procedures_main_kernel_的函数属性 432字节堆栈帧,1124字节溢出存储,532字节溢出加载 ptxas info:使用了63个寄存器,320字节cmem [0]
涂抹已经消失。似乎只计算main_kernel中的共享内存:我的代码中的设备子例程使用带有共享属性的变量,但这些似乎没有在输出中提及,例如设备子例程evalfuncs包含共享变量声明但相关输出是< / p>
ptxas info:device_procedures_evalfuncs_的函数属性 504字节堆栈帧,1140字节溢出存储,508字节溢出负载
是否需要在全局子例程中声明具有shared属性的所有变量?
答案 0 :(得分:1)
是否需要在全局子例程中声明具有shared属性的所有变量?
没有
您没有显示示例代码,编译命令,也没有确定您正在使用的PGI编译器工具的版本。但是,我能想到的最可能的解释是,从PGI 14.x开始,默认的CUDA编译选项是生成可重定位的设备代码。这在the current PGI release notes的第2.2.3节中有记录:
2.2.3。可重定位设备代码 rdc选项可用于指定生成的-ta = tesla和-Mcuda标志 可重定位的设备代码。从Linux上的PGI 14.1和Windows上的PGI 14.2开始,默认 特斯拉目标OpenACC和CUDA Fortran的代码生成和链接模式是rdc, 可重定位的设备代码。 您可以通过指定禁用默认值并启用旧行为和不可重定位代码 以下任何一项:-ta = tesla:nordc,-Mcuda = nordc,或指定任何1.x计算 能力或任何Radeon目标。
因此启用此功能的特定选项是:
–Mcuda=(no)rdc
(请注意-Mcuda=rdc
是默认值,如果您未指定此选项)
CUDA Fortran将Fortran主机代码与设备代码分开。对于设备代码,CUDA Fortran编译器执行CUDA Fortran-&gt; CUDA C转换,并将自动生成的CUDA C代码传递给CUDA C编译器。因此,rdc
和ptxinfo
等开关的行为和期望分别来自底层等效CUDA编译器选项(-rdc=true
和-Xptxas -v
)的行为。
当编译CUDA设备代码时没有rdc
选项时,编译器通常会尝试内核从内核调用的设备(子)例程到主内核代码中。因此,当编译器生成ptxinfo
时,它可以在编译(ptx程序集)内核代码时确定所有资源需求(例如共享内存,寄存器等)。
但是,当指定rdc
选项时,编译器可以(取决于一些其他开关和函数属性)将设备子例程作为具有其自己的入口点的单独可调用例程(即,不内联)。在这种情况下,当设备编译器正在编译内核代码时,对设备子例程的调用看起来就像一个调用指令,并且编译器(此时)不能看到设备子例程的资源使用要求。这并不意味着编译序列存在潜在的缺陷。它只是意味着ptxinfo
机制无法在那个时间点准确地汇总内核的资源需求及其所有的子程序。
在ptxinfo
模式下编译该子例程时,rdc
输出也不会声明设备子例程使用的共享内存总量。
如果您关闭rdc模式:
–Mcuda=nordc
我相信你会看到内核使用的共享内存及其所有被调用子程序的准确计算,给出一些警告,其中一个是编译器能够成功内联你的被调用子程序(很可能,并且会计应该仍然有效,即使它不能)另一个是你正在使用内核加上同一文件中的所有被调用的子程序(即翻译单元)。如果您的内核以不同的翻译单元调用设备子例程,则rdc
选项是使其工作的唯一方法。
在运行时,仍然会为您的代码正确分配共享内存(假设您没有违反可用的共享内存总量)。您还可以使用nvvp or nvprof等分析器,通过分析代码来准确读取内核使用的共享内存。
如果此解释没有描述您所看到的内容,我建议您提供完整的示例代码,以及您正在使用的确切编译命令,以及您正在使用的PGI工具的版本。 (我认为这对未来的问题也是一个很好的建议。)