доступ к фиктивной переменной в фортране мешает оптимизации? - PullRequest
4 голосов
/ 08 ноября 2019

Я пытаюсь оптимизировать некоторый фортран-код и заметил удивительное поведение, которое пытаюсь понять. Progb работает примерно в 3 или 4 раза быстрее, чем Proga. Единственная разница - это назначение «d = 2» в progb вместо «d = b» в proga, поэтому наивно они должны быть эквивалентны:

  program proga
  implicit  none

  call hist(2)
  stop
  end

  subroutine hist(b)
  implicit  none
  integer, intent(in):: b
  integer   d,i,p(200000000)

  d = b
  do i=1,200000000
     p(i) = i/d
  end do
  write(*,*) p(1)
  end


  program progb
  implicit  none

  call hist(2)
  stop
  end

  subroutine hist(b)
  implicit  none
  integer, intent(in):: b
  integer   d,i,p(200000000)

  d = 2
  do i=1,200000000
     p(i) = i/d
  end do
  write(*,*) p(1)
  end

Я компилирую с помощью «gfortran proga.f -O3»и аналогично для прогб. Это происходит в gcc версии 4.9.2 в Debian, а также в gcc версии 5.4.0 в cygwin.

Когда я компилирую без флага -O3, оба запускаются с одинаковой скоростью, поэтому звучит так, будто компилятор можетНе оптимизируй и прогу. Какую оптимизацию нельзя выполнить для proga и почему?

Я сократил свой код для этого поста (мой настоящий код делает что-то полезное!). Константа 200000000 должна быть достаточно большой, чтобы обеспечить значительное время выполнения. Запись предотвращает оптимизацию цикла.

1 Ответ

4 голосов
/ 08 ноября 2019

Значение 2 является очень особенным значением. Если компилятор знает, что он всегда делится на 2, он может просто сдвинуть биты вместо выполнения арифметических вычислений. Однако в progb компилятор должен считать с любым возможным целочисленным значением, поэтому должен реализовывать реальное деление, а не просто сдвиг битов.

Таким образом, доступ к аргументу не препятствует какой-либо оптимизации. Использование фиксированного значения позволяет провести некоторую конкретную оптимизацию. Особенно, если это степень 2.

Проверьте разницу на https://godbolt.org/z/TcJxYK

Общая версия использует

idiv    ecx

версия, деленная на 2 использует

shr     edx, 31
add     eax, edx
sar     eax

Инструкция idiv намного медленнее, чем сдвиги и сложения.

Для не степеней двойки она все еще оптимизируема, но, как правило, также включает в себя арифметические операции в виде умножений, сложений и вычитанийне просто сдвиги. Тем не менее, они быстрее, чем деление. Деление - очень медленная операция.


Как указал Стив, использование -fwhole-program позволяет компилятору компилировать все модули вместе, а также может предполагать, что ему не нужно генерировать ненужные подпрограммы.

Кстати, для упрощенных подпрограмм, которые я использовал в ссылке Godbolt выше, gfortran оптимизирует вызов подпрограммы даже без -fwhole-program.

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