Fortran-DVM - оглавление | Часть 1(1-4) | Часть 2 (5-6) | Часть 3 (7-15) | Часть
4 (Приложения) |
создан: октябрь, 2009 | - последнее обновление 01.12.09 - |
2.2. Синтаксис директив FDVM
directive-line |
is !DVM$ dvm-directive |
|
or CDVM$ dvm-directive |
|
or *DVM$ dvm-directive |
dvm-directive |
is specification-directive |
|
or executable-directive |
specification-directive |
is processors-directive |
|
or align-directive |
|
or distribute-directive |
|
or template-directive |
|
or pointer-directive |
|
or shadow-directive |
|
or dynamic-directive |
|
or inherit-directive |
|
or remote-group-directive |
|
or reduction-group-directive |
|
or consistent-directive |
|
or consistent-group-directive |
|
or task-directive |
|
or heap-directive |
|
or asyncid-directive |
executable-directive |
is realign-directive |
|
or redistribute-directive |
|
or parallel-directive |
|
or remote-access-directive |
|
or shadow-group-directive |
|
or shadow-start-directive |
|
or shadow-wait-directive |
|
or reduction-start-directive |
|
or reduction-wait-directive |
|
or consistent-start-directive |
|
or consistent-wait-directive |
|
or new-value-directive |
|
or prefetch-directive |
|
or reset-directive |
|
or parallel-task-loop-directive |
|
or map-directive |
|
or task-region-directive |
|
or end-task-region-directive |
|
or on-directive |
|
or end-on-directive |
|
or f90-directive |
|
or asynchronous-directive |
|
or end-asynchronous-directive |
|
or asyncwait-directive |
Ограничения:
Cпецкомментарий directive-line подчиняется правилам написания комментария в фиксированной или свободной форме в зависимости от формы исходного текста программной единицы.
Директивы спецификации должны находиться в разделе спецификаций.
Исполняемые директивы должны находиться среди исполняемых операторов.
Любое выражение, входящее в директиву спецификации, должно быть выражением спецификации.
Выражение спецификации – это выражение, в котором каждое первичное должно быть одной из следующих форм:
1) константа,
2) переменная, которая является формальным аргументом,
3) переменная из COMMON блока,
4) ссылка на встроенную функцию, где каждый аргумент является выражением спецификации,
5) выражение спецификации, заключенное в скобки.
3. Массивы виртуальных процессоров. Директива PROCESSORS
processors-directive |
is PROCESSORS processors-decl-list |
processors-decl |
is processors-name ( explicit-shape-spec-list ) |
explicit-shape-spec |
is [ lower-bound : ] upper-bound |
lower-bound |
is int-expr |
upper-bound |
is int-expr |
Ограничения.
Разрешается использовать несколько массивов виртуальных процессоров разной формы при следующем условии: количество процессоров в каждом массиве должно быть равно значению встроенной функции NUMBER_OF_PROCESSORS ( ).
Массивы данных с атрибутами COMMON и SAVE могут быть отображены на локальные массивы виртуальных процессоров при следующем условии: при каждом вызове процедуры локальный массив процессоров имеет одно и то же определение.
4.1. Директивы DISTRIBUTE и REDISTRIBUTE
distribute-directive |
is dist-action distributee dist-directive-stuff |
|
or dist-action [ dist-directive-stuff ] :: distributee-list |
dist-action |
is DISTRIBUTE |
|
or REDISTRIBUTE |
dist-directive-stuff |
is dist-format-list [ dist-onto-clause ] |
distributee |
is array-name |
|
or pointer-name |
|
or template-name |
dist-format |
is BLOCK |
|
or GEN_BLOCK ( block-size-array ) |
|
or WGT_BLOCK ( block-weight-array , nblock) |
|
or MULT_BLOCK ( divisor ) |
|
or * |
dist-onto-clause |
is ONTO dist-target |
dist-target |
is processors-name [(processors-section-subscript-list )] |
|
|
or task-name ( task-index ) |
|
|
|
|
processors-section-subscript |
is [ subscript ] : [ subscript ] |
|
|
|
|
subscript |
is int-expr |
|
|
|
|
divisor |
is int-expr |
|
|
|
|
nblock |
is int-expr |
|
|
|
|
block-size-array |
is array-name |
|
|
|
|
block-weight-array |
is array-name |
Ограничения:
Длина списка dist-format-list должна быть равна количеству измерений массива. Т.е. для каждого измерения должен быть задан формат распределения.
Количество распределенных измерений массива (формат задан не *) должно быть равно количеству измерений массива процессоров в dist-target.
Массив block-size-array в спецификации GEN_BLOCK, должен быть одномерным целочисленным массивом, размер которого равен размеру соответствующего измерения массива процессоров, а сумма значений его элементов равна размеру распределяемого измерения.
Массив block-weight-array в спецификации WGT_BLOCK, должен быть одномерным массивом типа DOUBLE PRECISION.
В одном списке dist-format-list не может быть указан формат GEN_BLOCK и формат WGT_BLOCK.
Директива REDISTRIBUTE может применяться только к массивам со спецификацией DYNAMIC.
Отсутствие dist-directive-stuff допустимо только в директиве DISTRIBUTE. В этом случае распределяемый массив может использоваться только после выполнения директивы REDISTRIBUTE.
4.3.1. Директивы ALIGN и REALIGN
align-directive |
is align-action alignee align-directive-stuff |
|
or align-action [ align-directive-stuff ] :: alignee‑list |
align-action |
is ALIGN |
|
or REALIGN |
|
|
align-directive-stuff |
is ( align-source-list ) align-with-clause |
|
|
alignee |
is array-name |
|
or pointer-name |
align-source |
is * |
|
or align-dummy |
align-dummy |
is scalar-int-variable |
align-with-clause |
is WITH align-spec |
|
|
align-spec |
is align-target ( align-subscript-list ) |
align-target |
is array-name |
|
or template-name |
|
or pointer-name |
align-subscript |
is int-expr |
|
or align-dummy-use |
|
or * |
align-dummy-use |
is [ primary-expr * ] align‑dummy [ add-op primary-expr ] |
primary-expr |
is int-constant |
|
or int-variable |
|
or ( int-expr ) |
|
|
add-op |
is + |
|
or - |
Ограничения:
Длина списка align-source-list должна быть равна количеству измерений выравниваемого массива.
Длина списка align-subscript-list должна быть равна количеству измерений базового массива align-target.
Директива REALIGN может применяться только к массивам со спецификацией DYNAMIC.
Отсутствие align-directive-stuff допустимо только в директиве ALIGN. В этом случае распределяемый массив может использоваться только после выполнения директивы REALIGN.
4.3.2. Директива TEMPLATE
template-directive |
is TEMPLATE template-decl-list |
template-decl |
is template-name [ ( explicit-shape-spec-list ) ] |
4.4. Директивы DYNAMIC и NEW_VALUE
dynamic-directive |
is DYNAMIC alignee-or-distributee-list |
|
|
alignee-or-distributee |
is alignee |
|
or distribute |
new-value-directive |
is NEW_VALUE |
5.1.2. Распределение витков цикла. Директива PARALLEL
parallel-directive |
is PARALLEL ( do-variable-list ) ON iteration-align-spec [ , new-clause ] [ , reduction-clause] [ , shadow-renew-clause] [ , shadow-compute-clause] [ , remote-access-clause ] [ , across-clause ] [ , consistent-clause ] |
iteration-align-spec |
is align-target ( iteration-align-subscript-list ) |
iteration-align-subscript |
is int-expr |
|
or do-variable-use |
|
or * |
|
|
do-variable-use |
is [ primary-expr * ] do-variable [ add-op primary-expr ] |
5.1.3. Приватные переменные. Спецификация NEW
new-clause |
is NEW ( new-variable-list ) |
new-variable |
is array-name |
|
or scalar-variable-name |
Ограничение:
· NEW-переменные не могут быть распределенными массивами.
5.1.4. Редукционные операции и переменные. Спецификация REDUCTION
reduction-clause |
is REDUCTION ( [ reduction-group-name : ] reduction-op-list ) |
reduction-op |
is reduction-op-name ( reduction-variable ) |
|
or reduction-loc-name ( reduction-variable , location-variable, int-expr) |
reduction-variable |
is array-name |
|
or scalar-variable-name |
location-variable |
is array-name |
reduction-op-name |
is SUM |
|
or PRODUCT |
|
or MAX |
|
or MIN |
|
or AND |
|
or OR |
|
or EQV |
|
or NEQV |
reduction-loc-name |
is MAXLOC |
|
or MINLOC |
Ограничение:
· Редукционные переменные вычисляются и используются только в операторах определенного вида - редукционных операторах.
6.2.1.Спецификация массива с теневыми гранями
shadow-directive |
is SHADOW dist-array ( shadow-edge-list ) |
|
or SHADOW ( shadow-edge-list ) :: dist-array-list |
dist-array |
is array-name |
|
or pointer-name |
shadow-edge |
is width |
|
or low-width : high-width |
width |
is int-expr |
low-width |
is int-expr |
high-width |
is int-expr |
Ограничения:
Размер левой теневой грани (low-width) и размер правой теневой грани (high-width) должны быть целыми константными выражениями, значения которых больше или равны 0.
Задание размера теневых граней как width эквивалентно заданию width : width.
По умолчанию, распределенный массив имеет теневые грани шириной 1 с обеих сторон каждого распределенного измерения.
6.2.2. Синхронная спецификация независимых ссылок типа SHADOW для одного цикла
shadow-renew-clause |
is SHADOW_RENEW ( renewee‑list ) |
|
or shadow-start-directive |
|
or shadow-wait-directive |
renewee |
is dist-array-name [ ( shadow-edge-list ) ] [ (CORNER) ] |
Ограничения:
Размер теневых граней, заполняемых значениями, не должен превышать максимального размера, описанного в директиве SHADOW.
Если размеры теневых граней не указаны, то используются максимальные размеры.
6.2.3. Вычисление значений в теневых гранях. Спецификация SHADOW_COMPUTE
shadow-compute-clause |
is SHADOW_COMPUTE [( dist-array-name ( shadow-edge-list ) )] |
6.2.4. Спецификация AСROSS зависимых ссылок типа SHADOW для одного цикла
across-clause |
is ACROSS ( dependent-array-list ) |
dependent-array |
is dist-array-name ( dependence-list ) [(section-spec-list)] |
dependence |
is flow-dep-length : anti-dep-length |
|
|
|
|
flow-dep-length |
is int-constant |
|
|
|
|
anti-dep-length |
is int-constant |
|
|
|
|
section-spec |
is SECTION ( section-subscript-list ) |
Ограничение:
· В каждой ссылке на массив может существовать зависимость по данным только по одному распределенному измерению.
6.2.5. Асинхронная cпецификация независимых ссылок типа SHADOW
shadow-group-directive |
is SHADOW_GROUP shadow-group-name ( renewee-list ) |
shadow-start-directive |
is SHADOW_START shadow-group-name |
shadow-wait-directive |
is SHADOW_WAIT shadow-group-name |
Ограничения.
Директива SHADOW_START должна выполняться после директивы SHADOW_GROUP.
Директива SHADOW_WAIT должна выполняться после директивы SHADOW_START.
Новые значения в теневых гранях могут использоваться только после выполнения директивы SHADOW_WAIT.
Директивы асинхронного обновления теневых граней не могут использоваться внутри параллельного цикла.
6.3.1. Директива REMOTE_ACCESS
remote-access-directive |
is REMOTE_ACCESS ( [ remote-group-name ] regular-reference-list) |
|
|
regular-reference |
is dist-array-name [( regular-subscript-list )] |
|
|
regular-subscript |
is int-expr |
|
or do-variable-use |
|
or : |
|
|
remote-access-clause |
is remote-access-directive |
6.3.3. Асинхронная спецификация удаленных ссылок типа REMOTE
remote-group-directive |
is REMOTE_GROUP remote-group-name-list |
Ограничение:
· Идентификатор, определенный этой директивой, может использоваться только в директивах REMOTE_ACCESS , PREFETCH и RESET.
prefetch-directive |
is PREFETCH remote-group-name |
|
|
reset-directive |
is RESET remote-group-name |
Ограничения.
Повторное выполнение директивы PREFETCH является корректным только в том случае, когда характеристики группы удаленных ссылок (параметры циклов, распределения массивов и значения индексных выражений в удаленных ссылках) не меняются.
Директиву PREFETCH можно выполнять для нескольких циклов (нескольких директив REMOTE_ACCESS), если между этими циклами не существует зависимости по данным для распределенных массивов, указанных в директивах REMOTE_ACCESS.
6.3.4.2.1. Директива ASYNCID
asyncid-directive |
is ASYNCID async-name-list |
|
|
6.3.4.2.2. Директивы ASYNCHRONOUS и END ASYNCHRONOUS
asynchronous-construct |
is asynchronous-directive |
|
copy-statement [ copy-statement ] … |
|
end-asynchronous-directive |
|
|
asynchronous-directive |
is ASYNCHRONOUS async-name |
|
|
end-asynchronous-directive |
is END ASYNCHRONOUS |
6.3.4.2.3. Директива ASYNCWAIT
asyncwait-directive |
is ASYNCWAIT async-name |
6.4.2. Асинхронная спецификация удаленных ссылок типа REDUCTION
reduction-group-directive |
is REDUCTION_GROUP reduction-group-name-list |
reduction-start-directive |
is REDUCTION_START reduction-group-name |
reduction-wait-directive |
is REDUCTION_WAIT reduction-group-name |
Ограничения.
До выполнения директивы REDUCTION_START редукционные переменные группы могут использоваться только в редукционных операторах параллельных циклов.
Директива REDUCTION_START и REDUCTION_WAIT должны выполняться после окончания цикла (циклов), где вычислялись значения редукционных переменных. Между этими операторами могут выполняться только те операторы, в которых не используются значения редукционных переменных.
Директива REDUCTION_WAIT уничтожает группу редукционных операций.
7.1. Описание массива задач
task-directive |
is TASK task-list |
|
|
task |
is task-name ( max-task ) |
|
|
7.2. Отображение задач на процессоры. Директива MAP
map-directive |
is MAP task-name ( task-index ) |
|
ONTO processors-name( processors-section-subscript-list) |
7.4. Распределение вычислений. Директива TASK_REGION
block-task-region |
is task-region-directive |
|
on-block |
|
[ on-block ]... |
|
end-task-region-directive |
|
|
task-region-directive |
is TASK_REGION task-name [ , reduction-clause ] |
|
[ , consistent-clause ] |
|
|
end-task-region-directive |
is END TASK_REGION |
|
|
on-block |
is on-directive |
|
block |
|
end-on-directive |
|
|
on-directive |
is ON task-name ( task-index ) [ , new-clause ] |
|
|
end-on-directive |
is END ON |
|
|
loop-task-region |
is task-region-directive |
|
parallel-task-loop |
|
end-task-region-directive |
|
|
parallel-task-loop |
is parallel-task-loop-directive |
|
do-loop |
|
|
parallel-task-loop-directive |
is PARALLEL ( do-variable ) ON task-name ( do-variable ) [ , new-clause ] |
8.3.1. Директива CONSISTENT
consistent-directive |
is CONSISTENT array-name-list |
8.3.2. Опция CONSISTENT
consistent-clause |
is CONSISTENT ([consistent-group-name : ] array-reference-list) |
array-reference |
is array-name ( regular-subscript-list ) |
regular-subscript |
is int-expr |
|
or do-variable-use |
|
or : |
8.3.3. Спецификация асинхронного выполнения приведения в консистентное состояние
consistent-group-directive |
is CONSISTENT_GROUP consistent-group-name-list |
consistent-start-directive |
is CONSISTENT_START consistent-group-name |
consistent-start-directive |
is CONSISTENT_WAIT consistent-group-name |
9. Процедуры
inherit-directive |
is INHERIT dummy-array-name-list |
Приложение 2. Примеры программ
Семь небольших программ из научной области приводятся для иллюстрации свойств языка Fortran DVM. Они предназначены для решения систем линейных уравнений:
A x = b
где A – матрица коэффициентов,
b – вектор свободных членов,
x – вектор неизвестных.
Для решения этой системы используются следующие основные методы.
Прямые методы. Хорошо известный метод исключения Гаусса является наиболее широко используемым алгоритмом этого класса. Основная идея алгоритма заключается в преобразовании матрицы А в верхнетреугольную матрицу и использовании затем обратной подстановки, чтобы привести ее к диагональной форме.
Явные итерационные методы. Наиболее известным алгоритмом этого класса является метод релаксации Якоби. Алгоритм выполняет следующие итерационные вычисления
xi,jnew = (xi-1,jold + xi,j-1old + xi+1,jold + xi,j+1old ) / 4
Неявные итерационные методы. К этому классу относится метод последовательной верхней релаксации. Итерационное приближение вычисляется по формуле
xi,jnew = ( w / 4 ) * (xi-1,jnew + xi,j-1new + xi+1,jold + xi,j+1old ) + (1-w) * xi,jold
При использовании "красно-черного" упорядочивания переменных каждый итерационный шаг разделяется на два полушага Якоби. На одном полушаге вычисляются значения "красных" переменных, на другом – "черных" переменных. "Красно-черное" упорядочивание позволяет совместить вычисления и обмены данными.
Пример 1. Алгоритм метода исключения Гаусса
PROGRAM GAUSS
C решение системы линейных уравнений A´ x = b
PARAMETER ( N = 100 )
REAL A( N, N+1 ), X( N )
C A : матрица коэффициентов (N,N+1).
C вектор правых частей линейных уравнений хранится
C в (N+1)-ом столбце матрицы A
C X : вектор неизвестных
C N : число линейных уравнений
CDVM$ DISTRIBUTE A ( BLOCK, *)
CDVM$ ALIGN X(I) WITH A(I, N+1)
C
C Инициализация
C
*DVM$ PARALLEL ( I ) ON A( I , * )
DO 100 I = 1, N
DO 100 J = 1, N+1
IF (( I .EQ. J ) THEN
A( I, J ) = 2.0
ELSE
IF ( J .EQ. N+1) THEN
A( I, J ) = 0.0
ENDIF
ENDIF
100 CONTINUE
C
C Исключение
C
DO 1 I = 1, N
C I-ая строка матрицы A буферизуется перед
C обработкой I-ого уравнения, и ссылки A(I,K), A(I, I)
C заменяются соответствующими ссылками на буфер
*DVM$ PARALLEL ( J ) ON A( J, * ) , REMOTE_ACCESS (A ( I, : ))
DO 5 J = I+1, N
DO 5 K = I+1, N+1
A( J, K ) = A( J, K ) - A( J, I ) * A( I, K ) / A( I, I )
5 CONTINUE
1 CONTINUE
C сначала вычисляется X(N)
X( N ) = A( N, N+1 ) / A( N, N )
C
C Нахождение X(N-1), X(N-2), ...,X(1) обратной подстановкой
C
DO 6 J = N-1, 1, -1
C (J+1)-ый элемент массива X буферизуется перед
C обработкой J-ого уравнения, и ссылка X(J+1)
C заменяется соответствующей ссылкой на буфер
*DVM$ PARALLEL ( I ) ON A( I , * ) , REMOTE_ACCESS ( X( J+1 ))
DO 7 I = 1, J
A( I, N+1 ) = A( I, N+1 ) - A( I, J+1 ) * X( J+1 )
7 CONTINUE
X( J ) = A( J, N+1 ) / A( J, J)
6 CONTINUE
PRINT *, X
END
PROGRAM JACOB
PARAMETER (K=8, ITMAX=20)
REAL A(K,K), B(K,K), EPS, MAXEPS
CDVM$ DISTRIBUTE A ( BLOCK, BLOCK)
CDVM$ ALIGN B( I, J ) WITH A( I, J )
C массивы A и B распределяются блоками
PRINT *, '********** TEST_JACOBI **********'
MAXEPS = 0.5E - 7
CDVM$ PARALLEL (J,I) ON A(I, J)
C гнездо из двух параллельных циклов, итерация (i,j) выполняется,
C на том процессоре, где размещен элемент A(i,j)
DO 1 J = 1, K
DO 1 I = 1, K
A(I, J) = 0.
IF(I.EQ.1 .OR. J.EQ.1 .OR. I.EQ.K .OR. J.EQ.K) THEN
B(I, J) = 0.
ELSE
B(I, J) = ( 1. + I + J )
ENDIF
1 CONTINUE
DO 2 IT = 1, ITMAX
EPS = 0.
CDVM$ PARALLEL (J, I) ON A(I, J), REDUCTION ( MAX( EPS ))
C переменная EPS используется для вычисления максимального значения
DO 21 J = 2, K-1
DO 21 I = 2, K-1
EPS = MAX ( EPS, ABS( B( I, J) - A( I, J)))
A(I, J) = B(I, J)
21 CONTINUE
CDVM$ PARALLEL (J, I) ON B(I, J), SHADOW_RENEW (A)
C копирование теневых элементов массива A
C с соседних процессоров перед выполнением цикла
DO 22 J = 2, K-1
DO 22 I = 2, K-1
B(I, J) = (A( I-1, J ) + A( I, J-1 ) + A( I+1, J) + A( I, J+1 )) / 4
22 CONTINUE
PRINT *, 'IT = ', IT, ' EPS = ', EPS
IF ( EPS . LT . MAXEPS ) GO TO 3
2 CONTINUE
3 OPEN (3, FILE='JACOBI.DAT', FORM='FORMATTED')
WRITE (3,*) B
CLOSE (3)
END
Пример 3. Алгоритм Якоби (асинхронный вариант)
PROGRAM JACOB1
PARAMETER (K=8, ITMAX=20)
REAL A(K,K), B(K,K), EPS, MAXEPS
CDVM$ DISTRIBUTE A ( BLOCK, BLOCK)
CDVM$ ALIGN B( I, J ) WITH A( I, J )
C массивы A и B распределяются блоками
CDVM$ REDUCTION_GROUP REPS
PRINT *, '********** TEST_JACOBI_ASYNCHR **********'
CDVM$ SHADOW_GROUP SA ( A )
C создание группы теневых граней
MAXEPS = 0.5E - 7
CDVM$ PARALLEL (J,I) ON A(I, J)
C параллельный цикл для инициализации массивов А и В
DO 1 J = 1, K
DO 1 I = 1, K
A(I, J) = 0.
IF(I.EQ.1 .OR. J.EQ.1 .OR. I.EQ.K .OR. J.EQ.K) THEN
B(I, J) = 0.
ELSE
B(I, J) = ( 1. + I + J )
ENDIF
1 CONTINUE
DO 2 IT = 1, ITMAX
EPS = 0.
C создается группа редукционных операций
C и начальные значения редукционных переменных запоминаются
CDVM$ PARALLEL (J, I) ON A(I, J), SHADOW_START SA ,
CDVM$* REDUCTION_GROUP ( REPS : MAX( EPS ))
C изменяется порядок выполнения витков цикла:
C сначала вычисляются и посылаются граничные элементы массива A,
C затем вычисляются внутренние элементы массива A
DO 21 J = 2, K-1
DO 21 I = 2, K-1
EPS = MAX ( EPS, ABS( B( I, J) - A( I, J)))
A(I, J) = B(I, J)
21 CONTINUE
CDVM$ REDUCTION_START REPS
C начало редукционной операции над частичными результатами,
C вычисленными в копиях переменной EPS на каждом процессоре
CDVM$ PARALLEL (J, I) ON B(I, J), SHADOW_WAIT SA
C изменяется порядок выполнения витков цикла:
C сначала вычисляются внутренние элементы массива B , затем принимаются
C от соседних процессоров теневые элементы массиваA,
C а потом вычисляются граничные элементы массива B
DO 22 J = 2, K-1
DO 22 I = 2, K-1
B(I, J) = (A( I-1, J ) + A( I, J-1 ) + A( I+1, J) + A( I, J+1 )) / 4
22 CONTINUE
CDVM$ REDUCTION_WAIT REPS
C ожидается результат выполнения редукционной операции
PRINT *, 'IT = ', IT, ' EPS = ', EPS
IF ( EPS . LT . MAXEPS ) GO TO 3
2 CONTINUE
3 OPEN (3, FILE='JACOBI.DAT', FORM='FORMATTED')
WRITE (3,*) B
CLOSE (3)
END
Пример 4. Последовательная верхняя релаксация
PROGRAM SOR
PARAMETER ( N = 100 )
REAL A( N, N ), EPS, MAXEPS, W
INTEGER ITMAX
*DVM$ DISTRIBUTE A ( BLOCK, BLOCK )
ITMAX=20
MAXEPS = 0.5E - 5
W = 0.5
*DVM$ PARALLEL ( I, J ) ON A( I, J )
DO 1 I = 1, N
DO 1 J = 1, N
IF ( I .EQ.J) THEN
A( I, J ) = N + 2
ELSE
A( I, J ) = -1.0
ENDIF
1 CONTINUE
DO 2 IT = 1, ITMAX
EPS = 0.
*DVM$ PARALLEL ( I, J) ON A( I, J), NEW (S),
*DVM$* REDUCTION ( MAX( EPS )), ACROSS (A(1:1,1:1))
C переменная S – приватная переменная
С (ее использование локализовано в пределах одного витка)
C переменная EPS используется для вычисления максимума
DO 21 I = 2, N-1
DO 21 J = 2, N-1
S = A( I, J )
A( I, J ) = (W / 4) * (A( I-1, J ) + A( I+1, J ) + A( I, J-1 ) +
* A( I, J+1 )) + ( 1-W ) * A( I, J)
EPS = MAX ( EPS, ABS( S - A( I, J )))
21 CONTINUE
PRINT *, 'IT = ', IT, ' EPS = ', EPS
IF (EPS .LT. MAXEPS ) GO TO 4
2 CONTINUE
4 PRINT *, A
END
Пример 5. "Красно-черная" последовательная верхняя релаксация
PROGRAM REDBLACK
PARAMETER ( N = 100 )
REAL A( N, N ), EPS, MAXEPS, W
INTEGER ITMAX
*DVM$ DISTRIBUTE A ( BLOCK, BLOCK )
ITMAX=20
MAXEPS = 0.5E - 5
W = 0.5
*DVM$ PARALLEL ( I, J ) ON A( I, J )
DO 1 I = 1, N
DO 1 J = 1, N
IF ( I .EQ.J) THEN
A( I, J ) = N + 2
ELSE
A( I, J ) = -1.0
ENDIF
1 CONTINUE
DO 2 IT = 1, ITMAX
EPS = 0.
C цикл для красных и черных переменных
DO 3 IRB = 1,2
*DVM$ PARALLEL ( I, J) ON A( I, J), NEW (S),
*DVM$* REDUCTION ( MAX( EPS )), SHADOW_RENEW (A)
C переменная S – приватная переменная
С (ее использование локализовано в пределах одного витка)
C переменная EPS используется для вычисления максимума
C Исключение : непрямоугольное итерационное пространство
DO 21 I = 2, N-1
DO 21 J = 2 + MOD ( I+ IRB, 2 ), N-1, 2
S = A( I, J )
A( I, J ) = (W / 4) * (A( I-1, J ) + A( I+1, J ) + A( I, J-1 ) +
* A( I, J+1 )) + ( 1-W ) * A( I, J)
EPS = MAX ( EPS, ABS( S - A( I, J )))
21 CONTINUE
3 CONTINUE
PRINT *, 'IT = ', IT, ' EPS = ', EPS
IF (EPS .LT. MAXEPS ) GO TO 4
2 CONTINUE
4 PRINT *, A
END
Пример 6. Статические задачи (параллельные секции)
PROGRAM TASKS
C прямоугольная сетка разделена на две области
C
|
|
K |
C |
N1 |
A1, B1 |
C |
N2 |
A2, B2 |
C
PARAMETER (K=100, N1 = 50, ITMAX=10, N2 = K – N1 )
CDVM$ PROCESSORS P(NUMBER_OF_PROCESSORS( ))
REAL A1(N1+1,K), A2(N2+1,K), B1(N1+1,K), B2(N2+1,K)
INTEGER LP(2), HP(2)
CDVM$ TASK MB( 2 )
CDVM$ ALIGN B1( I, J ) WITH A1( I, J )
CDVM$ ALIGN B2( I, J ) WITH A2( I, J )
CDVM$ DISTRIBUTE :: A1, A2
CDVM$ REMOTE_GROUP BOUND
CALL DPT(LP, HP, 2)
C Распределение задач (областей) по процессорам.
C Распределение массивов по задачам
CDVM$ MAP MB( 1 ) ONTO P( LP(1) : HP(1) )
CDVM$ REDISTRIBUTE A1( *, BLOCK ) ONTO MB( 1 )
CDVM$ MAP MB( 2 ) ONTO P( LP(2) : HP(2) )
CDVM$ REDISTRIBUTE A2( *, BLOCK ) ONTO MB( 2 )
C Инициализация
CDVM$ PARALLEL ( J, I ) ON A1(I, J)
DO 10 J = 1, K
DO 10 I = 1, N1
IF(I.EQ.1 .OR. J.EQ.1 .OR. J.EQ.K) THEN
A1(I, J) = 0.
B1(I, J) = 0.
ELSE
B1(I, J) = 1. + I + J
A1(I, J) = B1(I, J)
ENDIF
10 CONTINUE
CDVM$ PARALLEL ( J, I ) ON A2(I, J)
DO 20 J = 1, K
DO 20 I = 2, N2+1
IF(I.EQ.N2+1 .OR. J.EQ.1 .OR. J.EQ.K) THEN
A2(I, J) = 0.
B2(I, J) = 0.
ELSE
B2(I, J) = 1. + ( I + N1 – 1 ) + J
A2(I, J) = B2(I, J)
ENDIF
20 CONTINUE
DO 2 IT = 1, ITMAX
CDVM$ PREFETCH BOUND
C обмен границ
CDVM$ PARALLEL ( J ) ON A1(N1+1, J),
CDVM$* REMOTE_ACCESS (BOUND : B2( 2, J ) )
DO 30 J = 1, K
30 A1(N1+1, J) = B2(2, J)
CDVM$ PARALLEL ( J ) ON A2( 1, J),
CDVM$* REMOTE_ACCESS (BOUND : B1( N1, J ) )
DO 40 J = 1, K
40 A2(1, J) = B1(N1, J)
CDVM$ TASK_REGION MB
CDVM$ ON MB( 1 )
CDVM$ PARALLEL ( J, I ) ON B1(I, J),
CDVM$* SHADOW_RENEW ( A1 )
DO 50 J = 2, K-1
DO 50 I = 2, N1
50 B1(I, J) = (A1( I-1, J ) + A1( I, J-1 ) + A1( I+1, J) + A1( I, J+1 )) / 4
CDVM$ PARALLEL ( J, I ) ON A1(I, J)
DO 60 J = 2, K-1
DO 60 I = 2, N1
60 A1(I, J) = B1( I, J )
CDVM$ END ON
CDVM$ ON MB( 2 )
CDVM$ PARALLEL ( J, I ) ON B2(I, J),
CDVM$* SHADOW_RENEW ( A2 )
DO 70 J = 2, K-1
DO 70 I = 2, N2
70 B2(I, J) = (A2( I-1, J ) + A2( I, J-1 ) + A2( I+1, J) + A2( I, J+1 )) / 4
CDVM$ PARALLEL ( J, I ) ON A2(I, J)
DO 80 J = 2, K-1
DO 80 I = 2, N2
80 A2(I, J) = B2( I, J )
CDVM$ END ON
CDVM$ END TASK_REGION
2 CONTINUE
PRINT *, 'A1 '
PRINT *, A1
PRINT *, 'A2 '
PRINT *, A2
END
SUBROUTINE DPT( LP, HP, NT )
C распределение процессоров для NT задач (NT = 2)
INTEGER LP(2), HP(2)
NUMBER_OF_PROCESSORS( ) = 1
NP = NUMBER_OF_PROCESSORS( )
NTP = NP/NT
IF(NP.EQ.1) THEN
LP(1) = 1
HP(1) = 1
LP(2) = 1
HP(2) = 1
ELSE
LP(1) = 1
HP(1) = NTP
LP(2) = NTP+1
HP(2) = NP
END IF
END
Пример 7. Динамические задачи (цикл задач)
PROGRAM MULTIBLOCK
С Модель многообластной задачи.
C Количество областей, размер каждой области, внешние и внутренние границы
C определяются во время выполнения программы.
C Тест следующих конструкций FDVM: динамические массивы,
C динамические задачи, асинхронный REMOTE_ACCESS для динамических
C массивов (формальных параметров)
*DVM$ PROCESSORS MBC100( NUMBER_OF_PROCESSORS( ) )
PARAMETER (M = 8, N =8, NTST = 1)
C MXBL – максимальное количество областей
PARAMETER ( MXBL=2 )
TYPE BLK
REAL, POINTER, DIMENSION (:,:) :: PA, PB
*DVM$ ALIGN :: PB
*DVM$ DISTRIBUTE :: PA
*DVM$ DYNAMIC PA,PB
END TYPE BLK
TYPE (BLK) :: block(MXBL)
C block(I)%PA, block(I)%PB –
C значение функции на предыдущем и текущем шаге в I–ой области
C отложенное распределение массивов по каждой области
REAL, POINTER, DIMENSION( :, : ) :: P1, P2
*DVM$ DYNAMIC P1, P2
*DVM$ DISTRIBUTE :: P1
*DVM$ ALIGN :: P2
C SIZE( 1:2, I) – размеры измерений I–ой области
INTEGER SIZE( 2, MXBL )
C TINB( :,I ) – таблица внутренних границ I–ой области
C TINB( 1,I ) - - количество границ (от 1 до 4)
C TINB( 2,I ) = J - номер смежной области
C TINB( 3,I ), TINB( 4,I ) - границы одномерной секции
C TINB( 5,I ) - номер измерения в I-ой области (1 или 2)
C TINB( 6,I ) - координата измерения в I-ой области
C TINB( 7,I ) - номер измерения в J-ой области
C TINB( 8,I ) - координата измерения в J-ой области
INTEGER TINB( 29, MXBL )
C TEXB( :,I ) – таблица внешних границ I–ой области
C TEXB( 1,I ) - - количество границ (от 1 до 4)
C TEXB( 2,I ), TEXB( 3,I ) - координаты одномерной секции массива
C для 1-ой границы
C TEXB( 4,I ) - номер измерения (1 или 2)
C TEXB( 5,I ) - координата по данному измерению
INTEGER TEXB(17,MXBL)
C NBL - количество областей
C NTST – количество шагов
INTEGER NBL, NTST
C IDM – указатель на свободное место динамической памяти
INTEGER IDM
COMMON IDM
C массив задач
*DVM$ TASK TSA ( MXBL )
C имя группового обмена внутренних границ
*DVM$ REMOTE_GROUP GRINB
C LP( I ), HP( I ) – границы секции массива процессоров I-ой области
INTEGER LP(MXBL), HP(MXBL)
C TGLOB( :, I ) – таблица глобальных координат в сетке алгоритма Якоби
C для I-ой области
C TGLOB( 1, I ) – координата по 1-му измерению
C TGLOB( 2, I ) – координата по 2-му измерению
INTEGER TGLOB(2,MXBL)
INTERFACE
SUBROUTINE CMPINB ( AI, AJ, N1, N2, M1, M2, S1, S2, ID, INDI, JD, INDJ)
C вычисление величин на внутренних границах
REAL, POINTER, DIMENSION(:,:) :: AI, AJ
END
SUBROUTINE INEXB(A,B,N1,N2,S1,S2,ID,INDI)
C инициализация внешних границ
REAL, POINTER, DIMENSION(:,:) :: A,B
END
SUBROUTINE INDOM(A,B,M,N,X1,X2)
C инициализация областей
REAL, POINTER, DIMENSION(:,:) :: A, B
END
SUBROUTINE PRTB(B,N,M,IB)
C печать данных для области IB
REAL, POINTER, DIMENSION(:,:) :: B
END
SUBROUTINE JACOBI(A,B,N,M)
REAL, POINTER, DIMENSION(:,:) :: A, B
END
END INTERFACE
C разделение области M´N на подобласти
CALL DISDOM(NBL,TGLOB,TEXB,TINB,SIZE,M,N,MXBL)
C Разделение массива процессоров по областям
CALL MPROC(LP,HP,SIZE,NBL)
C Распределение задач (областей) по процессорам.
C Распределение массивов по задачам
IDM = 1
DO 10 IB = 1, NBL
*DVM$ MAP TSA( IB ) ONTO MBC100( LP(IB) : HP(IB) )
ALLOCATE (block(IB)%PA(SIZE(1, IB), SIZE(2, IB)))
P1 => block(IB)%PA
*DVM$ REDISTRIBUTE ( *, BLOCK ) ONTO TSA( IB ) :: P1
ALLOCATE (block(IB)%PB(SIZE(1, IB), SIZE(2, IB)))
P2 => block(IB)%PB
*DVM$ REALIGN P2( I, J ) WITH P1( I, J )
10 CONTINUE
C Инициализация внешних границ
DO 20 IB=1,NBL
LS =0
DO 20 IS = 1,TEXB(1,IB)
CALL INEXB (block(IB)%PA, block(IB)%PB,
* SIZE(1,IB), SIZE(2,IB),
* TEXB(LS+2,IB), TEXB(LS+3,IB), TEXB(LS+4,IB),
* TEXB(LS+5,IB) )
LS = LS+4
20 CONTINUE
C Инициализация областей
DO 25 IB = 1,NBL
CALL INDOM (block(IB)%PA, block(IB)%PB,
* SIZE(1,IB), SIZE(2,IB),
* TGLOB(1,IB), TGLOB(2,IB))
LS = LS+4
25 CONTINUE
DO 65 IB = 1,NBL
CALL PRTB(block(IB)%PA, SIZE(1,IB), SIZE(2,IB ),IB)
65 CONTINUE
C Цикл итераций
DO 30 IT = 1, NTST
C упреждающая подкачка буферов для внутренних границ
*DVM$ PREFETCH GRINB
C вычисление величин на внутренних границах
DO 40 IB = 1, NBL
LS = 0
DO 40 IS = 1, TINB(1,IB)
J = TINB(LS+2, IB)
CALL CMPINB (block(IB)%PA, block(J)%PA,
* SIZE(1,IB), SIZE(2,IB), SIZE(1,J), SIZE(2,J),
* TINB(LS+3,IB), TINB(LS+4,IB), TINB(LS+5,IB),
* TINB(LS+6,IB), TINB(LS+7,IB), TINB(LS+8,IB) )
LS = LS+7
40 CONTINUE
C вычисление величин внутри областей
C каждая область – отдельная задача
*DVM$ TASK_REGION TSA
*DVM$ PARALLEL ( IB ) ON TSA( IB )
DO 50 IB = 1,NBL
CALL JACOBI(block(IB)%PA, block(IB)%PB, SIZE(1,IB), SIZE(2,IB ))
50 CONTINUE
*DVM$ END TASK_REGION
30 CONTINUE
C конец итераций
C вывод значений массивов
DO 60 IB = 1,NBL
CALL PRTB(block(IB)%PA, SIZE(1,IB), SIZE(2,IB ),IB)
60 CONTINUE
END
SUBROUTINE CMPINB ( AI, AJ, N1, N2, M1, M2, S1, S2,
* ID, INDI, JD, INDJ)
C вычисление величин на внутренних границах
REAL, POINTER, DIMENSION(:,:) :: AI, AJ
INTEGER S1, S2
*DVM$ INHERIT AI, AJ
*DVM$ REMOTE_GROUP GRINB
IF ( ID .EQ. 1 ) THEN
IF ( JD .EQ. 1 ) THEN
*DVM$ PARALLEL ( K ) ON AI( INDI, K ),
*DVM$* REMOTE_ACCESS (GRINB : AJ( INDJ, K ) )
DO 10 K = S1,S2
10 AI(INDI,K) = AJ(INDJ,K)
ELSE
*DVM$ PARALLEL ( K ) ON AI( INDI, K ),
*DVM$* REMOTE_ACCESS (GRINB : AJ( K, INDJ ) )
DO 20 K = S1, S2
20 AI(INDI,K) = AJ(K,INDJ)
ENDIF
ELSE
IF ( JD .EQ. 1 ) THEN
*DVM$ PARALLEL ( K ) ON AI( K, INDI ),
*DVM$* REMOTE_ACCESS (GRINB : AJ( INDJ, K ) )
DO 30 K = S1,S2
30 AI(K, INDI) = AJ(INDJ,K)
ELSE
*DVM$ PARALLEL ( K ) ON AI( K, INDI ),
*DVM$* REMOTE_ACCESS (GRINB : AJ( K, INDJ) )
DO 40 K = S1, S2
40 AI(K,INDI) = AJ(K,INDJ)
ENDIF
ENDIF
END
SUBROUTINE MPROC(LP,HP,SIZE,NBL)
C распределение процессоров по областям
INTEGER LP(NBL),HP(NBL),SIZE(2,NBL)
C распределение для двух областей NBL=2
NUMBER_OF_PROCESSORS( ) = 1
NP = NUMBER_OF_PROCESSORS( )
NPT = NP/NBL
IF(NP.EQ.1) THEN
LP(1) = 1
HP(1) = 1
LP(2) = 1
HP(2) = 1
ELSE
LP(1) = 1
HP(1) = NPT
LP(2) = NPT+1
HP(2) = NP
ENDIF
END
SUBROUTINE INEXB(A,B,N1,N2,S1,S2,ID,INDI)
C инициализация внешних границ
REAL, POINTER, DIMENSION(:,:) :: A,B
INTEGER S1,S2
*DVM$ INHERIT A,B
IF(ID.EQ.1) THEN
*DVM$ PARALLEL (K) ON A(INDI,K)
DO 10 K = S1,S2
A(INDI,K) = 0
B(INDI,K) = 0
10 CONTINUE
ELSE
*DVM$ PARALLEL (K) ON A(K,INDI)
DO 20 K = S1,S2
A(K,INDI) = 0
B(K,INDI) = 0
20 CONTINUE
ENDIF
END
SUBROUTINE INDOM(A,B,M,N,X1,X2)
C инициализация областей
REAL, POINTER, DIMENSION(:,:) :: A, B
INTEGER X1,X2
*DVM$ INHERIT A,B
*DVM$ PARALLEL (I,J) ON A(I,J)
DO 10 I = 2,M-1
DO 10 J = 2,N-1
A(I,J) = I+J+X1+X2-3
B(I,J) = A(I,J)
10 CONTINUE
END
SUBROUTINE JACOBI(A,B,N,M)
REAL, POINTER, DIMENSION(:,:) :: A, B
*DVM$ INHERIT A,B
*DVM$ PARALLEL ( I, J ) ON B( I, J ), SHADOW_RENEW (A)
DO 10 I = 2,N-1
DO 10 J = 2,M-1
10 B(I,J) = (A(I-1,J)+A(I+1,J)+A(I,J-1)+A(I,J+1))/4
*DVM$ PARALLEL ( I, J ) ON A( I, J )
DO 20 I = 2,N-1
DO 20 J = 2,M-1
20 A(I,J) = B(I,J)
END
SUBROUTINE PRTB(B,N,M,IB)
C печать данных для области IB
REAL, POINTER, DIMENSION(:,:) :: B
*DVM$ INHERIT B
PRINT *, 'BLOCK', IB
PRINT *, B
END
SUBROUTINE DISDOM (NBL,TGL,TEXB,TINB,SIZE,M,N,MXBL)
INTEGER TGL(2,MXBL), TEXB(17,MXBL), TINB(29,MXBL), SIZE(2,MXBL)
INTEGER DM(20), DN(20),KDM,KDN,S,GM,GN
C разделение области M´N на две подобласти: M´(N/2) и M´(N-N/2)
DM(1) = M
KDM = 1
DN(1) = N/2
DN(2) = N - N/2
KDN = 2
S = 0
DO 10 I = 1,KDM
10 S = S + DM(I)
IF(S.NE.M) THEN
PRINT *, 'wrong division M'
STOP
ENDIF
DO 15 IB = 1,MXBL
TEXB(1,IB) = 0
TINB(1,IB) = 0
15 CONTINUE
S = 0
DO 20 J = 1,KDN
20 S = S + DN(J)
IF(S.NE.N) THEN
PRINT *, 'wrong division N'
STOP
ENDIF
DM(1) = DM(1) - 1
DN(1) = DN(1) - 1
DM(KDM) = DM(KDM) - 1
DN(KDN) = DN(KDN) - 1
C генерация таблиц (графов) внешних и внутренних границ
IB = 1
GM = 2
GN = 2
DO 30 J = 1,KDN
DO 40 I = 1,KDM
IF (I.EQ.1) THEN
L = TEXB(1,IB)*4
TEXB(L+2,IB) = 1
TEXB(L+3,IB) = DN(J)+2
TEXB(L+4,IB) = 1
TEXB(L+5,IB) = 1
TEXB(1,IB) = TEXB(1,IB)+1
ELSE
L = TINB(1,IB)*7
TINB(L+2,IB) = IB-1
TINB(L+3,IB) = 1
TINB(L+4,IB) = DN(J)+2
TINB(L+5,IB) = 1
TINB(L+6,IB) = 1
TINB(L+7,IB) = 1
TINB(L+8,IB) = DM(I-1)+1
TINB(1,IB) = TINB(1,IB)+1
ENDIF
IF (I.EQ.KDM) THEN
L = TEXB(1,IB)*4
TEXB(L+2,IB) = 1
TEXB(L+3,IB) = DN(J)+2
TEXB(L+4,IB) = 1
TEXB(L+5,IB) = DM(I)+2
TEXB(1,IB) = TEXB(1,IB)+1
ELSE
L = TINB(1,IB)*7
TINB(2,IB) = IB+1
TINB(3,IB) = 1
TINB(4,IB) = DN(J)+2
TINB(5,IB) = 1
TINB(6,IB) = DM(I)+2
TINB(7,IB) = 1
TINB(8,IB) = 2
TINB(1,IB) = TINB(1,IB)+1
ENDIF
IF (J.EQ.1) THEN
L = TEXB(1,IB)*4
TEXB(L+2,IB) = 1
TEXB(L+3,IB) = DM(I)+2
TEXB(L+4,IB) = 2
TEXB(L+5,IB) = 1
TEXB(1,IB) = TEXB(1,IB)+1
ELSE
L = TINB(1,IB)*7
TINB(L+2,IB) = IB-KDM
TINB(L+3,IB) = 1
TINB(L+4,IB) = DM(I)+2
TINB(L+5,IB) = 2
TINB(L+6,IB) = 1
Отсутствие средств работы с динамическими массивами в языке Фортран 77 заставляет пользователей моделировать динамическую память с помощью так называемых рабочих массивов. Динамическая память описывается как одномерный массив большого размера. Динамические массивы разной формы определяются как непрерывные сегменты в этом рабочем массиве.
Пример 1. Использование рабочего массива.
REAL HEAP(100000)
READ (6 , *) N, M
C в программе требуются динамические массивы размера N´ N и M´ M
CALL SUB1(HEAP(1), N, HEAP(1+N*N), M)
END
SUBROUTINE SUB1(A, N, B, M)
DIMENSION A(N , N), B(M , M)
. . .
END
Анализ существующих программ показал отсутствие определенной дисциплины работы с моделируемыми динамическими массивами. В частности, отсутствует явная фиксация размещения массива в памяти. Обращение к динамическому массиву осуществляется ссылкой на рабочий массив. Это делает невозможным для компилятора определить форму массива.
Предлагаемая модель является подмножеством модели динамических массивов Фортран 90 и позволяет без изменений выполнять эту модель в трех средах программирования
последовательная программа на языке Фортран 77,
параллельная программа на языке FDVM,
параллельная программа на языке HPF.
Для динамических массивов, распределяемых по умолчанию, FDVM разрешает использовать любые способы моделирования динамической памяти. Для динамических массивов, распределяемых директивами DISTRIBUTE и ALIGN, FDVM определяет следующую дисциплину размещения и использования динамических массивов.
* Все явно распределяемые динамические массивы размещаются в пуле динамической памяти с именем HEAP
REAL HEAP (MAXM)
где MAXM - количество слов динамической памяти.
* Тип данных и количество измерений динамического массива фиксируется следующей директивой FDVM
|
|
pointer-directive |
is type , POINTER ( dimension-list ) :: pointer-name-list |
dimension |
is : |
pointer-name |
is scalar-int-variable-name |
|
or int-array-name |
type определяет тип данных динамического массива. Переменные, специфицированные директивой POINTER, имеют следующие ограничения.
Переменной с атрибутом POINTER может быть присвоено только значение функции ALLOCATE или значение другой переменной с атрибутом POINTER.
Переменные с атрибутом POINTER в левой и правой части оператора присваивания должны иметь одинаковое количество измерений.
* Размеры каждого измерения и размещение динамического массива в HEAP фиксируется следующим оператором
pointer = ALLOCATE ( sdim ,... )
где
pointer - |
ссылка на целочисленную переменную (скаляр или элемент массива) с атрибутом POINTER |
sdim - |
целочисленный одномерный массив размера ndim. ndim - количество измерений многомерного массива, размещаемого в динамической памяти HEAP. Значение sdim( i ) определяет размер i-ого измерения. Размер выделяемого сегмента равен sdim( 1 )´ sdim( 2 )´....´ sdim( ndim ). |
Целочисленная функция ALLOCATE выдает номер начального элемента выделяемого сегмента динамической памяти HEAP. Функция ALLOCATE программируется пользователем, поэтому она может иметь дополнительные параметры помимо обязательного параметра sdim.
* В процедуре, где производится размещение динамического массива, разрешается только следующий тип ссылки на динамический массив
HEAP( pointer )
При этом такая ссылка может быть только фактическим аргументом вызова функции или подпрограммы.
Пусть в программе используется несколько пулов динамической памяти с идентификаторами ID1 , …, IDn. Нет необходимости переписывать программу с одним пулом динамической памяти HEAP. Достаточно указать следующую спецификацию
CDVM$ HEAP ID1 , …, IDn
Но каждый пул IDi должен удовлетворять вышеуказанным требованиям пула HEAP.
Пул может содержать только массивы, распределяемые директивами DISTRIBUTE и ALIGN.
Для распределения динамических массивов используются директивы DISTRIBUTE и REDISTRIBUTE, синтаксис которых расширен следующим образом:
distribute |
is . . . |
|
or pointer-name |
Если в качестве distributee указан скаляр или массив с атрибутом POINTER , то распределение откладывается до выполнения функции ALLOCATE, которая присваивает значение данному указателю. Вместо функции ALLOCATE выполняется создание массива и его распределение по форматам директивы DISTRIBUTE.
Директива REDISTRIBUTE для динамического массива может выполняться только после выполнения функции ALLOCATE, которая присваивает значение соответствующей переменной POINTER.
Если указатель динамического массива является элементом массива указателей, то распределить динамический массив можно только директивой REDISTRIBUTE. Т.к. директива REDISTRIBUTE допускает лишь ссылку на имя указателя, то элемент массива указателей необходимо предварительно переслать в скалярную переменную-указатель. Распределить массив с указателем PT(I) можно с помощью следующей последовательности операторов:
P1 = PT( I )
CDVM$ REDISTRIBUTE P1( BLOCK, BLOCK )
Программу, приведенную в примере 1, необходимо трансформировать в следующую FDVM программу.
Пример 2. Распределение динамических массивов FDVM.
REAL HEAP(100000)
INTEGER ALLOCATE
CDVM$ REAL, POINTER ( : , : ) :: PA, PB
INTEGER PA, PB
C дескрипторы динамических массивов
INTEGER DESCA(2), DESCB(2)
CDVM$ DISTRIBUTE (BLOCK , BLOCK) :: PA, PB
C в программе требуются массивы размера N´ N и M´ M
READ (6 , *) N, M
C конфигурация первого массива
DESCA(1) = N
DESCA(2) = N
C размещение и распределение первого массива
PA = ALLOCATE (DESCA,1)
C конфигурация второго массива
DESCB(1) = M
DESCB(2) = M
C размещение и распределение второго массива
PB = ALLOCATE ( DESCB, N*N+1 )
CALL SUB1(HEAP(PA), N, HEAP(PB), M)
END
SUBROUTINE SUB1(A, N, B, M)
DIMENSION A(N , N), B(M , M)
CDVM$ DISTRIBUTE *(BLOCK , BLOCK) :: A, B
. . .
END
FUNCTION ALLOCATE(DESC, P)
INTEGER DESC(2), P
ALLOCATE = P
END
Для спецификации выравнивания динамических массивов синтаксис директив ALIGN и REALIGN расширен следующим образом.
alignee |
is . . . |
|
or pointer-name |
align-target |
is . . . |
|
or pointer-name |
Если в директиве ALIGN в качестве выравниваемого массива (alignee) указана переменная с атрибутом POINTER, то выполнение директивы откладывается до выполнения функции ALLOCATE, которая определяет значение этой переменной. Директива REALIGN может выполняться только после выполнения функции ALLOCATE.
Пример 3. Выравнивание динамических массивов.
REAL HEAP(100000)
CDVM$ REAL, POINTER ( :, : ) :: PX, PY
INTEGER PX, PY, DESC(2)
CDVM$ ALIGN PY( I, J ) WITH PX( I, J )
CDVM$ DISTRIBUTE PX ( BLOCK, BLOCK )
. . .
PX = ALLOCATE(DESC, ...)
PY = ALLOCATE(DESC, ...)
. . .
CDVM$ REDISTRIBUTE PX ( BLOCK, * )
Пусть задана цепочка выравниваний директивами ALIGN
P1 f1 P2 f2 . . . fN-1 PN
где fi - функция выравнивания,
Pi - указатель на динамический массив.
Тогда размещение динамических массивов (выполнение функции ALLOCATE) должно происходить в обратном порядке, т.е.
PN = ALLOCATE(...)
. . .
P2 = ALLOCATE(...)
P1 = ALLOCATE(...)
Если указатель динамического массива является элементом массива указателей, то выравнивание динамического массива можно выполнить только директивой REALIGN. Т.к. директива REALIGN допускает лишь ссылку на имя указателя, то элемент массива указателей необходимо предварительно переслать в скалярную переменную-указатель. Выравнивание массива с указателем PT(I) на массив с указателем PT(J) можно выполнить с помощью следующей последовательности операторов:
P1 = PT( I )
P2 = PT( J )
CDVM$ REALIGN P1( I, J ) WITH P2( I+1, J )
Другие примеры распределения динамических массивов см. в следующем разделе.
Рассмотрим фрагмент программы, которая динамически настраивается на количество областей и размеры каждой области.
С NA - максимальное количество областей
PARAMETER ( NA=20 )
CDVM$ PROCESSORS R( NUMBER_OF_PROCESSORS( ) )
С память для динамических массивов
REAL HEAP(100000)
С размеры динамических массивов
INTEGER SIZE( 2, NA )
С массивы указателей для А и В
CDVM$ REAL, POINTER ( :, : ) :: PA, PB, P1, P2
INTEGER P1, P2, PA(NA), PB(NA)
CDVM$ TASK PT ( NA )
CDVM$ ALIGN :: PB, P2
CDVM$ DISTRIBUTE :: PA, P1
. . .
NP = NUMBER_OF_PROCESSORS( )
С распределение массивов по задачам
С динамическое размещение массивов и выполнение отложенных директив
С DISTRIBUTE и ALIGN
IP = 1
DO 20 I = 1, NA
CDVM$ MAP PT( I ) ONTO R( IP : IP+1 )
PA(I) = ALLOCATE ( SIZE(1,I), HEAP )
P1 = PA(I)
CDVM$ REDISTRIBUTE ( *, BLOCK ) ONTO PT( I ) :: P1
PB(I) = ALLOCATE ( SIZE(1,I), HEAP )
P2 = PB(I)
CDVM$ REALIGN P2( I, J ) WITH P1( I, J )
IP = IP + 2
IF( IP .GT. NP ) THEN IP = 1
20 CONTINUE
. . .
С распределение вычислений по задачам
CDVM$ TASK_REGION PT
CDVM$ PARALLEL ( I ) ON PT( I )
DO 50 I = 1,NA
CALL JACOBY( HEAP(PA(I)), HEAP(PB(I)), SIZE(1, I), SIZE(2, I) )
50 CONTINUE
CDVM$ END TASK_REGION
Массивы (области) циклически распределяются на секции из 2-х процессоров. Если NA > NP/2 , то на некоторые секции будет распределено несколько массивов. Витки циклов, распределенные на одну секцию, будут выполняться последовательно в модели параллелизма по данным.
Асинхронное копирование позволяет совместить передачу данных между процессорами с выполнением других операторов.
Асинхронное копирование определяется комбинацией директивы начала копирования (ASYNCHRONOUS ID) и директивой ожидания окончания копирования (ASYNCWAIT ID). Соответствие директив определяется одним идентификатором ID.
Директива ASYNCID описывает отдельный идентификатор для каждой пары директив асинхронного копирования.
Синтаксис директивы:
asyncid-directive |
is ASYNCID async-name-list |
|
|
Директива F90 представляет собой оператор копирования с префиксом.
Синтаксис.
f90-directive |
is F90 copy-statement |
|
|
copy-statement |
is array-section = array-section |
|
|
array-section |
is array-name [( section-subscript-list )] |
|
|
section-subscript |
is subscript |
|
or subscript-triplet |
|
|
subscript-triplet |
is [ subscript ] : [ subscript ] [ : stride] |
|
|
subscript |
is int-expr |
|
|
stride |
is int-expr |
Директивы ASYNCHRONOUS и END ASYNCHRONOUS задают блочную конструкцию.
Синтаксис.
asynchronous-construct |
is asynchronous-directive |
|
f90-directive [ f90-directive ] … copy-loop [ copy-loop ] … |
|
end-asynchronous-directive |
|
|
asynchronous-directive |
is ASYNCHRONOUS async-name |
|
|
end-asynchronous-directive |
is END ASYNCHRONOUS |
Все операторы присваивания в циклах копирования (copy-loop) должны быть описаны директивами F90 с соответствующим оператором копирования.
Синтаксис.
asyncwait-directive |
is ASYNCWAIT async-name |
Пример из раздела 6.3.4.1 можно специфицировать как асинхронное копирование на языке FDVM 2.0 следующим образом.
CDVM$ ASYNCID TR
REAL A(N1,N2,N3), B(N1,N3)
. . .
CDVM$ ASYNCHRONOUS TR
CDVM$ F90 A( :, 5, 3:N3 ) = B( :, 1:N3-2 )
DO 10 I1 = 1, N1
DO 10 I2 = 2, N3-1
10 A(I1, 5, I2+1) = B(I1, I2-1)
CDVM$ END ASYNCHRONOUS
. . .
последовательность операторов,
которая выполняется на фоне передачи данных
. . .
CDVM$ ASYNCWAIT TR
Fortran-DVM - оглавление | Часть 1(1-4) | Часть 2 (5-6) | Часть 3 (7-15) | Часть
4 (Приложения) |