我有一个简单的Fortran程序,其中主要组件是一个计算点积的4核OpenMP部分
OMP_NUM_THREADS=4
...
Do 30 k=1,lines
co(k)=0
si(k)=0
co_temp=0
si_temp=0
!$OMP PARALLEL DO PRIVATE(dotprod,Qcur) REDUCTION(+:co_temp,si_temp)
Do 40 i=1,ION_COUNT
dotprod=(rx(k)*x(i)+ry(k)*y(i)+rz(k)*z(i))*((2*3.1415926535)/l)
co_temp=co_temp+COS(dotprod)*26 !Qcur/Qavg
si_temp=si_temp+SIN(dotprod)*26 !Qcur/Qavg
40 continue
!$OMP END PARALLEL DO
co(k)=co_temp
si(k)=si_temp
q(k)= ( co(k),-si(k) )
s(k)= s(k) +( q(k) * conjg(q(k)) )
r(k)=r(k)+q(k)
30 continue
我对Fortran或其优化并不熟悉。我正在使用xlf90_r文件-qsmp = omp 编译。当使用4个核心时,我只获得大约1/2的加速,其他使用C的人在进行相同的计算时获得了几乎完美的1/4加速。无论OMP循环是30还是40,我都会得到大约相同的时间。另外,我在循环30和整个程序周围时间,这个循环需要99.x%的时间,所以我很确定这一点是瓶颈。我在这个部分做过的任何令人震惊的缓慢错误,任何人都看到了吗?
答案 0 :(得分:1)
快速浏览一下代码,看起来外循环的每次迭代都是独立的。我会说并行循环不是内循环。
OMP_NUM_THREADS=4
...
!$OMP PARALLEL DO PRIVATE(dotprod,Qcur,co_temp,si_temp)
Do 30 k=1,lines
co(k)=0
si(k)=0
co_temp=0
si_temp=0
Do 40 i=1,ION_COUNT
dotprod=(rx(k)*x(i)+ry(k)*y(i)+rz(k)*z(i))*((2*3.1415926535)/l)
co_temp=co_temp+COS(dotprod)*26 !Qcur/Qavg
si_temp=si_temp+SIN(dotprod)*26 !Qcur/Qavg
40 continue
co(k)=co_temp
si(k)=si_temp
q(k)= ( co(k),-si(k) )
s(k)= s(k) +( q(k) * conjg(q(k)) )
r(k)=r(k)+q(k)
30 continue
!$OMP END PARALLEL DO
答案 1 :(得分:0)
可能是在更好的处理器上执行了C测试,并且您正在使用双核。如果为true,则我预计不会有比2更好的速度。
如@ user1139069所建议,您应该并行化k上的第一个循环,以避免浪费i倍的时间来创建线程组。
我还认为您可能有一个错误的共享问题,因为线程可能在数组的neibourgh元素上工作。为了避免这种情况,我建议将循环40替换为
Do 40 ii=1,ION_COUNT/nCacheSize
DO 41 i_leap=1,nCacheSize
i=(ii-1)*nCacheSize+i_leap
...
41 CONTINUE
40 CONTINUE
这样可以强制线程在不同的内存缓存行上工作。我认为这将加快您的代码。
请注意,例如应通过parameter(nCacheSize=8)
将nCacheSize声明为常量。您应该输入的数字取决于您的机器和变量种类。因此,请尝试使用2、4、8、16、32来找到最佳值。
答案 2 :(得分:-1)
由于我不太明白的原因,将OMP置于外环上(非常轻微)。我无法弄清楚为什么它没有完美并行化。但是,我能够明显加快这段代码的速度。我将2 * l * pi变量更改为单个变量且仅为8位数。我也删掉了* 26,因为我可以简单地将最终值乘以26或26 ^ 2。我得到了大约30%的加速。不会猜到的,但你去了。