最近,我讀了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