是否所有具有共享属性的变量都需要在全局子程序中声明?
没有。
您没有显示示例代码、编译命令,也没有确定您正在使用的 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 开始,默认
Tesla-target OpenACC 和 CUDA Fortran 的代码生成和链接模式是 rdc,
可重定位设备代码。
您可以通过指定禁用默认值并启用旧行为和不可重定位代码
以下任何一项:–ta=tesla:nordc、–Mcuda=nordc,或通过指定任何 1.x 计算
能力或任何 Radeon 目标。
因此(禁用)启用此功能的特定选项是:
–Mcuda=(no)rdc
(注意-Mcuda=rdc是默认的,如果你不指定这个选项)
CUDA Fortran 将 Fortran 主机代码与设备代码分开。对于设备代码,CUDA Fortran 编译器进行 CUDA Fortran->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 工具的版本。 (我认为这对未来的问题也是一个很好的建议。)