【发布时间】:2013-05-21 14:19:37
【问题描述】:
我正在开发一个利用卡上所有可用 RAM 的 CUDA 应用程序,并试图找出减少缓存未命中的不同方法。
问题域由一个大的 2 维或 3 维网格组成,具体取决于所解决问题的类型。 (对于那些感兴趣的人,它是一个 FDTD 模拟器)。每个元素都依赖于“平行”数组(即另一个维度几乎相同的数组)中的两个或四个元素,因此内核必须访问三个或六个不同的数组。
问题
*希望这不是“过于本地化”。随意编辑问题
三个数组之间的关系可以可视化为(为平庸的ASCII艺术道歉)
A[0,0] -C[0,0]- A ---- C ---- A ---- C ---- A
| | | |
| | | |
B[0,0] B B B
| | | |
| | | |
A ---- C ---- A ---- C ---- A ---- C ---- A
| | | |
| | | |
B B B B
| | | |
| | | |
A ---- C ---- A ---- C ---- A ---- C ---- A
| | | |
| | | |
B B B B[3,2]
| | | |
| | | |
A ---- C ---- A ---- C ---- A ---- C ---- A[3,3]
[2,3]
由线连接的项目是耦合的。如上所示,A[] 依赖于B[] 和C[],而B[] 仅依赖于A[],C[] 也是如此。所有A[] 在第一个内核中更新,所有B[] 和C[] 在第二遍中更新。
如果我将这些数组声明为简单的 2D 数组,我将获得跨步内存访问。对于非常大的域大小(上面网格中的 3x3 +- 1),这会导致占用率和性能不足。
所以,我想到了以 Z 顺序曲线重新排列数组布局:
此外,将它们交错到一个数组中是相当简单的,这应该会提高提取性能,因为(取决于交错顺序)给定单元格更新所需的至少一半元素将彼此接近。但是,我不清楚 GPU 在访问多个数组时是否使用多个数据指针。如果是这样,这种想象中的好处实际上可能是一个障碍。
问题
我听说 NVidia 在使用纹理内存或 cudaArray 时会在后台自动执行此操作。如果不是这种情况,我是否应该期望在跨越大跨度时增加延迟(当 Z 曲线在高细分级别从右上角到左下角时)以消除较小网格中局部性的好处?
将网格划分为可以放入共享内存的更小块肯定会有所帮助,而 Z 顺序使这变得相当简单。我应该有一个单独的内核通道来更新块之间的边界吗?与我预期的节省相比,启动另一个内核的开销会很大吗?
使用 2D 与 1D 阵列有什么真正的好处吗?我希望内存是线性的,但不确定 CUDA 文献中经常使用的 2D 内存布局隐喻是否有任何实际意义。
哇 - 很长的问题。感谢您阅读并回答所有这些内容。
【问题讨论】:
-
据我了解,您在
A、B和C之间存在依赖关系,如下所示:A[i] = B[i] op C[i]、B[i] = op A[i]、C[i] = op A[i]?一些代码也会有所帮助。
标签: caching cuda space-filling-curve