Поразительная разница в производительности между ифортом и гфортраном - PullRequest
3 голосов
/ 17 января 2012

Недавно я прочитал пост о переполнении стека о поиске целых чисел, которые являются идеальными квадратами.Поскольку я хотел поиграть с этим, я написал следующую маленькую программу:

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, и скомпилированная программа Intel действительно использует гораздо больше инструкций.

Мой вопрос: почему?Есть ли способ узнать, откуда именно разница?

РЕДАКТИРОВАТЬ:

  • 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 использует только немного больше времени.Я предполагаю, что что-то идет не так, когда ifort пытается оптимизировать оператор IF.

EDIT2:

Я пробовал с версией ifort 12.1.2.273 это намного быстрее, так что, похоже, они исправили это.

1 Ответ

3 голосов
/ 25 января 2012

Какие версии компилятора вы используете?Интересно, что это похоже на случай, когда наблюдается снижение производительности с 11,1 до 12,0 - например, для меня 11,1 (ifort -fast square.f90) занимает 3,96 с, а 12,0 (те же параметры) - 13,3 с.Гфортран (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 сек.

Также,В качестве дополнительного преимущества: если у вас многоядерный процессор, попробуйте добавить -parallel в командную строку ifort:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...