Fortran ndarray与n * 1d阵列的效率

时间:2016-04-28 15:54:28

标签: arrays fortran hpc

自从我开始研究我正在使用的实际代码之后,这就是我正在努力解决的问题。 我的顾问在过去的十年里写过这篇文章,并且在某些时候,我们通常存储在矩阵或张量中的股票价值。

实际上,我们使用Virial定理(来自分子动力学模拟)计算六个独立组合物的矩阵,并且他有习惯在每个记录步骤存储6 * 1D阵列,每个值一个,即xy(n) ,xz(n)yz(n)... n是记录数。

我假设单个数组s(n,3,3)可能更有效,因为值将彼此更紧密地存储(xy(n)和xz(n)没有理由并排存储在内存中)并减少有关内存损坏或内存访问错误的错误。我试着在实验室里讨论它,但最终没人关心,这只是一个假设。

如果代码中的所有内容都没有像那样存储,那么这就不会对我产生错误。每个3d数量都存储在3个不同的数组中,而不是1个。对于代码的性能,这对我来说感觉很奇怪。

对于长计算和大数据量,它们的效果是否相同?我决定在解决由于错误的内存访问导致的错误之后发布这里,其中一个因为我发现代码更易读,数据更容易计算(s = s + ...而不是六行xy = xy +。 ..例如)。

2 个答案:

答案 0 :(得分:2)

列彼此靠近的事实并不是很重要,尤其是在前导维n很大的情况下。您的CPU有多个预取流,可以在不同列的不同数组中同时预取。

如果您在可分配A(n,3,3)的数组A中进行某些随机访问,则在编译时不知道这些维度。因此,随机元素A(i,j,k)的地址将为address_of(A(1,1,1)) + i + (j-1)*n + (k-1)*3*n,并且必须在每次对阵列进行随机访问时执行时计算。地址的计算涉及3个整数乘法(每个3个CPU周期)和至少3个加法(每个1个周期)。但是,编译器可以使用相对地址来优化常规访问(可预测)。

如果你有不同的1索引数组,地址的计算只涉及一个整数加法(1个循环),因此当使用单个3索引数组时,每次访问都会产生至少11个周期的性能损失。

此外,如果你有9个不同的数组,它们中的每一个都可以在缓存行边界上对齐,而你将被迫在行的末尾使用填充来确保单个数组的这种行为。

所以我想说在A(n,3,3)的特定情况下,因为最后两个索引很小并且在编译时已知,所以你可以安全地将9个不同的数组转换为潜在的获得一些表现。

请注意,如果您经常以随机顺序使用相同索引i的9个数组的数据,则将数据重新组织为A(3,3,n)将使您的性能明显提高。如果a是双精度,如果A(4,4,n)在64字节边界上对齐,A可能会更好,因为每个A(1,1,i)将位于缓存行的第1个位置。< / p>

答案 1 :(得分:1)

假设您总是沿n循环,并且每个循环内部需要访问矩阵中的所有组件,存储像s(6,n)s(3,3,n)这样的数组将受益于{{3} }。

do i=1,n
   ! do some calculation with s(:,i)
enddo

然而,如果你的内圈看起来像这样

resultarray(i)=xx(i)+yy(i)+zz(i)+2*(xy(i)+yz(i)+xz(i))

不要更改数组布局,因为您可能会中断cache optimization优化。