рекомендуемые практики размещения массивов в Фортране - PullRequest
0 голосов
/ 12 июня 2018

Каковы рекомендации или рекомендации относительно того, где мы должны выделить массив?

Например, если у меня есть (упрощенная версия моей) программы, как показано, я выделяю выходную переменную (переменнуюинтереса) в основной программе.Эта основная программа вызывает подпрограмму foo, которая, в свою очередь, вызывает подпрограмму foo2, которая выполняет фактические вычисления.Мой вопрос заключается в том, какова наилучшая / рекомендуемая практика для того, где должно быть сделано распределение.

  • Если foo2 выполняет фактические вычисления, должен ли он выделять массивы?
  • Если foo вызывает foo2, foo должен выделять массив и foo2делать только вычисления?
  • Должен ли я написать новую функцию / подпрограмму, чтобы просто распределить массивы?
  • Или лучше распределить в основной программе и передать массивы в виде предполагаемой формы?

Если это важно, у меня есть модуль с именем global, который содержит производные типы в основной программе и основные параметры кода, такие как размер каждого массива (Ni,Nj, допуски и т. Д.)

program main
    use global
    implicit none

    type(myVar_) :: ans

    Ni = 10
    Nj = 20

    if (allocated(ans%P)) deallocate(ans%P)
    allocate(ans%P(1:Ni, 1:Nj))

    call foo(ans)

    print *, P
end program main

module global
    integer, parameter :: dp=kind(0.d0)

    integer :: Ni, Nj

    type myVar_
        real(dp), allocatable :: P(:,:)
    end type myVar_

end module global

subroutine foo(myVar)
    use global
    implicit none

    type(myVar_) :: myVar

    call foo2(myVar%P)

end subroutine

subroutine foo2(P)
    use global
    implicit none

    real(dp), intent(inout) :: P(:,:)

    ! do calculations for P
end subroutine foo2

что такое

1 Ответ

0 голосов
/ 13 июня 2018

Хорошей практикой является избегать распределения в низкоуровневых подпрограммах и функционировать по соображениям производительности.Как видно из [1], простые добавления занимают около 1-3 циклов ЦП, пара выделения и освобождения (из «маленького» массива) может занимать от 200 до 500 циклов ЦП.

Я бы предложилВы можете написать подпрограмму, используя переменную «work» в качестве входных данных и, возможно, работающую на месте (то есть, перезаписывая ввод с результатом), например:

subroutine do_computation(input,output,work1,work2)
   work1 = ...
   work2 = ...
   output = ...
end subroutine

. Вы можете сделать функцию-обертку, которая делает выделение дляудобство:

subroutine convenient_subroutine(input,output)
   allocate(work1(...),work2(...)
   call do_computation(input,output,work1,work2)
   deallocate(work1,work2)
end subroutine

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

[1] http://ithare.com/infographics-operation-costs-in-cpu-clock-cycles/

...