4. Компиляция и компоновка
В начало страницы
В разделе на простом примере описывается, как вызывать п-б подпрограммы BLAS и LAPACK из OpenMP Fortran-программы.
В начало страницы
Рассмотрим систему линейных уравнений
Ax = b
где A есть вещественная полная матрица порядка n, b -- вектор правой части порядка n, а x --- вектор-решение. Для нас интересен случай, когда мы имеем много векторов правых частей, для каждого из которых нужно получить решение. Такая задача в матричной форме может быть записана как
AX = B
где каждый столбец из B , обозначаемый как bi ( i = 1,2,...,m) , представляет очередной вектор правой части, и каждый стобец из X, обозначаемый как xi
( i = 1,2,...,m) , есть вектор-решение, соответствующее bi
В начало страницы
Вообще говоря, пользователь должен выбрать подпрограмму DGESV из LAPACK, подпрограмму-драйвер, для решения уравнений в приведенной выше
матричной форме. Но в целях объяснения давайте воспользуемся родом
компонентных подпрограмм DGETRF и DGETRS, которые называются вычислительными
подпрограммами в руководстве по LAPACK. Первая из них вычисляет LU-факторизацию
заданной матрицы коэффициентов A, а вторая решает факторизованную систему,
находя решения X.
Предположим, что мы хотим решить уравнения порядка 200 при 80 различных векторах правых частей. Сначала рассмотрим применение обычных, не поточно-
безопасных BLAS и LAPACK. Пример такой программы приведен ниже, где подпрограмма inita устанавливает коэффициентную матрицу в массив a, матрица правых частей, состоящая из bi, устанавливается по заданным решениям, а подпрограмма check проверяет полученные опять решения xi
на их точность.
Пример с употреблением обычных, не п-б, BLAS и LAPACK
implicit real*8 (a-h,o-z)
parameter(maxn=200,m=80,k=maxn+1)
parameter(zero=0.0d0,one=1.0d0)
real*8 a(k,maxn),aa(k,maxn),x(k,m),b(k,m)
integer ip(maxn)
C ===========================================================
C Определение матрицы
C ===========================================================
n=maxn
call inita(a,k,n)
do i=1,n
do j=1,n
aa(j,i)=a(j,i)
end do
end do
C ===========================================================
C LU-разложение
C ===========================================================
call dgetrf(n,n,a,k,ip,info)
C ===========================================================
C Определение векторов
C ===========================================================
do jm=1,m
do jn=1,n
x(jn,jm)=jn+jm
end do
end do
call dgemm('N','N',n,m,n,one,aa,k,x,k,zero,b,k)
C ===========================================================
C Решение
C ===========================================================
call dgetrs('N',n,m,a,k,ip,b,k,info)
if(info.ne.0) then
write(6,*) 'error in dgetrs info = ',info
stop
end if
C ===========================================================
C Проверка результата
C ===========================================================
call check(a,b,k,n,m)
end
Теперь воспользуемся п-б версией LAPACK. LU-факторизация производится так же, как и в рассмотренном примере, но процедура получения решения X немного отличается и мы хотим использовать кратные CPU. В следующем примере вызываются подпрограммы п-б версии LAPACK. 80 векторов правых частей разделяются на группы, каждая содержит одно и то же количество, mblk, векторов правых частей и эти группы передаются одновременно подпрограмме DGETRS. Заметим также, что начальная установка X для получения правых частей производится блоками посредством вызова поточно-безопасной подпрограммы DGEMM для умножения матриц.
Пример BLAS, LAPACK п-б версии
implicit real*8 (a-h,o-z)
parameter(maxn=200,m=80,mblk=4,k=maxn)
parameter(zero=0.0d0,one=1.0d0)
real*8 a(k,maxn),aa(k,maxn),x(k,m),b(k,m)
integer ip(maxn)
C ===========================================================
C Определение матрицы
C ===========================================================
n=maxn
call inita(a,k,n)
do i=1,n
do j=1,n
aa(j,i)=a(j,i)
end do
end do
C ===========================================================
C LU-разложение
C ===========================================================
call dgetrf(n,n,a,k,ip,info)
!$OMP PARALLEL PRIVATE(mb,info)
!$OMP DO
do i=1,m,mblk
mb=min(mblk,m-i+1)
C ===========================================================
C Определение векторов
C ===========================================================
do jm=1,mb
do jn=1,n
x(jn,jm+i-1)=jn+i+jm-1
end do
end do
call dgemm('N','N',n,mb,n,one,aa,k,x(1,i),k,zero
& ,b(1,i),k)
C ===========================================================
C Решение
C ===========================================================
call dgetrs('N',n,mb,a,k,ip,b(1,i),k,info)
if(info.ne.0) then
write(6,*) 'error in dgetrs info = ',info
stop
end if
end do
!$OMP END PARALLEL
C ===========================================================
C Проверка результата
C ===========================================================
call check(a,b,k,n,m)
end
Пояснения
1. Пара директив !$OMP PARALLEL и !$OMP END PARALLEL определяют область параллельности, код между этими директивами выполняется параллельно кратными
потоками. Директива !$OMP PARALLEL создает группу кратных потоков, а предложение PRIVATE(...) указывает, что переменные или массивы в скобках
располагаются в своей копии памяти в каждом потоке. Переменные и массивы, которые не фигурируют в предложении PRIVATE, имеют только одну копию, разделяемую всеми потоками в параллельной части.
2. Директива !$OMP DO указывает, что конструкция DO, расположенная сразу после директивы, может исполняться параллельно по отношению к параметру DO в кратных потоках. Другими словами, вычисления для каждого значения параметра DO производятся в потоке асинхронно по отношению к остальным потокам.
3. Более важной характеристикой является то, что приведенный выше код может компилироваться без параметра --openmp, компоноваться с библиотеками
BLAS и LAPACK и затем правильно работать, выдавая те же результаты, хотя его исполнение будет итти дольше. Это происходит потому, что в таком случае директивы OpenMP рассматриваются как комментарии и выполняемые операторы Fortran ничем не отличаются от обычных конструкций Fortran.
В начало страницы
Поточно-безопасные версии BLAS и LAPACK должны вызываться из OpenMP Fortran программ. Компиляция должна производиться с помощью компилятора Fujitsu
Fortran. В настоящем разделе описываются процедуры компиляции таких программ. Пользователи, использующие подпрограммы и BLAS и LAPACK, должны следовать указаниям радела "4.2 Поточно-безопасная версия LAPACK", а подпрограммы BLAS могут компоноваться неявно.
В начало страницы
BLAS можно использовать компоновкой ее с пользовательскими программами, написанными на языке Fortran. Она компонуется с пользовательской программой при указании -lblasmt в командной строке для lf95. Пишите -lblasmt после исходных и объектных имен Fortran'а. Другие параметры, относящиеся к оптимизации, указываются по мере необходимости.
Например: lf95 a.f -lblasmt
Когда пользовательская программа написана с OpenMP Fortran API, требуется параметр --openmp.
Например:lf95 --openmp a.f -lblasmt
Исполнение программы производится указанием ее имени после приглашения. Количество создаваемых потоков может указываться переменной окружения OMP_NUM_THREADS. Нужно заметить, что при компиляции с параметром --openmp все массивы, используемые в программе пользователя, помещаются в области стека и может случиться, что стек превысит отведенные для него пределы. В таком случае пользователь может увеличить стек командой limit (в случае csh) или ulimit (в случаях sh или ksh).
В начало страницы
LAPACK может использоваться компоновкой ее с пользовательской программой, написанной на языке Fortran. Она присоединяется к пользовательской программе при указании -llapackmt в командной строке для lf95. Поскольку LAPACK вызывает BLAS, пишите -lblasmt после -llapackmt.
Пример: lf95 a.f -llapackmt -lblasmt
Если программа написана с OpenMP Fortran API, требуется параметр --openmp. Пример: lf95 --openmp a.f -llapackmt -lblasmt
Рис. 1 показывает ход обработки программы пользователя, использующей BLAS и LAPACK, от компиляции до исполнения.
Start
| --------------
| .........<....... |User Program|
| . --------------
---------------
| Fortran |
|(compilation)|
---.----------- -------------------
. | | BLAS library |
--------<................... | | |
|Object|.........>.......... | .........<...... | LAPACK library | ----- . | . | |
--------------- | Fortran library|
| Fortran | -------------------
| (Linkage) |
--.------------
------------<............... |
|Executable| |
| program |.........>...... |
------------ . |
-------------........>........: Data flow |(Execution)|------>------: Processing flow
-------------
|
End
Рис. 1 Ход обработки от компиляции до исполнения (BLAS, LAPACK)