2014-12-17 4 views
0

Я пишу программу Fortran. Программа реализует некоторые численные методы. Скорость программы очень важна. Я решил избавиться от динамических массивов (ускоряет ли она программу?) И сталкивается со следующей проблемой. У меня есть 3D-массивы (NXxNYxNZ = MAX-элементы), где я знаю MAX, но я не знаю отношения NX/NY/NZ. Это может быть так: 1x1xNZ или как это 2xNYx1 и т. Д. Решение, которое я вижу - используйте указатели. Упрощенный 2D случай:fortran 2003 и указатели

program ptrtest 
    parameter (MAX = 50) ! I know this number on compile time. 
    integer :: NX,NY   ! I will find this numbers on run time. 
    real, target :: a(MAX) ! Static Array 
    real, pointer :: b(:,:) 
    a = 5 
    read(*,*) NX, NY   ! I get NX, NY (NX*NY == MAX) 
    b (1:NX, 1:NY) => a  ! I can use b(:,:) <- this is my goal. 
end program ptrtest 

Этот пример работает, но я боюсь, что такое обновление замедляющего реальной программы, где я использую даже 5d массивы. Является ли это возможным?

+3

Вы не показывают достаточно программу, чтобы действительно комментарий (Вы работаете одновременно с a и b? y передавая b подпрограмме?), но в целом производительность будет хуже при работе с переменными, которые имеют атрибут TARGET или POINTER, поскольку некоторые оптимизации могут быть предотвращены. Это будет зависеть от специфики, но выделение выделяемого массива размера (nx, ny) один раз вряд ли будет таким значительным, как и показатель READ, который заполняет nx и ny. – IanH

+3

Если вам нужен массив с определенными размерами времени выполнения, я рекомендую использовать выделяемый массив, а не массив указателей, если вам не нужна дополнительная функция указателя. ассигнования более безопасны. Кроме того, лучше всего решить вашу проблему, а затем определить медленные части, а не догадываться в начале. Микро-оптимизации редко имеют большое значение. Важным является выбор эффективного алгоритма. –

+2

FWIW Я согласен с другими комментаторами. Но если вы знаете 'MAX' во время компиляции, но нет, то до времени выполнения,' nx', 'ny' и' nz' вы всегда можете использовать проверенные и проверенные (для которых нужно понимать «старомодные»,) подход использования 1D-массива (элементов 'MAX') и арифметики с индексом roll-your-own. Если учесть этот подход, внимательно рассмотрите замечания @ M.S.B по оптимизации. –

ответ

2

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

  • выделить 1D массив размера MAX
  • прохода к подпрограмме, а также NX, NY , и NZ. Это позволит избежать указателя , который приведет к потере производительности (в отличие от C, стандарт Fortran предполагает, что аргументы массива подпрограмм не перекрываются, см. this post).

Например:


program noptrtest 
    implicit none 
    integer, parameter :: MAX = 50  ! I know this number on compile time. 
    integer :: NX,NY   ! I will find this numbers on run time. 
    real :: a(MAX)   ! Static Array 

    read(*,*) NX, NY   ! I get NX, NY (NX*NY == MAX) 

    if (NX*NY /= MAX) then 
    stop 'NX*NY /= MAX' 
    endif 
    call run(a,NX,NY) 
end program noptrtest 


subroutine run(b,NX,NY) 
    integer :: NX,NY 
    real :: b(NX,NY) 
    integer :: i,j 

    do j=1,NY 
    do i=1,NX 
     ! use b(i,j) here 
    enddo 
    enddo 
end 

Если производительность действительно имеет значение здесь некоторые другие полезные приемы:

  • Скажите ваш компилятор для выравнивания массивов на 32- байт (с ifort, используйте директиву !DIR$ ATTRIBUTES ALIGN : 32
  • Измерьте физически свой 2D-массив таким образом, чтобы размер ведущего измерения был кратным 32 байтам. Для реального * 4 вам нужно несколько из восьми элементов.
  • Скажи компилятор, что каждый столбец правильно выровненный с помощью !DIR$ VECTOR ALIGNED директивы

Например:

program noptrtest 
    implicit none 
    integer, parameter :: real_kind = 4 
    integer, parameter :: MAX = 50    ! I know this number on compile time. 
    integer, parameter :: MAXDIM = MAX*(32/real_kind) ! Max possible dimension required 
    integer   :: NX,NY, NX_MOD   ! I will find this numbers on run time. 
    real(real_kind) :: a(MAXDIM)    ! Static Array 

    !DIR$ ATTRIBUTES ALIGN : 32 :: a 

    read(*,*) NX, NY   ! I get NX, NY (NX*NY == MAX) 

    if (NX*NY /= MAX) then 
    stop 'NX*NY /= MAX' 
    endif 

    if (mod(NX,real_kind) == 0) then 
    NX_MOD = NX 
    else 
    NX_MOD = ((NX/real_kind)+1)*real_kind 
    endif 

    call run(a,NX_MOD,NX,NY) 
end program noptrtest 


subroutine run(b,NX_MOD,NX,NY) 
    integer :: NX_MOD,NX,NY 
    real :: b(NX_MOD,NY) 
    integer :: i,j 

    do j=1,NY 
    !DIR$ VECTOR ALIGNED 
    do i=1,NX 
    ! use b(i,j) here 
    enddo 
    enddo 
end 

Редактировать

Это старого стиля Fortran трюк избегает поворота ter aliasing.

Ссылки на указатель ступенчатости:

+5

* Старинный стиль Fortran даст вам лучшее * Покажите нам номера; без данных этот «ответ» - это мнение. –

+0

Это не мнение. Посмотрите на вариант -fno-alias компиляторов C для получения дополнительных пояснений. Как я уже сказал: «(в отличие от C, стандарт Fortran предполагает, что аргументы массива подпрограмм не перекрываются)». Сглаживание указателя является хорошо известной проблемой для компиляторов, и он не присутствовал в Фортране, прежде чем они вводили указатели. См. –

+0

Мне тоже хотелось бы увидеть некоторые фактические цифры. – bdforbes

Смежные вопросы