Решение многопоточной линейной системы в OpenBLAS

У меня есть код, использующий Fortran 95 и компилятор gfortran. Я также использую OpenMP, и мне приходится обрабатывать очень большие массивы. В моем коде мне также приходится решать систему линейных уравнений с помощью решателя DGTSV от OpenBLAS. Я также хочу распараллелить этот решатель, используя openblas, который должен на это способен. Но у меня проблемы с синтаксисом. Используя приложенный псевдокод, все 4 процессора используются почти на 100%, но я не уверен, решает ли каждое ядро ​​линейные уравнения отдельно или они разбивают его на части и вычисляют параллельно. Весь материал скомпилирован с использованием gfortran -fopenmp -lblas a.f95 -o a.out

Итак, мой псевдокод выглядит так

program a
implicit none
integer, parameter  ::  N   =       200
real*8, dimension(numx) ::  D   =       0.0
real*8, dimension(numx-1):: DL  =       0.0
real*8, dimension(numx-1):: DU  =       0.0
real*8, dimension(numx) ::  b   =       0.0
integer         ::  info    =       0
integer :: numthread=4
...
!$OMP PARALLEL NUM_THREADS(numthread)
...
!$OMP DO
...
!$OMP END DO
CALL DGTSV(N,1,DL,D,DU,b,N,info)
!$OMP DO
...
!$OMP END DO
...
!$OMP END PARALLEL
end program a

Что мне нужно сделать, чтобы сделать решатель распараллеленным, чтобы каждое ядро ​​вычисляло части решателя?


person user1548953    schedule 24.07.2012    source источник
comment
Каждый поток решал бы всю систему линейных уравнений, повторяя работу всех остальных потоков, даже если бы OpenBLAS был скомпилирован с поддержкой OpenMP. Вам нужно вызвать DGTSV вне параллельного региона, и он создаст свой собственный параллельный регион внутри реализации подпрограммы.   -  person Hristo Iliev    schedule 24.07.2012
comment
круто, спасибо за быстрый ответ. Я попробую так.   -  person user1548953    schedule 25.07.2012
comment
Вы также можете поместить вызов DGTSV внутрь конструкции OpenMP SINGLE и включить вложенный параллелизм. Это сэкономит вам крошечную долю времени.   -  person Hristo Iliev    schedule 25.07.2012
comment
да спасибо! Я знаю этот вариант. Я узнаю, насколько велика экономия времени.   -  person user1548953    schedule 26.07.2012


Ответы (1)


Внутри параллельной области OpenMP все потоки выполняют один и тот же код (как в MPI), и работа разделяется только тогда, когда потоки достигают цикла/раздела/задачи.

В вашем примере работа внутри циклов (OMP DO) распределяется между доступными потоками. После завершения цикла неявный барьер синхронизирует все потоки, а затем они параллельно выполняют функцию DGTSV. После возврата подпрограммы цикл снова разделяется.

@HristoIliev предложил использовать пункт OMP SINGLE. Это ограничивает выполнение фрагмента кода внутри только одним потоком и заставляет все остальные потоки ждать его (если вы не укажете nowait).

С другой стороны, вложенный параллелизм вызывается в том случае, когда вы объявляете параллельную область внутри другой параллельной области. Это также применимо, когда вы выполняете вызовы параллельной библиотеки OpenMP внутри параллельного региона.

По умолчанию OpenMP не увеличивает параллелизм вложенных параллельных областей, вместо этого его может выполнить только поток, который входит в параллельную область. Это поведение можно изменить с помощью переменной среды с OMP_NESTED по true.

Решение OMP SINGLE намного лучше, чем разделение параллельной области на две части, так как ресурсы повторно используются для следующего цикла:

$!OMP PARALLEL
  $!OMP DO
  DO ...
  END DO

  $!OMP SINGLE
  CALL DGTSV(...)

  $!OMP DO
  DO ...
  END DO
$!OMP END PARALLEL

Чтобы проиллюстрировать использование OMP_NESTED, я покажу вам некоторые результаты, которые я получил от приложения, которое использовало FFTW (реализация быстрого преобразования Фурье), сконфигурированное для использования OpenMP. Выполнение выполнялось на 16-ядерном двухпроцессорном узле Intel Xeon E5 @2,46 ГГц.

На следующих графиках показано количество времени, затрачиваемое на все приложение, где параллельные регионы появляются, когда ЦП > 1, сериализованные регионы, когда ЦП = 1, и регионы синхронизации, когда ЦП = 0.

Приложение смущающе параллельно, поэтому в данном конкретном случае использование вложенности нецелесообразно (FFTW не так хорошо масштабируется).

Это исполнение OMP_NESTED=false. Обратите внимание, как количество параллелизма ограничено количеством потоков, потраченных во внешней параллельной области (ftdock).

Невложенная версия OpenMP

Это OMP_NESTED=true казнь. В этом случае можно увеличить параллелизм дальше, чем количество потоков, затраченных на внешнюю параллельную область. Максимально возможный параллелизм в этом случае равен 16, когда либо 8 внешних потоков создают один узел для выполнения внутренней параллельной области, либо 4 создают по 3 дополнительных потока каждый (8x2 = 4x4 = 16).

Вложенная версия OpenMP

person Jorge Bellon    schedule 06.10.2016
comment
Каков вывод? Может быть, это только я, но я понятия не имею, как интерпретировать этот график. Сама проблема (с FFTW) для меня очень актуальна. - person Vladimir F; 06.10.2016
comment
Вывод таков: как обычно бывает. График показывает, сколько потоков программа может выполнять параллельно (лучше всего, если у вас есть одна полоса больше 16, что является максимальным числом ядер). В моем конкретном примере лучшей стратегией было просто бросить 16 потоков во внешнюю параллельную область и использовать сериализованную версию библиотеки. В случае с OP, если процедура BLAS должна быть сериализована, хорошей отправной точкой будет использование вложенного параллелизма, хотя все эти барьеры синхронизации в какой-то момент ограничат масштабируемость. - person Jorge Bellon; 06.10.2016