Почему Fortran тратит так много времени на 'for_allocate' или 'for_deallocate'?
Я пытаюсь оптимизировать некоторый код Фортрана, который я унаследовал. Это очень повторяющийся код, на выполнение которого уходят дни, и я очень стараюсь сократить время выполнения. После сокращения времени выполнения некоторых функций и подпрограмм последнее узкое место, согласно VTune Amplifier, - это for_deallocation и for_allocation, специально вызываемые из одной подпрограммы. Я немного не уверен относительно того, что означает "for_" перед распределением и освобождением, особенно потому, что в процедуре не выполняется никакого выделения. Краткое содержание кода выглядит следующим образом:
module global_variables
double precision, allocatable :: input_values(:)
double precision, allocatable :: input_values2(:,:)
double precision, allocatable :: indices_array(:)
double precision, allocatable :: value_array(:)
double precision, allocatable :: final_result(:)
end module
subroutine func1()
allocate( ...global values...)
do I=1,n
call func2(I)
end do
end subroutine func1
subroutine func2(I)
double precision, intent(in) :: I
double precision :: value, x
double precision, dimension(3) :: output_array
call find_Indices(x)
value_array = input_values(indices_array)
call calculations(value)
do j = 1,3
value_array = input_values2(indices_array,j)
call calculations(output_array(j))
end do
final_result = output_array * value
end subroutine func2
subroutine find_Indices(position)
indices_array = some calculation on position
end subroutine find_Indices
subroutine calculations(output)
double precision :: output
output = some calculation on value_array
end subroutine calculations
Мне пришлось суммировать, а не вставлять фактический код из-за его природы. Подпрограмма с чрезмерным временем выделения / освобождения - func2. В подпрограмме нет операторов выделения и нет перераспределений глобальных значений. Используя доступную мне документацию, я не смог выяснить, что имеется в виду под "for_" перед allocate/ deallocate или почему почему на func2 тратится так много времени. Из-за размера кода, который я указал, размещение всех массивов в куче, что будет учитывать распределение, однако разрешение возврата массивов обратно в стек совсем не уменьшит время.
Кто-нибудь может помочь мне понять природу for_allocate/ for_deallocate? Или причина, по которой эта функция тратит так много времени на ее вызов?
РЕШЕНИЕ:
При поиске свойств массива, для другой проблемы, с которой я столкнулся, я наткнулся на этот пост: Fortran: динамические массивы и автоматический массив. Избегание выделения памяти.
Что показывает, что существуют значительные издержки при изменении выделяемых глобальных массивов. Изменение value_array из выделяемого массива в массив указателей (double Precicsion, pointer:: value_array(:)) убрало большую часть накладных расходов из for_allocate и for_deallocate и сократило время выполнения до 1/5 от того, что было. Это говорит мне о том, что при изменении значений выделяемого массива исходный массив освобождается, а новый выделяется. Это может быть хорошо известно в сообществе Фортран, но как новый пользователь, который не сталкивался с какой-либо документацией такого поведения, мне это было неочевидно.
1 ответ
Ознакомьтесь с примерами в разделе "6. Косвенный доступ к массиву" по адресу https://software.intel.com/en-us/articles/fortran-array-data-and-arguments-and-vectorization
Повторные распределения (очень вероятно), потому что при использовании массива индекса компилятор выделяет временный массив (пример 7.1 в ссылке выше) для хранения результирующего массива. Альтернативой является явное зацикливание индексов (пример 7.2).
Ссылка выше для MIC архитектур, но принцип, вероятно, тот же на обычном процессоре. Нить здесь https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/685221 также намекает на создание временных массивов для массива индексации.
Чтобы быть уверенным в том, что происходит, есть возможность проверить вывод сборки или явно протестировать сценарий "явной индексации".