【发布时间】:2012-06-15 21:40:46
【问题描述】:
首先我需要描述我正在使用 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”背后的人的一篇论文中),这是什么意思?
感谢您的任何回答。请随时在 cmets 部分提出任何问题。
【问题讨论】:
-
感谢您如此清楚地陈述您的问题。您是否在 CUDA 分析器中运行过您的程序? Compute Visual Profiler 将分析您的程序并生成一组建议。有哪些建议?每个线程是否用于不同的单元格?您是否尝试过确定 warp 生成哪种内存访问模式?
-
您是否阅读过this paper 的 CUDA 中 3D 高阶有限差分方案,并查看过 these slides(来自第 25 页)?
-
罗杰,我还没有通过 CUDA 分析器运行它,但我会这样做 - 感谢您的建议。没有线程在同一时间步骤中写入同一个单元格(我认为这就是您要问的?)。如果它们在多维数据集中彼此相邻,则不同线程会巧合地读取数组中的位置。每个 warp 的内存访问模式是我没有注意的。我现在会在听到这些答案中提到它之后。谢谢。
-
talonmies,感谢您的链接!我还没有看到那些。有没有一种简单的方法可以找到这样有用的、更具学术性的论文?我现在刚刚有时间看一眼,但这些肯定会有用。
标签: optimization memory cuda gpu