我一直在使用不同文件中的模块和子程序编译项目。每个子程序都写在单独的文件中。模块也一样。然后,我测试了将这些文件单独编译为目标文件(-c),然后与优化标志链接,并使用cat合并整个源代码并将相同的过程应用于此单个源文件。我发现,编译单个文件生成的可执行文件比多个文件生成的可执行文件快40%,尽管两者使用完全相同的标记。 我想知道是否有人知道它为什么会发生,以及英特尔Fortran编译器上是否有任何标志编译多个文件,因为它们是单个文件。
答案 0 :(得分:5)
正如@ chw21所要求的,我创建了一个显示问题的小程序:
program main
use operators
implicit none
integer :: n
real(8), dimension(:,:), allocatable :: a, b, c
integer :: i,j,k
n = 1000
allocate(a(n,n), b(n,n), c(n,n))
call random_number(a)
call random_number(b)
do j = 1, n
do i = 1, n
do k = 1, n
!c(i,j) = c(i,j) + a(k,i) * b(k,j)
c(i,j) = add(c(i,j), mul(a(k,i), b(k,j)))
enddo
enddo
enddo
write(*,*) sum(c)
end program
with module:
module operators
contains
function add(a,b) result (c)
real(8), intent(in) :: a, b
real(8) :: c
c = a + b
end function
function mul(a,b) result (c)
real(8), intent(in) :: a, b
real(8) :: c
c = a * b
end function
end module
这个想法是,如果编译器知道它们非常小,那么这些函数通常应该被内联。我用-O2
进行了三次测试:
-ipo
(或-flto
) ifort 13.0.0
和gfortran 5.2.0
在不同计算机上的结果为:
Test | 1. | 2. | 3.
---------+-------+-------+-------
ifort | 1.3s | 15.7s | 1.9s
gfortran | 1.1s | 3.7s | 1.1s
不幸的是,我不知道为什么第一次和第三次使用ifort测试之间仍然存在差异...我想,看看生成的代码会对这个问题有所了解。
更新:时间是通过执行time ./a.out
来衡量的,这导致了稳定的时间。由于使用ifort -O2
进行标准编译,最大指令集应为SSE2(因此,无FMA),处理器最多支持SSE4a(Opteron 6128)。对最近的英特尔处理器(最高AVX)的额外测试显示了类似的结果。
一个重要的事情似乎是缺乏内部循环的内联和矢量化,这在IPO和单文件编译期间应用(参见--opt-report
)。此外,IPO和单文件编译之间的矢量化似乎存在一些差异。