Optimization 在fortran中访问虚拟变量会阻止优化吗?
我试图优化一些fortran代码,并注意到一些我试图理解的令人惊讶的行为。progb的运行速度大约是proga的3到4倍。唯一的区别是progb中的赋值“d=2”而不是proga中的“d=b”,所以很简单,它们应该是等价的:Optimization 在fortran中访问虚拟变量会阻止优化吗?,optimization,fortran,Optimization,Fortran,我试图优化一些fortran代码,并注意到一些我试图理解的令人惊讶的行为。progb的运行速度大约是proga的3到4倍。唯一的区别是progb中的赋值“d=2”而不是proga中的“d=b”,所以很简单,它们应该是等价的: program proga implicit none call hist(2) stop end subroutine hist(b) implicit none integer, intent(in):: b integer
program proga
implicit none
call hist(2)
stop
end
subroutine hist(b)
implicit none
integer, intent(in):: b
integer d,i,p(200000000)
d = b
do i=1,200000000
p(i) = i/d
end do
write(*,*) p(1)
end
program progb
implicit none
call hist(2)
stop
end
subroutine hist(b)
implicit none
integer, intent(in):: b
integer d,i,p(200000000)
d = 2
do i=1,200000000
p(i) = i/d
end do
write(*,*) p(1)
end
我用“gfortran proga.f-O3”编译,同样也用progb编译。这发生在Debian上的gcc版本4.9.2以及cygwin上的gcc版本5.4.0上
当我编译时,没有-O3标志,两者都以相同的速度运行,所以听起来编译器也不能优化proga。什么优化不能在proga上完成,为什么
我已经为这篇文章删减了我的代码(我的实际代码做了一些有用的事情!)。常量200000000应该足够大,以提供重要的运行时间。写入操作可防止循环被优化。值2是一个非常特殊的值。如果编译器知道它总是被2除,它可以只移位位,而不是进行算术计算。但是,在
progb
中,编译器必须使用任何可能的整数值进行计数,因此必须实现实除法,而不仅仅是位移位
因此,访问参数不会抑制任何优化。使用固定值可以进行某些特定的优化。特别是当它是2的幂时
检查以下位置的差异:
通用版本使用
idiv ecx
版本除以2使用
shr edx, 31
add eax, edx
sar eax
idiv
指令比移位和加法慢得多
对于非二次幂,它仍然是可优化的,但它通常还涉及乘法、加法和减法等算术运算,而不仅仅是位移位。然而,这些都比除法更快。除法是一项非常缓慢的工作
正如steve所指出的,使用
-fwhole program
可以使编译器将所有单元编译在一起,并且可以假定它不需要生成不需要的子例程
顺便说一句,对于我在上面的godbolt链接中使用的简化子例程,gfortran优化了对子例程的调用,即使没有
-fwhole程序
,感谢您的快速回复,Vladimir。因此,编译器不够聪明,不知道b在proga中总是取值2?编译器相当聪明。不幸的是,程序员并没有试图帮助编译器。尝试使子例程成为包含ed内部子程序,或尝试使用-fwhole程序选项proga
和hist
是独立的作用域单元。神奇的是,Steve,-fwhole程序实现了这一点,两个版本运行速度一样快。我想补充一点,没有-fwhole程序,不仅2的幂在progb中运行得更快,将d设置为大素数仍然比proga快。所以我猜编译器知道d有一个特定的值(2的幂或否),它允许编译器在没有-fwhole程序的情况下进行优化。@fredko即使对于较大的素数,它也可以很好地进行优化。但这不仅仅是一个很容易说明的位移位。它还将进行一些乘法运算,这仍然比除法快,但仍然比移位快。@steve-fwholeprogram
做什么?你知道ifort的等价物吗?