2

我将竭尽全力尝试将经常访问的数据存储在tile_static内存中,以利用随之而来的无限性能必杀技。

但是,我刚刚读到只有某些硬件/驱动程序实际上可以动态索引 tile_static 数组,并且该操作无论如何都可能溢出到全局内存。

在一个理想的世界里,我只是做它并配置文件,但事实证明这是一项重大操作,我想知道我是否在这里浪费时间:

tile_static int staticArray[128];
int resultFast = staticArray[0]; // this is super fast

// but what about this:   
i = // dynamically derived value!
int resultNotSoFast = staticArray[i]; // is this faster than getting it from global memory?

如何确定我的 GPU/驱动程序是否支持静态数组的动态索引?

4

1 回答 1

2

本地内存的动态索引

所以我对此进行了一些挖掘,因为我也想了解这一点。如果您指的是本地内存的动态索引,则不是 tile_static(或用 CUDA 的说法,“共享内存”)。在上面的示例中,staticArray应声明为:

int staticArray[128]; // not tile_static

这不能被动态索引,因为一个数组int staticArray[128]实际上存储为 128 个寄存器并且这些不能被动态访问。无论如何分配这样的大型数组都是有问题的,因为它会占用大量的寄存器,而这些寄存器是 GPU 上的有限资源。每个线程使用过多的寄存器,您的应用程序将无法使用所有可用的并行性,因为一些可用线程将停止等待寄存器可用。

在 C++ AMP 的情况下,我什至不确定 DX11 提供的抽象级别是否会使这有点无关紧要。我不是 DX11 的专家知道。

这里有一个很好的解释,在 CUDA 内核中,如何将数组存储在“本地线程内存”中?

银行冲突

平铺静态存储器被划分为称为银行的多个模块。Tile 静态内存通常由 16、32 或 64 个 bank 组成,每个 bank 为 32 位宽。这是特定于特定 GPU 硬件的,将来可能会发生变化。平铺静态存储器在这些存储体中交错。这意味着对于使用 32 个 bank 实现的 tile 静态内存的 GPU,如果 arr 是一个数组 <float, 1>,那么 arr[1] 和 arr[33] 在同一个 bank 中,因为每个 float 占用一个 32 位 bank地点。这是处理银行冲突时要理解的关键点。

每个银行每个周期可以服务一个地址。为了获得最佳性能,warp 中的线程应该访问不同 bank 中的数据,或者全部读取单个 bank 中的相同数据,这种模式通常由硬件优化。当遵循这些访问模式时,您的应用程序可以最大化可用的切片静态内存带宽。在最坏的情况下,同一个 warp 中的多个线程从同一个 bank 访问数据。这会导致这些访问被序列化,这可能会导致性能显着下降。

我认为混淆的关键点可能是(基于您的其他一些问题)是内存库是 32 位宽,但负责访问该库中的所有内存,这将是 1/16、1/32或总平铺静态内存的 1/64。

您可以在此处阅读有关银行冲突的更多信息。什么是银行冲突?(做 Cuda/OpenCL 编程)

于 2013-11-12T05:07:43.143 回答