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

时间:2012-12-14 09:06:55

标签: c performance gcc fortran archlinux

当我将一些fortran代码移植到c时,令我感到惊讶的是,使用ifort(intel fortran编译器)编译的fortran程序与使用gcc编译的c程序之间的大部分执行时间差异来自三角函数的评估函数(sincos)。这令我感到惊讶,因为我曾经相信这个answer解释的是,正弦和余弦等函数是在微处理器内部的微码中实现的。

为了更明确地发现问题,我在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 version 4.7.2同时

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

real    0m2.148s
user    0m2.090s
sys     0m0.003s

这几乎是差异的10倍!我是否仍然可以相信cos的gcc实现是微处理器实现的包装器,其方式类似于可能在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的基准测试让我觉得这个问题可能与gcc(4.7.2)的特定版本有关,也可能与我正在使用的特定版本(Arch x86_64 Linux)有关。我的电脑。所以我使用intel core i7debian x86_64 Linuxgcc 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论坛上询问这个问题。

然而,对整个故事的解释仍然非常受欢迎。

1 个答案:

答案 0 :(得分:15)

大多数情况是由于数学库的差异造成的。需要考虑的一些要点:

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