2016-08-10 6 views
1

Я пытаюсь ускорить довольно длительную программу, которая изначально не была предназначена для параллельных вычислений. Поэтому я экспериментирую с автоматическим распараллеливанием с 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 
+1

Умный оптимизирующий компилятор (и оптимизирующие компиляторы может быть очень умным) поймет, что ничего не будет сделано со значением 'Y', так поэтому не нужно возиться с петлями, которые определяют' Y'. Точно так же он понял бы, что не нужно беспокоиться об определении «Х» и «А». Это приведет к краху всей программы вплоть до некоторых запросов таймера и некоторых выходных операторов. Я не исследовал, делает ли gfortran это или нет (время не предполагает), но с оптимизацией вы можете не выполнять то, что считаете себя. – IanH

+0

Первый цикл является очевидным кандидатом на коммутацию гнезд петли, но я не рассчитываю на то, что gfortran найдет это автоматически. Я также не рассчитываю на gfortran, выполняющий автоматическую замену dot_product в последнем. – tim18

+1

Помещение «print *, Y (1), Y (N)» перед освобождением() может быть полезно, чтобы избежать возможной ошибки уничтожения. С gfort-6.1 на osx10.9 установка -floop-nest-optimize сделала расчет почти в два раза быстрее @@ (я не знал, что эти параллельные (?) Варианты настолько интересны ...) – roygvib

ответ

0

Я считаю, что этот третий цикл, как правило, улучшается с OpenMP СОКРАЩЕНИЯ (или сокращения DIR $ DO SIMD на ifort!).

USE OMPLIB 
.... 
do i=1, N 
    !$OMP DO SIMD REDUCTION(+:Y) 
    do j=1, N 
     Y(i) = Y(i) + A(j, i) * X(j) 
    end do 
end do 

И с некоторыми работами, возможно, Y (I) может быть ЧАСТНЫМ, чтобы быть параллельным по петле I. Если рабочая нагрузка не высока, она редко делает так много улучшений для параллелизации по I-циклу для этих простых случаев.

YRMV

+0

Конечно, директивы OpenMP могут быть добавлены во многих местах кода. Речь идет о автоматической потоковой передаче и о том, почему она не масштабируется с количеством потоков.Директивы SIMD могут ускорить базовый код, но я сомневаюсь, что он вылечит масштабирование. Это может повредить его (более быстрый код сложнее сделать быстрее). –

+0

И обратите внимание, что это может помешать оптимизации гнезда. –

+0

@ Vladimir, что такое «экскурсионная операция»? Точка SIMD заключается в том, что это, кстати, полезно для векторной оптимизации ... И не столько для параллельной оптимизации. Большую часть времени он предпринимает определенные усилия, чтобы определить, где и как получить ускорение. – Holmz