我在这个琐碎的节目中发现了一个非常好奇的效果
module Moo
contains
subroutine main()
integer :: res
real :: start, finish
integer :: i
call cpu_time(start)
do i = 1, 1000000000
call Squared(5, res)
enddo
call cpu_time(finish)
print '("Time = ",f6.3," seconds.")',finish-start
end subroutine
subroutine Squared(v, res)
integer, intent(in) :: v
integer, intent(out) :: res
res = v*v
end subroutine
! subroutine main2()
! integer :: res
! real :: start, finish
! integer :: i
!
! call cpu_time(start)
!
! do i = 1, 1000000000
! res = v*v
! enddo
! call cpu_time(finish)
!
! print '("Time = ",f6.3," seconds.")',finish-start
! end subroutine
end module
program foo
use Moo
call main()
! call main2()
end program
编译器是mac上的gfortran 4.6.2。如果我使用-O0
编译并运行程序,则时间为4.36秒。如果我取消注释子程序main2()
,而不取消其调用,则时间平均变为4.15秒。如果我也取消注释call main2()
第一个时间变为3.80而第二个时间变为1.86(可以理解,我没有函数调用)。
我比较了在第二和第三种情况下生成的汇编程序(例程未注释;调用注释和未注释)并且它们完全相同,除了实际调用main2例程。
代码如何通过调用将来会发生的例程来提高性能,并且在结果代码中基本没有区别?
答案 0 :(得分:6)
我注意到的第一件事是你的程序太短,无法进行适当的基准测试。你用多少次跑步来平均?什么是标准偏差?我在代码中添加了一个嵌套的do循环,以使其更长:
do i = 1, 1000000000
do j=1,10
call Squared(5, res)
enddo
enddo
我只查看了案例1和案例2(main2评论和未注释),因为案例3不同并且与此比较无关。我希望在案例2中运行时略有增加,因为需要将更大的可执行文件加载到内存中,即使该部分未在程序中使用。
对于三个编译器,我为时间1和2做了计时(每次运行3次):
pgf90 10.6-0 x86-64上的64位目标Linux -tp istanbul-64
英特尔(R)Fortran英特尔(R)64编译器XE,适用于在英特尔(R)64,版本12.0.2.137 Build 20110112上运行的应用程序
GNU Fortran(GCC)4.1.2 20080704(Red Hat 4.1.2-51)
关于AMD Opteron(tm)处理器6134
我的脚本输出是:
exp 1 with pgf90:
Time = 30.619 seconds.
Time = 30.620 seconds.
Time = 30.686 seconds.
exp 2 with pgf90:
Time = 30.606 seconds.
Time = 30.693 seconds.
Time = 30.635 seconds.
exp 1 with ifort:
Time = 77.412 seconds.
Time = 77.381 seconds.
Time = 77.395 seconds.
exp 2 with ifort:
Time = 77.834 seconds.
Time = 77.853 seconds.
Time = 77.825 seconds.
exp 1 with gfortran:
Time = 68.713 seconds.
Time = 68.659 seconds.
Time = 68.650 seconds.
exp 2 with gfortran:
Time = 71.923 seconds.
Time = 74.857 seconds.
Time = 72.126 seconds.
请注意,案例1和案例2之间的时间差异对于gfortran而言最大,而对于pgf90而言则最小。
编辑:在Stefano Borini指出我忽略了这样一个事实,即只使用调用cpu_time对循环进行基准测试,可执行加载时间是不合适的。 AShelley的回答提出了可能的原因。对于更长的运行时间,两种情况之间的差异变得最小。仍然 - 我发现gfortran的情况有很大差异(见上文)答案 1 :(得分:5)
我认为@ IRO-bot有正确的答案,但我想指出代码放置会影响时间,即使是相同的装配。
我有两个在相同处理器上运行的嵌入式应用程序。每个都有相同的手动编码程序例程,以提供尽可能紧密的忙循环(用于插入亚微秒延迟)。我最近惊讶地发现,在一个应用程序中,循环占用了50%!比另一个更长。两者都生成了完全相同的组件。
事实证明,在一个可执行文件中,循环体的起始地址允许它完全落在处理器的唯一指令缓存行中。在较慢的一个上,相同的功能从一个地址开始,导致它跨越两行。需要额外的提取主导了这种紧密循环的时机。
因此,由于指令缓存序列发生了变化,因此可以找到添加未执行代码会影响代码时序的实例。