2

首先,我需要描述我正在使用 CUDA 的应用程序。

这是一个相当标准的热流模拟。我采用一堆 3D 浮点数组(可变温度和热量,以及恒定 k 值、sar_value 和其他一些)并将它们复制到分配在 GPU 上的线性数组中。所有这些都在全局内存中。

接下来,我启动一个计算热流的核函数。我使用 2 维块构造和 1D 线程构造启动这个内核。该块对应于我们正在对其执行热流计算的模拟立方体的 x 和 y 坐标。线程对应于 z 坐标。所有线程/块坐标都是总立方体大小的倍数,以最大限度地提高性能。

接下来,在每个单元格上,我执行冗长的计算。所有的数组都是线性的,所以我准备了偏移量来计算 z、y 和 x 方向上的下一个单元格。大部分空间局部性发生在写入/读取内存中,因此纹理内存不是一个选项。总共,每次计算有 2 次写入大数组,6 次常量大数组读取(如在 300 MB 浮点数组的一个索引中),8 次可变大数组读取,6 次常量小数组读取(如 300 的立方根)兆)。所有这些都发生在两行代码中。我没有将同一内存位置的多次读取作为单独的读取包括在内,因为我假设它们已被缓存。

其次,我将描述我通过这个计算得到的结果。

我在 Tesla C1060 上获得了大约 2.25 亿个细胞/秒。在大型数据集(40-6000 万个单元)上,我发现每个单元启动 1 个线程与每 2 个单元启动 1 个线程与每 4 个单元启动 1 个线程之间的性能没有差异,一直到某个点。这向我表明,计算的限制因素是实际的内存获取。当我为多个块启动 1 个线程时,我减轻了系统上的内存过载,因此每次计算都更快,尽管计算的并行性较低 - 净没有性能提升,+ 或 - 一个或两个百分比。

我尝试了什么?我尝试将我在空间上最局部的常量大数组放入 3D 纹理内存 - 灾难性的 3-4 倍减速。我认为常量内存是不可行的,因为数据访问模式使得大数组中的每个索引只被访问一次或两次,此外,我不一定知道编译时输入的大小。我在大型常量数组上尝试过一维纹理;也不好。

我还能做些什么吗?此外,如果您可以看到每秒获取的字节数(2.25 亿/秒 * 100 左右字节),它正好在 Tesla C1060 的内存带宽的大约 10 倍之内。为什么内存是限制因素?我在某处看到有人“平铺”他们的数据集以进行类似的热流计算(我认为在“Mint”背后的人的论文中),这是什么意思?

谢谢你的任何答案。请随时在评论部分提出任何问题。

4

1 回答 1

3

接下来,在每个单元格上,我执行冗长的计算。所有的数组都是线性的,所以我准备了偏移量来计算 z、y 和 x 方向上的下一个单元格。

仔细考虑你在数组中获得的访问模式类型,在一个扭曲中。warp 中的线程应该以“行优先”的顺序访问连续的地址。如果您碰巧遇到了“列主要”访问模式之类的东西,那么您的代码将发出比必要更多的内存事务。

CUDA 编程指南 4.2 中的第 2.2 节,线程层次结构描述了线程索引如何映射到线程 ID。检查以查看连续的线程 ID 是否也导致(至少在很大程度上)连续的数组索引。

于 2012-06-13T03:11:34.753 回答