如何优化指针间接层

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。

【讨论】:

以上是关于如何优化指针间接层的主要内容,如果未能解决你的问题,请参考以下文章

间接采购品类多,机械制造企业如何破局制胜优化间采管理?

间接采购品类多,机械制造企业如何破局制胜优化间采管理?

有效三角形的个数--二分和双指针

为啥不使用指针数组来优化链表而使用跳过列表呢?

如何告诉 LLVM 它可以优化离店?

四数之和的解决方法--双指针+去重+剪枝