自从我开始研究我正在使用的实际代码之后,这就是我正在努力解决的问题。 我的顾问在过去的十年里写过这篇文章,并且在某些时候,我们通常存储在矩阵或张量中的股票价值。
实际上,我们使用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 +。 ..例如)。
答案 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优化。