Я пытаюсь ускорить довольно длительную программу, которая изначально не была предназначена для параллельных вычислений. Поэтому я экспериментирую с автоматическим распараллеливанием с gfortran
.Автоматическое распараллеливание с gfortran
У меня есть следующая тестовая программа, которая в основном только выполняет несколько петель и измеряет время выполнения:
program autoparallel
implicit none
integer :: N = 10000
double precision, allocatable :: A(:, :), X(:), Y(:)
integer :: i, j
integer :: time_start, time_finish, time_rate
call system_clock (time_start, time_rate)
allocate(A(N, N), X(N), Y(N))
do i=1, N
do j=1, N
A(i, j) = i * j
end do
end do
do i=1, N
X(i) = i
end do
do i=1, N
Y(i) = 0.d0
end do
do i=1, N
do j=1, N
Y(i) = Y(i) + A(j, i) * X(j)
end do
end do
call system_clock (time_finish, time_rate)
write(*,*) 'Elapsed time: ', (time_finish-time_start)/real(time_rate), ' seconds'
write(*,*) Y(1), Y(N)
deallocate(A, X, Y)
end program autoparallel
Я выполнил его с различными флагами компилятора пять раз каждые:
gfortran test.f90
4.14799976 seconds
4.51900005 seconds
4.42399979 seconds
4.15600014 seconds
4.38000011 seconds
gfortran -floop-parallelize-all -ftree-parallelize-loops=2 autoparallel.f90
4.36899996 seconds
4.07499981 seconds
4.35599995 seconds
4.17899990 seconds
4.37500000 seconds
gfortran -floop-parallelize-all -ftree-parallelize-loops=4 autoparallel.f90
4.28399992 seconds
4.42600012 seconds
4.19999981 seconds
4.33199978 seconds
4.14499998 seconds
gfortran -O3 autoparallel.f90
3.63599992 seconds
3.63599992 seconds
3.79800010 seconds
3.55900002 seconds
3.59599996 seconds
gfortran -O3 -floop-parallelize-all -ftree-parallelize-loops=4 autoparallel.f90
3.09299994 seconds
3.08299994 seconds
3.46799994 seconds
3.00099993 seconds
3.00699997 seconds
gfortran -O3 -floop-nest-optimize autoparallel.f90
1.03100002 seconds
1.01800001 seconds
1.02300000 seconds
1.03600001 seconds
0.947000027 seconds
Так в основном время выполнения равномерно с количеством потоков. Только после оптимизации происходит автоматическая распараллеливание. Я пытаюсь понять, почему это так.
По крайней мере, все i
-loops могут быть распределены по нескольким потокам без какой-либо оптимизации.
Так что же здесь происходит? Есть ли другие флагов компилятора, которые я мог бы использовать для ускорения работы программы? И какие флаги противоречат моей цели распараллеливания?
-floop-nest-optimize
не работает вместе с -floop-parallelize-all
. Ошибка:
isl_constraint.c:497: position out of bounds
Умный оптимизирующий компилятор (и оптимизирующие компиляторы может быть очень умным) поймет, что ничего не будет сделано со значением 'Y', так поэтому не нужно возиться с петлями, которые определяют' Y'. Точно так же он понял бы, что не нужно беспокоиться об определении «Х» и «А». Это приведет к краху всей программы вплоть до некоторых запросов таймера и некоторых выходных операторов. Я не исследовал, делает ли gfortran это или нет (время не предполагает), но с оптимизацией вы можете не выполнять то, что считаете себя. – IanH
Первый цикл является очевидным кандидатом на коммутацию гнезд петли, но я не рассчитываю на то, что gfortran найдет это автоматически. Я также не рассчитываю на gfortran, выполняющий автоматическую замену dot_product в последнем. – tim18
Помещение «print *, Y (1), Y (N)» перед освобождением() может быть полезно, чтобы избежать возможной ошибки уничтожения. С gfort-6.1 на osx10.9 установка -floop-nest-optimize сделала расчет почти в два раза быстрее @@ (я не знал, что эти параллельные (?) Варианты настолько интересны ...) – roygvib