2012-08-13 96 views
3

一个循环我有这样的结构的环矢量化其访问非连续的存储器位置

参考:Maxwell Code Example

do z=1,zend 
    do y=1,yend 
     do x=1,xend 
      k=arr(x,y,z) 
      do while(k.ne.0) 
       ix=fooX(k) 
       iy=fooY(k) 
       iz=fooZ(k) 
       x1=x(ix ,iy ,iz) 
       x2=x(ix+1,iy ,iz) 
       x3=x(ix ,iy+1,iz) 
       x4=x(ix+1,iy+1,iz) 
       x5=x(ix ,iy ,iz+1) 
       x6=x(ix+1,iy ,iz+1) 
       x7=x(ix ,iy+1,iz+1) 
       x8=x(ix+1,iy+1,iz+1) 

       y1=y(ix ,iy ,iz) 
       y2=y(ix+1,iy ,iz) 
       y3=y(ix ,iy+1,iz) 
       y4=y(ix+1,iy+1,iz) 
       y5=y(ix ,iy ,iz+1) 
       y6=y(ix+1,iy ,iz+1) 
       y7=y(ix ,iy+1,iz+1) 
       y8=y(ix+1,iy+1,iz+1) 

       z1=z(ix ,iy ,iz) 
       z2=z(ix+1,iy ,iz) 
       z3=z(ix ,iy+1,iz) 
       z4=z(ix+1,iy+1,iz) 
       z5=z(ix ,iy ,iz+1) 
       z6=z(ix+1,iy ,iz+1) 
       z7=z(ix ,iy+1,iz+1) 
       z8=z(ix+1,iy+1,iz+1) 
       sumX+=x1+x2+..x8 
       sumY+=y1+y2+..y8 
       sumZ+=z1+z2+..z8 

       k=linkArr(k) 
      enddo 
     enddo 
    enddo 
enddo 

X1到X8是长方体的8个角。向量化代码有三个挑战。一个是8个数组元素在内存中不连续。其次是固有的while循环结构以及链接的List访问。第三,从fooX,fooY,fooZ返回的ix,iy,iz的值不是连续的。所以循环的每次迭代都有一组完全不同的ix,iy,iz。所以即使在迭代中,内存访问也是分散的。 我尝试以下方法:1。 展开的3级DO循环为:

do z=1,zend 
    do y=1,yend 
     do x=1,xend 
      if(arr(x,y,z).NE.0) then 
       kArr(indx)=arr(x,y,z) 
       DO WHILE (kArr(indx).NE.0) 
        indx = indx + 1 
        kArr(indx)=linkArr(kArr(indx-1)) 
       ENDDO 
      endif 
     enddo 
    enddo 
enddo 

有了这个,我已经摆脱了while循环结构的,现在我能够在卡尔运行一个大循环其中我组8个元素(说我的VPU一次可以容纳8组数据)。它没有提高性能。如果有人感兴趣,我可以发布这些细节。我需要关于如何优化此代码的建议。我试过的另一个选择是将x,y,z数据组合到一个单独的数组中,这样当我计算x1时,z1也会在相邻的存储单元中。

+1

你没有告诉我们足够的。值x1 ... x8,y1..y8,z1..z8发生了什么?代码呈现的方式现在可以全部消除,并且您没有计算问题,因为您的循环体即空。 – 2012-08-13 08:50:50

+0

@IraBaxter:编辑了代码片段。感谢您指出或我的循环执行将毫无意义。 – arunmoezhi 2012-08-13 09:14:56

+0

如果你真的想提高性能,那么你应该考虑使用SSE内在函数。 “希望”编译器能够生成快速/向量化的代码肯定会导致失望。我总是假定编译器生成糟糕的代码,并且时间关键部分需要用ASM或内部函数编写(这种假设通常是正确的)。 – BitBank 2012-08-16 01:19:23

回答

2

while while循环正在杀死你。在类似的情况在几年前,我在性能上略有改善做这样的事情:

! at top of your code, introduce: 
integer :: special_index 
integer :: ix(1000), iy(1000), iz(1000) !promoting scalars to arrays. 
             ! make as big as possibly needed. 

! code as usual until you get to your loops, then 

! first, make lookup table 
special_index=0 
do z=1,zend 
    do y=1,yend 
    do x=1,xend 
     k=arr(x,y,z) 
     do while(k.ne.0) 
     special_index=special_index+1 
     ix(special_index)=fooX(k) 
     iy(special_index)=fooY(k) 
     iz(special_index)=fooZ(k) 
     k=linkArr(k) 
     enddo 
    enddo 
    enddo 
endoo 
! and now we do the calculation, loop over lookup table: 
do n=1,special_index 
    x1=x(ix(n) ,iy(n) ,iz(n)) 
    x2=x(ix(n)+1,iy(n) ,iz(n)) 
    x3=x(ix(n) ,iy(n)+1,iz(n)) 
    etc. 
enddo 

就像我说的,这帮助我在几年前。你的旅费可能会改变。第一个循环仍然不会矢量化,但第二个循环可能会提供更好的性能。

+0

我已经试过了。第二个循环得到了矢量化,并导致性能下降。它慢了3倍。 – arunmoezhi 2012-09-19 22:51:44

+0

我并不完全相信你会从中得到很大的提升,但我很惊讶它实际上降低了表现,并且受到了很大的影响。呃,好吧。我给了它一个镜头。如果有其他事情发生在我身上,我会让你知道的。祝你好运。 – 2012-09-19 23:52:00

+0

感谢您的时间和帮助。 – arunmoezhi 2012-09-20 00:37:20