如何优化指针间接层
Posted
技术标签:
【中文标题】如何优化指针间接层【英文标题】:How to optimize the layers of pointer indirection 【发布时间】:2009-09-10 12:18:46 【问题描述】:我正在尝试在重型计算应用程序中优化此类事情:
说我有一个
double d[500][500][500][500];
至少从编译器的角度来看,以下是相当昂贵的
double d[x][y][j][k]
我想告诉编译器它是连续内存,方便计算偏移量。
在我的例子中,
我有这样的事情:
double n=0;
for (int i=0; i < someNumber; i++)
n+=d[x][i][j][k] /*(some other math calculations)*/;
所以我尝试通过将它放在一个单独的函数中来优化它
void func( double*** const restrict dMatrix )
/* and do some calculations herel*/
没有多大帮助:(
对优化有什么建议吗?
编辑
我无法重写代码以使数组成为一维数组。我必须和这个多维野兽一起工作:(
【问题讨论】:
你的数组已经是一维的了。 它是 4 维但连续的。我想告诉编译器它是连续内存,它已经知道了。
至少从编译器的角度来看相当昂贵不太可能 除非您有 512GB 的 RAM,否则您的计算将绑定到如此多的交换,以至于任何微优化都将毫无意义。您唯一能做的就是重新排序内存访问,以便它们是连续的(在您发布的示例中,这意味着迭代最后一个索引 - d[][][][i] 而不是 d[][i] [][]。此外,正如其他人已经指出的那样,这里没有指针间接...... 【参考方案1】:
我怀疑问题不在于偏移量计算,而是实际访问内存。当您声明一个 4 维数组并在除最后一个之外的任何级别访问具有相邻索引的元素时,内存地址实际上彼此相距很远,这会导致大量缓存未命中和显着减速。
【讨论】:
我同意。原始发布者应该能够通过比较循环 i 在 d[x][i][j][k] 上的性能与循环 k 的性能来验证这一点。然后阅读people.redhat.com/drepper/cpumemory.pdf,了解您可能需要了解的有关内存和缓存的所有信息。【参考方案2】:请注意,这是很多(大约 466 GB,如果我的数学是正确的)数据,请注意交换和缓存访问问题。如果您实际上没有使用 500^4 个元素,则需要分析您的应用程序,以查看在性能方面真正消耗您的是“间接”。
【讨论】:
您仍然可以执行 d[500][500][500][500] 并以自己的方式访问它。没有区别。 你的建议和C的假多维数组一模一样。 删除了关于显式一维的建议,因为 a[2][2] 和 a[2 * 2] 是等价的。很抱歉造成混乱。【参考方案3】:C 编译器当然知道内存何时是连续的。你不必告诉它。
【讨论】:
【参考方案4】:正如在别处提到的,内存是连续的,缓慢来自缓存未命中。为了减少这种情况,您要确保(如果可能)您正在迭代相邻元素以获得最大的缓存一致性,而不是在内存中进行大的跳跃。在 C 中,我相信这意味着您最常迭代的值应该是数组的最后一维,而最不常迭代的值应该是第一个维度:请参阅the Wikipedia article。
【讨论】:
【参考方案5】:C 中没有多维数组。所有数组都是一维的,编译器只计算正确的偏移量。这意味着您无法通过自己计算偏移量来使其更快。这是 C 语言的限制。
您可以通过减少缓存未命中的数量来加快速度。 a[0][?][?][?]
可能与a[1][?][?][?]
相差甚远。
【讨论】:
【参考方案6】:您过去能够做的是使用增量指针来加快访问数组的速度。
所以使用一个简单的数组。
char aString[500];
for (int i=0; i<500; i++)
aString[i] = 0; // Array access is really a multiply!
变成
char aString[500];
char *aStringPtr;
for (aStringPtr= &aString[0] ; aStringPtr<&aString[0]+500; aStringPtr++)
*aStringPtr = 0;
它的运行速度大约是第一个示例的两倍。
【讨论】:
为什么它的运行速度是原来的两倍? 我认为这是因为在第二个示例中,您首先增加了一个地址,然后您增加了一个值并将其添加到地址中。 我不认为打开优化时应该有性能差异......【参考方案7】:作为unwind said,您的数组大约是半兆字节。你需要一个足够大的磁盘和一个足够大的页面文件。然后,您可能还需要一个非常大的 RAM。最后,你的缓存大小也很重要,所以你访问元素的顺序会有很大的不同。地址计算会在噪音中。
如果这实际上是一个稀疏数组,你应该这样对待它。事实上,用指针数组组织它可能是一个很好的方法。
事实上,如果以最快的方式将数据简单地加载到该数组中,可能需要数小时。
顺便说一句,我希望您使用的是 64 位机器。 32 位地址只能访问大约 4 GB。
【讨论】:
以上是关于如何优化指针间接层的主要内容,如果未能解决你的问题,请参考以下文章