Повышение производительности подпрограмму, которая проверяет на вакансию в решетку


Я использую следующую функцию для проверки, является ли небольшой подраздел в 3D массива, все равно нулю. Если любое значение в определенном подразделом является ненулевым, я выйти и вернуться .false.. В CheckForVacancy, подпрограммы bc вызывается, который заботится о вне границ массива индексов.

Эта подпрограмма вызывается миллионы раз в течение определенного прогона и он несет ответственность за примерно половину времени выполнения всей программы. В далеком прошлом, я пытался оптимизировать его, изменяя порядок, в котором я могу получить доступ к Lattice массив и с помощью any встроенный массив с кружочками, но я не видел много улучшений. Кроме того, "массив срезов" решение может усложниться при работе с границами массива. Я тоже пробовал возиться с оптимизацией флагов, но я был в значительной степени вслепую экспериментировать в этой точке.

Код выглядит следующим образом:

LOGICAL FUNCTION CheckForVacancy (x, y, z)
  ! Checks for vacancy for a site [x,y,z]

  use atrpmodule

  IMPLICIT NONE

  INTEGER, INTENT(IN) :: x, y, z
  INTEGER :: Sx, Sy, Sz, i
  INTEGER, DIMENSION(1:26) :: SpaceX = (/1,1,1,0,-1,-1,-1,0,1,1,1,0,-1,-1,-1,0,0,1,1,1,0,-1,-1,-1,0,0/)
  INTEGER, DIMENSION(1:26) :: SpaceY = (/0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1/)
  INTEGER, DIMENSION(1:26) :: SpaceZ = (/1,0,-1,-1,-1,0,1,1,1,0,-1,-1,-1,0,1,1,0,1,0,-1,-1,-1,0,1,1,0/)
  !---------------------------------------------------------------------------

  checkforvacancy=.true.
  do i=1,26
     Sx = x + SpaceX(i)
     Sy = y + SpaceY(i)
     Sz = z + SpaceZ(i)
     call bc(Sx,Sy,Sz)
     if (lattice(Sx,Sy,Sz)/=0)then
        CheckForVacancy=.false.
        exit
     endif
  enddo

END FUNCTION CheckForVacancy

SUBROUTINE bc (x, y, z)
  ! Takes case of boundary conditions
  USE atrpmodule
  IMPLICIT NONE

  INTEGER :: x, y, z
  !---------------------------------------------------------------------------
  IF (x < 1) then
     x = x + LattXDimm
  elseIF(x > LattXDimm) then
     x = x - LattXDimm
  endif

  IF (y < 1) then
     y = y + LattYDimm
  elseIF (y > LattYDimm) then
     y = y - LattYDimm
  endif

  IF (z < 1) then
     z = z + LattZDimm
  elseIF (z > LattZDimm) then
     z = z - LattZDimm
  endif

END SUBROUTINE bc

Для справки Lattice определяется так:

INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: Lattice

Он выделяется в зависимости от входных данных программы, а затем приравнять к нулю. Также для справки, я использую компилятор GNU.

Я подозреваю, что ответ на этот вопрос может быть то, что я не могу сделать лучше, но я хотел, чтобы увидеть, если любой Фортран программисты могут увидеть то, что мне не хватает или, возможно, хотите попробовать.



113
1
задан 22 марта 2018 в 06:03 Источник Поделиться
Комментарии
1 ответ

Три мысли по этому поводу.

Во-первых, если решетка маленький, вы не столкнетесь с граничным условием в большинстве случаев. Проверьте, если граничное условие можно раз и имеют две функции CheckForVacancy один с и один без пограничных проверок.

Вторая мысль полностью удалить границу проверить путем добавления повторяющихся элементов. В одно измерение, если у вас следующие

Index:1,2,3,4,5 
Value:3,4,3,2,1

Сделать массив

Index:0,1,2,3,4,5,6
Value:1,3,4,3,2,1,3

Так вы торгуете дополнительное место для хранения, чтобы удалить границы проверяет.

И, наконец, еще много no_ops в цикле for. Все эти добавить ноль операторы ничего не делают. Вы могли бы развернуть цикл, чтобы устранить их за счет более код. Вы уже убрали опцию 0,0,0, я думаю.

Ваш комментарий свидетельствует о том, что решетки изменяется во время выполнения, что делает удаление границы проверить более сложные.

В зависимости от размеров решетки и числа раз вы называете CheckForVacancy в отдельную ячейку можно мемоизировать клетки, прилегающих к ячейке или предварительно вычислить их. Это будет работать если у вас достаточно памяти и при вызове функции с теми же значениями несколько раз.

1
ответ дан 22 марта 2018 в 10:03 Источник Поделиться