mgi*_*son 5 performance fortran
我有一个"蒙面数组",我想添加到另一个数组 - 换句话说,我有3个数组A,B和mask.我的问题是什么是最有效的(在执行时间方面)存储掩码的方式(作为逻辑数组,作为1和0的真实数组)?
编辑
这是一个你可以玩的玩具程序(如果你有mpif77):
program main
implicit None
include 'mpif.h'
integer, parameter :: ntry=10000
integer, parameter :: asize=1000000
real,dimension(asize) :: A,B,maskr
logical,dimension(asize) :: mask
real*8 :: dd,dt,dtave,dtbest
integer i
do i=1,asize
maskr(i)=mod(i,2)
mask(i)=.False.
if(mod(i,2).eq.0) mask(i)=.True.
enddo
A=1.0; B=1.0
dtbest=1d33
dtave=0.0
do i=1,ntry
dt=mpi_wtime()
call add_arrays_logical(asize,A,B,mask)
dt=mpi_wtime()-dt
dtbest=min(dt,dtbest)
dtave=dtave+dt
enddo
print*,"==== logical ==="
print*,"Average",dtave/ntry
print*,"Best",dtbest
A=1.0; B=1.0
dtbest=1d33
dtave=0.0
do i=1,ntry
dt=mpi_wtime()
call add_arrays_real(asize,A,B,maskr)
dt=mpi_wtime()-dt
dtbest=min(dt,dtbest)
dtave=dtave+dt
enddo
print*,"==== Real ==="
print*,"Average",dtave/ntry
print*,"Best",dtbest
A=1.0; B=1.0
dtbest=1d33
dtave=0.0
do i=1,ntry
dt=mpi_wtime()
where(mask) A=A+B
dt=mpi_wtime()-dt
dtbest=min(dt,dtbest)
dtave=dtave+dt
enddo
print*,"==== Where ===="
print*,"Average",dtave/ntry
print*,"Best",dtbest
end
subroutine add_arrays_logical(n,A,B,mask)
integer n
real A(n),B(n)
logical mask(n)
do i=1,n
if(mask(i))then
A(i)=A(i)+B(i)
endif
enddo
end
subroutine add_arrays_real(n,A,B,mask)
integer n
real A(n),B(n),mask(n)
do i=1,n
A(i)=A(i)+mask(i)*B(i)
enddo
end
Run Code Online (Sandbox Code Playgroud)
我的结果:
(gfortran -O2)
==== logical ===
Average 1.52590200901031483E-003
Best 1.48987770080566406E-003
==== Real ===
Average 1.78022863864898680E-003
Best 1.74498558044433594E-003
==== Where ====
Average 1.48216445446014400E-003
Best 1.44505500793457031E-003
Run Code Online (Sandbox Code Playgroud)
(gfortran -O3 -funroll-loops -ffast-math)
==== logical ===
Average 1.47997992038726811E-003
Best 1.44982337951660156E-003
==== Real ===
Average 1.40655457973480223E-003
Best 1.37186050415039063E-003
==== Where ====
Average 1.48403010368347165E-003
Best 1.45006179809570313E-003
Run Code Online (Sandbox Code Playgroud)
(pfg90 -fast) - 在一台很旧的机器上
==== logical ===
Average 5.4871437072753909E-003
Best 5.4519176483154297E-003
==== Real ===
Average 4.6096980571746831E-003
Best 4.5847892761230469E-003
==== Where ====
Average 5.3572671413421634E-003
Best 5.3288936614990234E-003
Run Code Online (Sandbox Code Playgroud)
(pfg90 -O2) - 在一台很旧的机器上
==== logical ===
Average 5.4929971456527714E-003
Best 5.4569244384765625E-003
==== Real ===
Average 5.5974062204360965E-003
Best 5.5701732635498047E-003
==== Where ====
Average 5.3811835527420044E-003
Best 5.3341388702392578E-003
Run Code Online (Sandbox Code Playgroud)
当然,有一些事情可以影响这一点 - 例如编译器对循环进行矢量化的能力 - 那么是否有关于应该如何实现这样的事情的经验法则?
为什么不用"哪里"?
where (mask) A = A + B
Run Code Online (Sandbox Code Playgroud)
可能使用面罩是最快的,但唯一可以确定的方法是测量.
如果你所说的触发器指的是浮点运算,那么第一个选项显然更好,因为在这种情况下,每个循环迭代有 1 次触发器,其中 mask(n) == .true。。而对于第二个选项,无论 mask(n) 的值如何,每个循环迭代都有 2 次触发器。
OTOH,如果您有兴趣最大限度地减少执行此函数所花费的时间,为什么不在数据上尝试这两个版本并测试哪个版本更快?
您可能还想测试使用 Fortran 90+ WHERE 构造的版本
where(mask) A = A + B
Run Code Online (Sandbox Code Playgroud)