在 Cuda 中使用最大共享内存

use*_*436 1 cuda

我无法使用超过 48K 的共享内存(在 V100、Cuda 10.2 上)

我打电话

cudaFuncSetAttribute(my_kernel,
                     cudaFuncAttributePreferredSharedMemoryCarveout,
                     cudaSharedmemCarveoutMaxShared);
Run Code Online (Sandbox Code Playgroud)

my_kernel第一次启动之前。

我在内部使用启动边界和动态共享内存my_kernel

__global__
void __launch_bounds__(768, 1)
my_kernel(...)
{
    extern __shared__ float2 sh[];
    ...
}
Run Code Online (Sandbox Code Playgroud)

内核是这样调用的:

dim3 blk(32, 24); // 768 threads as in launch_bounds.

my_kernel<<<grd, blk, 64 * 1024, my_stream>>>( ... );
Run Code Online (Sandbox Code Playgroud)

cudaGetLastError()内核调用返回后cudaErrorInvalidValue

如果我使用 <= 48 K 的共享内存(例如,my_kernel<<<grd, blk, 48 * 1024, my_stream>>>),它就可以工作。

编译标志是:

nvcc -std=c++14 -gencode arch=compute_70,code=sm_70 -Xptxas -v,-dlcm=cg

我错过了什么?

Rob*_*lla 8

这里

计算能力 7.x 设备允许单个线程块寻址共享内存的全部容量:Volta 上为 96 KB,图灵上为 64 KB。依赖每块超过 48 KB 共享内存分配的内核是特定于体系结构的,因此它们必须使用动态共享内存(而不是静态大小的数组),并且需要使用 cudaFuncSetAttribute() 进行显式选择,如下所示:

cudaFuncSetAttribute(my_kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, 98304);
Run Code Online (Sandbox Code Playgroud)

当我将该行添加到您显示的代码中时,无效值错误就会消失。对于图灵设备,您可能希望将该数字从 98304 更改为 65536。当然,对于您的示例,65536 也足够了,尽管如问题标题所述,还不足以使用 volta 上可用的最大值。

类似的方式,Ampere 设备上的内核应该能够使用最多 160KB 的共享内存 (cc 8.0) 或 100KB (cc 8.6),动态分配,使用上述选择加入机制,编号 98304 更改为 163840(对于例如 cc 8.0)或 102400(对于 cc 8.6)。

请注意,以上涵盖了 Volta (7.0) Turing (7.5) 和 Ampere (8.x) 情况。具有 7.x 之前计算能力的 GPU 无法处理每个线程块超过 48KB 的空间。在某些情况下,这些 GPU 的每个多处理器可能有更多的共享内存,但这样做是为了在某些线程块配置中允许更大的占用。程序员不能使用超过 48KB 的每个线程块。

尽管它与此处提供的代码无关(它已经在使用动态共享内存分配),但请注意摘录的文档引用,在支持它的设备上使用超过 48KB 的共享内存需要两件事:

  1. 上面已经描述的选择加入机制
  2. 动态而不是静态共享存储器分配在内核代码。

动态示例:

extern __shared__ int shared_mem[];
Run Code Online (Sandbox Code Playgroud)

静态示例:

__shared__ int shared_mem[1024];
Run Code Online (Sandbox Code Playgroud)

动态分配的共享内存还需要在内核启动配置参数中传递一个大小(问题中给出了一个示例)。