c - 为什么 gcc 数学库效率这么低?

标签 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 版本 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 倍的差异!我是否仍然相信 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) 有关我的电脑。所以我用 debian x86_64 Linuxgcc version 4.4.5ifort version 12.1 在 intel core i7 盒子上重复了测试。 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 论坛问问这个问题了。

不过,还是很欢迎解释整个故事。

最佳答案

这主要是由于数学库的差异。需要考虑的几点:

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

关于c - 为什么 gcc 数学库效率这么低?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13875540/

相关文章:

c - 优化 O(n^2) 到 O(n)(未排序的字符串)

c - 为什么在管道的读取端关闭时不会发生 SIGPIPE?

C wait() 确实有效

c++ - 涉及通用引用的过载解决方案

c - Gnu-Make 无法包含 makefile

SQL:有效地将增量数字附加到字符串,避免重复

java - 如果枚举中的类型只使用一次,我应该创建一个枚举还是一个类

与 XP 相比,WinForms ListView 在 Windows 7 中绘制速度极慢

c - 为 main 外部的结构元素赋值

c - 帮助理解C中的->运算符