最近,我读了post on Stack Overflow关于找到完美正方形的整数。因为我想玩这个,我写了下面的小程序:ifort和gfortran之间令人费解的性能差异
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来分析它,而英特尔编译的程序的确使用了更多的指令。
我的问题是为什么?有没有办法找出差异究竟在哪里?
EDITS:
- gfortran版本4.6.2和ifort版本12.0.2
- 倍从运行
time ./a.out
获得,并且是真正的/用户时间(SYS总是几乎为0) - 此在Linux x86_64上,gfortran和ifort都是64位版本
- ifort内联了所有内容,gfortran仅在-O3,但后者的汇编代码比ifort更简单,它使用xmm寄存器很多
- 固定的代码行,循环前加入
NTOT=0
,应该可以解决问题与其他gfortran版本
当复数IF
声明被删除,gfortran大约需要4倍的时间(10-11秒)。这是预料之中的,因为该声明大约会抛出约75%的数字,从而避免对它们执行SQRT
。另一方面,只能使用更多的时间。我的猜测是,当ifort尝试优化IF
声明时出现问题。
EDIT2:
我试着用ifort版本12.1.2.273它的速度更快,所以看起来他们固定的。
是那些墙倍或CPU时间?你能为每一个粘贴'time'的输出吗?这些32位版本还是64位版本? –
2012-01-17 10:49:58
您是否尝试过反汇编每个编译器发出的对象文件并对它们进行比较? – talonmies 2012-01-17 11:02:28
@talonmies:不,我没有,因为我真的不懂组装。尽管通过'valgrind --tool = callgrind --dump-instr = yes'运行也提供了汇编代码,但这真的很复杂(很多不同),并且取决于优化级别。 – steabert 2012-01-17 11:08:53