ifort和gfortran之间令人费解的性能差异

时间:2012-01-17 10:39:38

标签: fortran

最近,我读了一篇关于找到完美正方形整数的post on Stack Overflow。因为我想玩这个,我写了以下小程序:

PROGRAM PERFECT_SQUARE
IMPLICIT NONE
INTEGER*8 :: N, M, NTOT
LOGICAL :: IS_SQUARE

N=Z'D0B03602181'
WRITE(*,*) IS_SQUARE(N)

NTOT=0
DO N=1,1000000000
  IF (IS_SQUARE(N)) THEN
    NTOT=NTOT+1
  END IF
END DO
WRITE(*,*) NTOT ! should find 31622 squares
END PROGRAM

LOGICAL FUNCTION IS_SQUARE(N)
IMPLICIT NONE
INTEGER*8 :: N, M

! check if negative
IF (N.LT.0) THEN
  IS_SQUARE=.FALSE.
  RETURN
END IF

! check if ending 4 bits belong to (0,1,4,9)
M=IAND(N,15)
IF (.NOT.(M.EQ.0 .OR. M.EQ.1 .OR. M.EQ.4 .OR. M.EQ.9)) THEN
  IS_SQUARE=.FALSE.
  RETURN
END IF

! try to find the nearest integer to sqrt(n)
M=DINT(SQRT(DBLE(N)))
IF (M**2.NE.N) THEN
  IS_SQUARE=.FALSE.
  RETURN
END IF

IS_SQUARE=.TRUE.
RETURN
END FUNCTION

使用gfortran -O2进行编译时,运行时间为4.437秒,-O3为2.657秒。然后我认为使用ifort -O2进行编译可能会更快,因为它可能有更快的SQRT函数,但结果显示运行时间现在是9.026秒,而ifort -O3也是如此。我尝试使用Valgrind进行分析,英特尔编译的程序确实使用了更多的指令。

我的问题是为什么?有没有办法找出差异的来源?

编辑:

  • gfortran版本4.6.2和ifort版本12.0.2
  • 次是从运行time ./a.out获得的,是实际/用户时间(sys总是几乎为0)
  • 这是在Linux x86_64上,gfortran和ifort都是64位版本
  • ifort内联所有内容,gfortran仅在-O3,但后者汇编代码比ifort更简单,ifort使用xmm寄存器
  • 固定的代码行,在循环之前添加NTOT=0,应解决其他gfortran版本的问题

当删除复杂的IF语句时,gfortran需要大约4倍的时间(10-11秒)。这是可以预料的,因为该声明大约抛出了大约75%的数字,避免对它们进行SQRT。另一方面,ifort仅使用稍多的时间。我的猜测是当ifort尝试优化IF语句时会出现问题。

EDIT2:

我尝试使用ifort版本12.1.2.273它速度要快得多,所以看起来他们已经解决了这个问题。

1 个答案:

答案 0 :(得分:3)

您使用的是哪些编译器版本? 有趣的是,它看起来像是一个从11.1到12.0的性能回归的情况 - 例如对我来说,11.1(ifort -fast square.f90)需要3.96s,而12.0(相同选项)需要13.3s。 gfortran(4.6.1)( - O3)仍然更快(3.35秒)。 我以前见过这种回归,虽然不那么引人注目。 顺便说一句,用

替换if语句
is_square = any(m == [0, 1, 4, 9])
if(.not. is_square) return

使用ifort 12.0运行速度提高两倍,但在gfortran和ifort 11.1运行速度更慢。

看起来问题的一部分是12.0过于积极地试图对事物进行矢量化:添加

!DEC$ NOVECTOR
在DO循环之前的

(不更改代码中的任何其他内容)将运行时间缩短到4.0秒。

另外,作为附带好处:如果您有多核CPU,请尝试在ifort命令行中添加-parallel:)