当我将一些Fortran代码转换成C时,令我惊讶的是:使用ifort(英特尔Fortran编译器)编译的Fortran程序和使用gcc编译的C程序之间大部分执行时间差异来自三角函数(sin
, cos
)的计算。这令我感到惊讶,因为我曾经相信这个答案所解释的,即正弦和余弦等函数是在微处理器内部的微码中实现的。
为了更明确地发现问题,我制作了一个小型Fortran测试程序。
program ftest
implicit none
real(8) :: x
integer :: i
x = 0d0
do i = 1, 10000000
x = cos (2d0 * x)
end do
write (*,*) x
end program ftest
在 intel Q6600
处理器和 3.6.9-1-ARCH x86_64 Linux
操作系统下,我使用的是 ifort version 12.1.0
$ ifort -o ftest ftest.f90
$ time ./ftest
-0.211417093282753
real 0m0.280s
user 0m0.273s
sys 0m0.003s
而在 gcc 版本 4.7.2
中我得到了
$ gfortran -o ftest ftest.f90
$ time ./ftest
0.16184945593939115
real 0m2.148s
user 0m2.090s
sys 0m0.003s
这几乎是一个10倍的差异!我仍然可以相信gcc对cos
的实现类似于intel实现中可能做的方式,即它是微处理器实现的包装器吗?如果是这样,瓶颈在哪里?
编辑
根据评论,启用优化应该会提高性能。 我的意见是优化不会影响库函数...这并不意味着我不会在非平凡程序中使用它们。 但是,这里有两个额外的基准测试(现在在我的家用电脑上intel core2
)
$ gfortran -o ftest ftest.f90
$ time ./ftest
0.16184945593939115
real 0m2.993s
user 0m2.986s
sys 0m0.000s
和
$ gfortran -Ofast -march=native -o ftest ftest.f90
$ time ./ftest
0.16184945593939115
real 0m2.967s
user 0m2.960s
sys 0m0.003s
你(评论者)具体指的是哪些优化?在这个特定的例子中,每次迭代都依赖于上一次的结果,编译器如何利用多核处理器进行优化?修改2:
Daniel Fisher和Ilmari Karonen的基准测试让我想到问题可能与我在计算机上使用的特定版本(Arch x86_64 Linux的gcc 4.7.2)有关。因此,我在
debian x86_64 Linux
上的intel core i7
电脑上重复了测试,使用了gcc version 4.4.5
和ifort version 12.1.0
。$ gfortran -O3 -o ftest ftest.f90
$ time ./ftest
0.16184945593939115
real 0m0.272s
user 0m0.268s
sys 0m0.004s
和
$ ifort -O3 -o ftest ftest.f90
$ time ./ftest
-0.211417093282753
real 0m0.178s
user 0m0.176s
sys 0m0.004s
对我来说,这个性能差异是可以接受的,不会让我产生疑问。看来我需要在Arch Linux论坛上询问这个问题。
然而,整个故事的解释仍然非常受欢迎。
ifort
不会执行任何类型的循环展开。它会非常字面地翻译循环,并调用其自己优化过的cos
例程,该例程以某种方式比fcos
更快地计算余弦。初步查看,反汇编的cos
例程似乎使用表格化参数缩减。GCC调用系统范围内的数学库,实现了类似的功能,但对于英特尔处理器来说没有libimf
进行了优化。 - Hristo Iliev