为什么gcc数学库效率低下?

Ben*_*tic 30 c performance gcc fortran archlinux

当我将一些fortran代码移植到c时,令我感到惊讶的是,使用ifort(intel 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

而与gcc version 4.7.2我得到

$ gfortran -o ftest ftest.f90 
$ time ./ftest
  0.16184945593939115     

real    0m2.148s
user    0m2.090s
sys     0m0.003s
Run Code Online (Sandbox Code Playgroud)

这几乎是差异的一个因素!我是否仍然可以相信gcc实现cos是一个围绕微处理器实现的包装器,类似于这可能是在intel实现中完成的?如果这是真的,瓶颈在哪里?

编辑

根据评论,启用优化应该可以提高性能.我的观点是优化不会影响库函数......这并不意味着我不会在非平凡的程序中使用它们.但是,这里有两个额外的基准测试(现在在我的家用电脑上intel core2)

$ gfortran -o ftest ftest.f90
$ time ./ftest
  0.16184945593939115     

real    0m2.993s
user    0m2.986s
sys     0m0.000s
Run Code Online (Sandbox Code Playgroud)

$ gfortran -Ofast -march=native -o ftest ftest.f90
$ time ./ftest
  0.16184945593939115     

real    0m2.967s
user    0m2.960s
sys     0m0.003s
Run Code Online (Sandbox Code Playgroud)

你(评论员)想到了哪些特别的优化?在这个特定的例子中,编译器如何利用多核处理器,每个迭代都依赖于前一个迭代的结果?

编辑2

Daniel Fisher和Ilmari Karonen的基准测试使我认为问题可能与gcc(4.7.2)的特定版本有关,也可能与我在计算机上使用的特定版本(Arch x86_64 Linux)有关.所以我在intel core i7盒子上重复了测试debian x86_64 Linux,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
Run Code Online (Sandbox Code Playgroud)

$ ifort -O3 -o ftest ftest.f90
$ time ./ftest
  -0.211417093282753     

real    0m0.178s
user    0m0.176s
sys     0m0.004s
Run Code Online (Sandbox Code Playgroud)

对我来说,这是一个非常可接受的性能差异,这永远不会让我问这个问题.看来我将不得不在Arch Linux论坛上询问这个问题.

但是,对整个故事的解释仍然非常受欢迎.

jan*_*neb 16

其中大部分是由于数学库的差异.有些要考虑的要点:

  • 是的,带有x87单元的x86处理器具有fsin和fcos指令.但是,它们是用微码实现的,并没有特别的理由说它们必须比纯软件实现更快.
  • GCC没有自己的数学库,而是使用提供的系统.在Linux上,这通常由glibc提供.
  • 32位x86 glibc使用fsin/fcos.
  • x86_64 glibc使用SSE2单元的软件实现.很长一段时间,这比使用x87指令的32位glibc版本要慢很多.但是,(最近有些)进行了改进,因此根据您所拥有的glibc版本,情况可能不会像过去那样糟糕.
  • 英特尔编译器套件拥有非常快速的数学库(libimf).此外,它还包括矢量化的超越数学函数,通常可以使用这些函数进一步加速循环.