我正在尝试在繁重的计算应用程序中优化这类内容:
说我有一个
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*/
}
没有多大帮助:(
有关优化它的任何建议吗?
}
修改
我无法重写代码以使数组成为一维的。我必须使用这个多维野兽:(
答案 0 :(得分:14)
我怀疑问题不是偏移计算,而是实际访问内存。当你声明一个4维数组并访问具有相邻索引的任何级别的元素时,除了最后一个之外,内存地址实际上相距很远,这会导致大量缓存未命中和显着减速。
答案 1 :(得分:5)
请注意,这是很多(大约466 GB,如果我的数学是正确的)数据,并且要注意交换和缓存访问问题。如果你实际上没有使用500 ^ 4个元素,你需要对你的应用程序进行概要分析,看它确实是“间接”,这会让你在性能方面付出代价。
答案 2 :(得分:5)
C编译器当然知道内存何时连续。你不必告诉它。
答案 3 :(得分:4)
正如其他地方所提到的,无论如何内存是连续的,缓慢来自缓存未命中。要减少这种情况,您需要确保(如果可能)您在相邻元素上进行迭代以获得最大的缓存一致性,而不是在内存中进行大量跳转。在C中我相信这意味着你最常用的迭代值应该是数组的最后一个维度,最不常见的迭代应该是第一个维度:参见the Wikipedia article。
答案 4 :(得分:3)
C中没有多维数组。所有数组都是1维的,编译器只计算正确的偏移量。这意味着您无法通过自己计算偏移量来加快速度。这是C语言的限制。
您可以通过减少缓存未命中量来加快速度。 a[0][?][?][?]
可能远离a[1][?][?][?]
。
答案 5 :(得分:1)
您以前能够做的事情就是使用增量指针来加速访问阵列。
所以使用一个简单的数组。
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;
这比第一个例子快两倍。
答案 6 :(得分:1)
作为unwind said,你的数组大约是半TB。你需要一个足够大的磁盘和一个足够大的页面文件。然后,您可能还需要一个非常大的RAM。最后,您的缓存大小也很重要,因此您访问元素的顺序将产生巨大的差异。地址计算将在噪声中。
如果这实际上是一个稀疏数组,你应该这样对待它。实际上,使用指针数组组织它可能是一种很好的方法。
实际上,只需将数据加载到该数组中,如果以最快的方式完成,可能需要数小时。
顺便说一句,我希望你在64位机器上。 32位地址只能访问大约4 GB。