Fortran-DVM - оглавление Часть 1 (1-4) Часть 2
(5-6)
Часть 3 (7-12) Часть 4 (Приложения)
создан: апрель, 2001 - последнее обновление 06.10.02 -

5. Распределение вычислений

5.1. Параллельные циклы

5.1.1. Определение параллельного цикла

Моделью выполнения FDVM программы, как и программ на других языках с параллелизмом по данным, является модель ОПМД (одна программа - множество потоков данных). На все процессоры загружается одна и та же программа, но каждый процессор в соответствии с правилом собственных вычислений выполняет только те операторы присваивания, которые изменяют значения переменных, размещенных на данном процессоре (собственных переменных).

Таким образом, вычисления распределяются в соответствии с размещением данных (параллелизм по данным). В случае размноженной переменной оператор присваивания выполняется на всех процессорах, а в случае распределенного массива - только на процессоре (или процессорах), где размещен соответствующий элемент массива.

Определение " своих" и пропуск " чужих" операторов может вызвать значительные накладные расходы при выполнении программы. Поэтому спецификация распределения вычислений разрешается только для циклов, которые удовлетворяют следующим условиям:

Цикл, удовлетворяющий этим условиям, будем называть параллельным циклом. Управляющая переменная последовательного цикла, охватывающего параллельный цикл или вложенного в него, может индексировать только локальные (размноженные) измерения распределенных массивов.

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 ]
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      do-variable [ add-op primary-expr ]
         [ primary-expr * ]

Директива PARALLEL размещается перед заголовком цикла и распределяет витки циклов в соответствии с распределением массива или шаблона. Семантика директивы аналогична семантике директивы ALIGN, где индексное пространство выравниваемого массива заменяется индексным пространством цикла. Индексы циклов в списке do-variable-list перечисляются в том порядке, в котором размещены соответствующие операторы DO в тесно-гнездовом цикле.

Синтаксис и семантика отдельных частей директивы описаны в следующих разделах:

new-clause                       раздел 5.1.3
reduction-clause              
раздел 5.1.4
shadow-renew-clause      
раздел 6.2.2
shadow-compute-clause  
раздел 6.2.3
across-clause                   
раздел 6.2.4
remote-access-clause      
раздел 6.3.1

Пример 5.1. Распределение витков цикла с регулярными вычислениями.

                 REAL A(N, M), B(N, M+1), C(N, M), D(N, M)
CDVM$  ALIGN ( I, J ) WITH B( I, J+1 ) :: A, C, D
CDVM$  DISTRIBUTE B ( BLOCK , BLOCK )
                 
    
. . .
CDVM$  PARALLEL ( I, J ) ON B( I, J+1 )

                 DO 10 I = 1, N
                 DO 10 J = 1, M-1
                 A(I,J) = D(I,J) + C(I,J)
                 B(I,J+1) = D(I,J) - C(I,J)
10            CONTINUE

Цикл удовлетворяет всем условиям параллельного цикла. В частности, левые части операторов присваивания одного витка цикла A(I,J) и B(I,J+1) размещаются на одном процессоре через выравнивание массивов А и В.

Если левые части операторов присваивания размещены на разных процессорах (распределенный виток цикла), то цикл необходимо разделить на несколько циклов.

Пример 5.2. Разделение цикла

  CDVM$   PARALLEL ( I ) ON A( 2*I )
            DO 10 I = 1, N                   DO 10 I = 1, N
            DO 10 J = 1, M-1 10             A(2*I) = . . .
            A(2*I) = . . . CDVM$   PARALLEL ( I) ON B( 3*I )
            B(3*I) = . . .                   DO 11 I = 1, N
10       CONTINUE 11             B(3*I) = . . .

Цикл разделен на 2 цикла, каждый из которых удовлетворяет условию параллельного цикла.

5.1.3. Приватные переменные. Спецификация NEW

Если использование переменной локализовано в пределах одного витка цикла, то ее необходимо указать в спецификации NEW:

new-clause is      NEW ( new-variable-list )
new-variable is      array-name
  or     scalar-variable-name

NEW-переменные (приватные переменные) не могут быть распределенными массивами. Значение приватной переменной не определено в начале витка цикла и не используется после витка цикла, поэтому в каждом витке цикла может использоваться свой экземпляр приватной переменной.

Пример 5.3. Спецификация приватной переменной.

CDVM$  PARALLEL ( I, J ) ON A( I, J ) , NEW ( X )
                 DO 10 I = 1, N
                 DO 10 J = 1, N
                 X = B(I,J) + C(I,J)
                A(I,J) = X
10           CONTINUE

5.1.4. Редукционные операции и переменные. Спецификация REDUCTION

Очень часто в программе встречаются циклы, в которых выполняются редукционные операции - в некоторой переменной суммируются элементы массива или вычисляется максимальное (минимальное) значение. Витки таких циклов можно распределять, если указать спецификацию 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

Редукционными переменными не могут быть распределенные массивы. Редукционные переменные вычисляются и используются только в операторах определенного вида - редукционных операторах.

Введем следующие обозначения

rv - редукционная переменная
L - одномерный массив целого типа
n - число координат минимума или максимума
er - выражение, не содержащее rv
Ik - целая переменная
op - одна из следующих операций языка Фортран: +, -, .OR., .AND., .EQV., .NEQV.
ol - одна из следующих операций языка Фортран: .GE., .GT., .LE., .LT.
f - функция max или min

В теле цикла редукционный оператор имеет один из следующих видов:

1)  rv = rv  op  er
     rv = er  op  rv

2)  rv = f( rv, er )
     rv = f( er, rv )
3)  if( rv  ol  er )   rv = er
   if( er  ol  rv )   rv = er

4)  if( rv  ol  er )  then 
       rv = er
       L( 1 ) = e1
         .  .  
       L( n ) = en
     endif

     if( er  ol  rv )  then 
       rv = er
       L( 1 ) = e1
        .  .  .
       L( n ) = en
     endif

Соответствие вида оператора, операции языка Фортран и имени редукции FDVM приведено в следующей таблице.

Вид оператора операция Фортран имя редукции FDVM
     
1 + SUM(rv)
1 * PRODUCT(rv)
1 .AND. AND(rv)
1 .OR. OR(rv)
1 .EQV. EQV(rv)
1 .NEQV. NEQV(rv)
2,3   MAX(rv)
    MIN(rv)
4   MINLOC(rv, L, n)
    MAXLOC(rv, L, n)

Операция MAXLOC (MINLOC) предполагает вычисление максимального (минимального) значения и определение его координат.

Пример 5.4. Спецификация редукции.

                  S = 0
                  Y =1.E10
                  X = -1.
                  IMIN(1) = 0
CDVM$  PARALLEL ( I ) ON A( I ) ,
CDVM$  REDUCTION(SUM(S), MAX(X), MINLOC(Y,IMIN,1))
                 DO 10 I = 1, N
                       S = S + A(I)
                       X = MAX(X, A(I))
                       IF(A(I)
.LT. Y) THEN
                                   Y = A(I)
                                   IMIN(1) = I
                       ENDIF
10            CONTINUE

5.2. Вычисления вне параллельного цикла

Вычисления вне параллельного цикла выполняются по правилу собственных вычислений. Пусть оператор

IF p THEN lh = rh

где p – логическое выражение,
lh – левая часть оператора присваивания (ссылка на скаляр или элемент массива),
rh – правая часть оператора присваивания (выражение),

находится вне параллельного цикла.

Тогда этот оператор будет выполняться на процессоре, где распределены данные со ссылкой lh (процессор own( lh )). Все данные в выражениях p и rh должны быть размещены на процессоре own( lh ). Если какие-либо данные из выражений p и rh отсутствуют на процессоре own( lh ), то их необходимо указать в директиве удаленного доступа (см. 6.1.2) перед этим оператором.

Если lh является ссылкой на распределенный массив А и существует зависимость по данным между rh и lh, то распределенный массив необходимо размножить с помощью директивы

REDISTRIBUTE А( *,...,* ) или REALIGN А( *,...,* )

перед выполнением оператора.

Пример 5.5. Оператор собственных вычислений.

                 PARAMETER (N = 100)
                 REAL A(N, N+1), X(N)
CDVM$  ALIGN X( I ) WITH A( I, N+1)
CDVM$  DISTRIBUTE ( BLOCK, * ) :: A
                
    
. . .
C              обратная подстановка алгоритма Гаусса
C              собственные вычисления вне циклов
С
С              оператор собственных вычислений
С              левая и правая части – на одном процессоре
                 X(N) = A(N,N+1) / A(N,N)
                 DO 10 J = N-1, 1, -1
CDVM$  PARALLEL ( I ) ON A ( I, *)
                 DO 20 I = 1, J
                       A(I,N+1) = A(I,N+1) - A(I,J+1) * X(J+1)
20            CONTINUE
C              собственные вычисления в последовательном цикле,
С              охватывающем параллельный цикл
                 X(J) = A(J,N+1) / A(J,J)
10            CONTINUE

Отметим, что A(J,N+1) и A(J,J) локализованы на том процессоре, где размещается X(J).

6. Cпецификация удаленных данных

6.1. Определение удаленных ссылок

Удаленными данными будем называть данные, размещенные на одном процессоре и используемые на другом процессоре. Фактически эти данные являются общими (разделяемыми) данными для этих процессоров. Ссылки на такие данные будем называть удаленными ссылками. Рассмотрим обобщенный оператор

IF (…A(inda)…) B(indb) = …C(indc)

где A, B, C - распределенные массивы,
inda, indb, indc -
индексные выражения.

В модели DVM этот оператор будет выполняться на процессоре own(B(indb)), т.е. на том процессоре, где размещен элемент B(indb). Ссылка A(inda) и C(indc) не являются удаленными ссылками, если соответствующие им элементы массивов A и C размещены на процессоре own(B(indb)). Единственной гарантией этого является выравнивание A(inda), B(indb) и C(indc) в одну точку шаблона выравнивания. Если выравнивание невозможно или невыполнено, то ссылки A(inda) и/или C(indc) необходимо специфицировать как удаленные ссылки. В случае многомерных массивов данное правило применяется к каждому распределенному измерению.

По степени эффективности обработки удаленные ссылки разделены на два типа: SHADOW и REMOTE.

Если массивы B и C выровнены и

inda = indc ± d ( dположительная целочисленная константа),

то удаленная ссылка C(indc) принадлежит типу SHADOW. Удаленная ссылка на многомерный массив принадлежит типу SHADOW, если распределяемые измерения удовлетворяют определению типа SHADOW.

Удаленные ссылки, не принадлежащие типу SHADOW, составляют множество ссылок типа REMOTE.

Особым множеством удаленных ссылок являются ссылки на редукционные переменные (см. 5.2.4), которые принадлежат типу REDUCTION. Эти ссылки могут использоваться только в параллельном цикле.

Для всех типов удаленных ссылок возможны два вида спецификаций: синхронная и асинхронная.

Синхронная спецификация задает групповую обработку всех удаленных ссылок для данного оператора или цикла. На время этой обработки, требующей межпроцессорных обменов, выполнение данного оператора или цикла приостанавливается. Асинхронная спецификация позволяет совместить вычисления с межпроцессорными обменами. Она объединяет удаленные ссылки нескольких операторов и циклов. Для запуска операции обработки ссылок и ожидания ее завершения служат специальные директивы. Между этими директивами могут выполняться другие вычисления, в которых отсутствуют ссылки на специфицированные переменные.

6.2. Удаленные ссылки типа SHADOW

6.2.1. Спецификация массива с теневыми гранями

Удаленная ссылка типа SHADOW означает, что обработка удаленных данных будет происходить через “теневые” грани. Теневая грань представляет собой буфер, который является непрерывным продолжением локальной секции массива в памяти процессора (см. рис.6.1.).Рассмотрим оператор

A( i ) = B( i + d2) + B( i – d1)

где d1, d2целые положительные константы. Если обе ссылки на массив B являются удаленными ссылками типа SHADOW, то массив B необходимо специфицировать в директиве SHADOW как B( d1 : d2 ), где d1 – ширина левой грани, а d2 – ширина правой грани. Для многомерных массивов необходимо специфицировать грани по каждому измерению. При спецификации теневых граней указывается максимальная ширина по всем удаленным ссылкам типа SHADOW.

Синтаксис директивы SHADOW.

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 для одного цикла

Синхронная спецификация является частью директивы PARALLEL:

shadow-renew-clause is      SHADOW_RENEW ( renewee-list )
   
renewee is      dist-array-name [ ( shadow-edge-list ) ]
         [ (CORNER) ]

Ограничения:

Выполнение синхронной спецификации заключается в обновлении теневых граней значениями удаленных переменных перед выполнением цикла.

Пример 6.1. Спецификация SHADOW-ссылок без угловых элементов.

                  REAL A(100), B(100)
CDVM$   ALIGN B( I ) WITH A( I )
CDVM$   DISTRIBUTE ( BLOCK) :: A
CDVM$   SHADOW B( 1:2 )
                  
    
. . .
CDVM$  PARALLEL ( I ) ON A ( I ), SHADOW_RENEW ( B )
                 DO 10 I = 2, 98
                        A(I) = (B(I-1) + B(I+1) + B(I+2) ) / 3
10            CONTINUE

При обновлении значений в теневых гранях используются максимальные размеры 1:2 , заданные в директиве SHADOW.

Распределение и схема обновления теневых граней показана на рис.6.1.

Рис.6.1. Распределение массива с теневыми гранями.

На каждом процессоре распределяются два буфера, которые являются непрерывным продолжением локальной секции массива. Левая теневая грань имеет размер в 1 элемент (для B(I-1)), правая теневая грань имеет размер в 2 элемента (для B(I+1) и B(I+2)). Если перед выполнением цикла произвести обмен между процессорами по схеме на рис.6.1., то цикл может выполняться на каждом процессоре без замены ссылок на массивы ссылками на буфер.

Для многомерных распределенных массивов теневые грани могут распределяться по каждому измерению. Особая ситуация возникает, когда необходимо обновлять " угол" теневых граней. В этом случае требуется указать дополнительный параметр CORNER.

Пример 6.2. Спецификация SHADOW-ссылок с угловыми элементам.

                  REAL A(100,100), B(100,100)
CDVM$  ALIGN B( I, J ) WITH A( I, J )
CDVM$  DISTRIBUTE A ( BLOCK,BLOCK)
                
    
. . . 
CDVM$  PARALLEL ( I, J ) ON A ( I, J ), SHADOW_RENEW ( B (CORNER))
                 DO 10 I = 2, 99
                 DO 10 J = 2, 99
                 A(I,J) = (B(I,J+1) + B(I+1,J) + B(I+1,J+1) ) / 3
10            CONTINUE

Теневые грани для массива В распределяются по умолчанию размером в 1 элемент по каждому измерению. Т.к. имеется удаленная " угловая" ссылка B(I+1,J+1) , то указывается параметр CORNER.

Рис. 6.2. Схема локальной секции массива с теневыми гранями.

6.2.3. Вычисление значений в теневых гранях. Спецификация SHADOW_COMPUTE

В разделах 6.2.1 и 6.2.2. были описаны способы обновления значений в теневых гранях путем обмена данными между процессорами. При этом новые значения массива вычислялись в одном цикле, а обновление производилось либо перед выполнением, либо во время выполнения другого цикла.

При некоторых условиях значения в теневых гранях можно обновлять без обмена данными между процессорами. Новые значения в теневых гранях можно вычислять в том же цикле, в котором вычисляются новые значения массивов. Такой способ обновления значений в теневых гранях описывается спецификацией SHADOW_COMPUTE, которая является частью директивы PARALLEL.

shadow-compute-clause is      SHADOW_COMPUTE

Рассмотрим некоторый параллельный цикл

CDVM$ PARALLEL (I1 , I2, …, In) ON A(f1,f2 ,…,fk)

где A – идентификатор массива, в соответствии с которым распределяются витки цикла.

Пусть
{LH} - множество ссылок на распределенные массивы в левых частях операторов присваивания цикла;
{RH} - множество ссылок на распределенные массивы в правых частях (выражениях) операторов присваивания цикла.

Для применения спецификации SHADOW_COMPUTE необходимо выполнение следующих условий:

  1. ширина теневых граней распределенных измерений массивов из множеств {LH} и {RH} должна быть не меньше ширины теневых граней соответствующих измерений массива A;
  2. теневые грани массивов из множества {RH} должны содержать значения, соответствующие значениям массивов.

Во время выполнения цикла значения в теневых гранях массивов из множества {LH} обновляются. Ширина обновленной части каждой теневой грани равна ширине соответствующей теневой грани массива A.

Пример 6.3. Спецификация SHADOW_COMPUTE.

CDVM$   DISTRIBUTE (BLOCK) :: A, B, C, D
CDVM$
  SHADOW A(1:2)
CDVM$
  SHADOW B(2:2)
CDVM$
  PARALLEL ( I ) ON C( I ), SHADOW_COMPUTE,
CDVM$
* SHADOW_RENEW( A, B )
                  DO 10 I = 1, N
                       C( I ) = A( I ) + B( I )
                       D( I ) = A( I ) - B( I )
10             CONTINUE

Так как по умолчанию ширина теневых граней для массивов C и D равна 1, то условие 1) удовлетворяется. Выполнение спецификации SHADOW_RENEW удовлетворяет условие 2).

6.2.4. Спецификация ACROSS зависимых ссылок типа SHADOW для одного цикла

Рассмотрим следующий цикл

         DO 10 I = 2, N-1
           DO 10 J = 2, N-1
                A(I,J) = (A(I,J-1) + A(I,J+1) + A(I-1,J) + A(I+1,J)) / 4
10      CONTINUE

Между витками цикла с индексами i1 и i2 ( i1<i2 ) существует зависимость по данным (информационная связь) массива A, если оба эти витка осуществляют обращение к одному элементу массива по схеме запись-чтение или чтение-запись.

Если виток i1 записывает значение, а виток i2 читает это значение, то между этими витками существует потоковая зависимость или просто зависимость i1®  i2.

Если виток i1 читает “старое” значение, а виток i2 записывает “новое” значение, то между этими витками существует обратная зависимость i1¬  i2.

В обоих случаях виток i2 может выполняться только после витка i1.

Значение i2 - i1 называется диапазоном или длиной зависимости. Если для любого витка i существует зависимый виток i + d (d - константа), тогда зависимость называется регулярной или зависимостью с постоянной длиной.

Цикл с регулярными вычислениями, в котором существуют регулярные зависимости по распределенным массивам, можно распределять с помощью директивы PARALLEL, указывая спецификацию ACROSS.

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 )

В спецификации ACROSS перечисляются все распределенные массивы, по которым существует регулярная зависимость по данным. Для каждого измерения массива указывается длина прямой зависимости (flow-dep-length) и длина обратной зависимости (anti-dep-length). Нулевое значение длины зависимости означает отсутствие зависимости по данным.

Ограничение:

Если в цикле обновляются не все значения массива, а только значения некоторых секций массива, то эти секции следует указать в разделе SECTION.

Пример 6.4. Спецификация цикла с регулярной зависимостью по данным.

CDVM$  PARALLEL ( I, J ) ON A( I, J ) , ACROSS ( A( 1:1, 1:1 ))
                 DO 10 I = 2, N-1
                 DO 10 J = 2, N-1
                      A(I,J) = (A(I,J-1) + A(I,J+1) + A(I-1,J) + A(I+1,J)) / 4
10            CONTINUE

По каждому измерению массива А существует прямая и обратная зависимость длиной 1.

Спецификация ACROSS реализуется через теневые грани. Длина обратной зависимости определяет ширину обновления правой грани, а длина прямой зависимости – ширину обновления левой грани. Обновление значений правых граней производится перед выполнением цикла (как для директивы SHADOW_RENEW). Обновление левых граней производится во время выполнения цикла по мере вычисления значений удаленных данных. Фактически, ACROSS-ссылки являются подмножеством SHADOW–ссылок, между которыми существует зависимость по данным.

Эффективность параллельного выполнения цикла ACROSS

Измерение массива, по которому существует зависимость по данным, будем называть рекуррентным измерением.

Степень эффективности параллельного выполнения цикла ACROSS зависит от количества распределенных рекуррентных измерений.

Одномерный массив. Для одномерного распределенного массива с рекуррентным измерением возможно только последовательное выполнение (см. рис. 6.3).

Многомерный массив. Для многомерного массива выделим следующие сочетания рекуррентных распределенных измерений по степени убывания эффективности.

1) существует хотя бы одно не рекуррентное измерение. Массив и цикл распределяются только по этому измерению. Цикл выполняется как обычный параллельный цикл без спецификации ACROSS.

Пример 6.5. Распараллеливание по не рекуррентному измерению.

CDVM$  DISTRIBUTE A( BLOCK, * )
CDVM$  PARALLEL ( I ) ON A( I, * )
                 DO 30 I = 1,N1
                 DO 30 J = 2,N2-1
30                  A(I,J) = A(I,J-1) + A(I,J+1)

Отметим, что этот способ может быть не самым эффективным, если N1 значительно меньше N2 и количества процессоров (недостаточный параллелизм)

2) Распределено только одно рекуррентное измерение. Остальные измерения локализованы на каждом процессоре. Система поддержки организует конвейерное распараллеливание (см. рис.6.4). При этом размер ступени конвейера автоматически определяется на каждой ЭВМ, в зависимости от времени выполнения цикла и времени передачи данных при обновлении теневых граней.

Пример 6.6. Конвейерное распараллеливание.

CDVM$  DISTRIBUTE A( BLOCK, * )
CDVM$  PARALLEL ( I, J ) ON A( I, J ) ,ACROSS ( A( 1:1, 1:1 ))
                 DO 40 I = 2,N1-1
                 DO 40 J = 2,N2-1
40                  A(I,J) = A(I,J-1) + A(I,J+1) + A(I-1,J) + A(I+1,J)

Ограничение конвейерного параллелизма. Для организации конвейерного распараллеливания необходимо выполнение дополнительных условий:

3) Существует m>1 распределенных рекуррентных измерений. Массив виртуальных процессоров содержит также m измерений. Система поддержки автоматически организует параллельное выполнение по гиперплоскостям массива процессоров. Каждая гиперплоскость имеет m-1 измерение.

Пример 6.7. Распараллеливание по гиперплоскостям.

CDVM$  DISTRIBUTE A( BLOCK, BLOCK )
CDVM$  PARALLEL ( I, J ) ON A( I, J ) ,
ACROSS ( A( 1:1, 1:1 ))
                 DO 50 I = 2,N1-1
                 DO 50 J = 2,N2-1
50            A(I,J) = A(I,J-1) + A(I,J+1) + A(I-1,J) + A(I+1,J)

На рис.6.5. изображен двумерный массив виртуальных процессоров. Параллельно будут выполняться вычисления на процессорах, принадлежащих одной гиперплоскости (диагональной линии).

Рис.6.3. Последовательное выполнение

Рис.6.4. Конвейерное выполнение

Рис.6.5. Распараллеливание по гиперплоскостям решетки виртуальных процессоров.

6.2.5. Асинхронная cпецификация независимых ссылок типа SHADOW

Обновление значений в теневых гранях, описанное в разделе 6.2.2, является неделимой (синхронной) операцией обмена для неименованной группы распределенных массивов. Эту операцию можно разделить на две операции:

На фоне ожидания значений теневых граней можно выполнять вычисления, в частности, вычисления на внутренней области локальной секции массива.

Асинхронное обновление теневых граней для именованной группы распределенных массивов описывается следующими директивами.

Определение группы.

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_GROUP директивы SHADOW_START и SHADOW_WAIT могут выполняться многократно. Новые значения в теневых гранях могут использоваться только после выполнения директивы SHADOW_WAIT.

Особым вариантом является использование директив SHADOW_START и SHADOW_WAIT в спецификации shadow-renew-clause параллельного цикла.

Синтаксис спецификации shadow-renew-clause расширен следующим образом:

shadow-renew-clause is      . . .
  or     shadow-start-directive
  or     shadow-wait-directive

Если в спецификации указана директива SHADOW_START, то на каждом процессоре производится опережающее вычисление значений, пересылаемых в теневые грани других процессоров. После этого производится обновление теневых граней и вычисление на внутренней области локальной секции массива (см. рис.6.2).

Если в спецификации указана директива SHADOW_WAIT, то производится опережающее вычисление значений во внутренней области локальной секции массива. После завершения ожидания новых значений своих теневых граней выполняются вычисления, использующие эти значения.

Пример 6.8. Совмещение счета и обновления теневых граней.

                 REAL A(100,100), B(100,100), C(100,100), D(100,100)
CDVM$  ALIGN ( I, J ) WITH C( I, J ) :: A, B, D
CDVM$  DISTRIBUTE ( BLOCK, BLOCK ) :: C
                
    
. . .
CDVM$  SHADOW_GROUP AB ( A, B )
                 
    
. . .
CDVM$  SHADOW_START AB
                
    
. . .
CDVM$  PARALLEL ( I, J ) ON C ( I, J ), SHADOW_WAIT AB
                 DO 10 I = 2, 99
                 DO 10 J = 2, 99
                      C(I,J) = (A(I-1,J) + A(I+1,J) + A(I,J-1) + A(I,J+1) ) / 4
                      D(I,J) = (B(I-1,J) + B(I+1,J) + B(I,J-1) + B(I,J+1) ) / 4
10            CONTINUE

Распределенные массивы по умолчанию имеют теневые грани в 1 элемент по каждому измерению. Т.к. в спецификации параллельного цикла указана директива SHADOW_WAIT, то изменяется порядок выполнения витков цикла. Сначала будут выполняться вычисления на внутренней области каждой локальной секции массива, затем выполнится директива ожидания новых значений теневых граней. Выполнение цикла завершается вычислением значений пересылаемых в теневые грани.

6.3. Удаленные ссылки типа REMOTE

6.3.1. Директива REMOTE_ACCESS

Удаленные ссылки типа REMOTE специфицируются директивой 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

Директива REMOTE_ACCESS может быть отдельной директивой (область действия - следующий оператор) или дополнительной спецификацией в директиве PARALLEL (область действия – тело параллельного цикла).

Если удаленная ссылка задается как имя массива без списка индексов, то все ссылки на этот массив в параллельном цикле (операторе) являются удаленными ссылками типа REMOTE.

Рассмотрим удаленную ссылку на многомерный распределенный массив

A( ind1, ind2,…,indk )

Пусть indjиндексное выражение по j-ому измерению.

В директиве REMOTE_ACCESS индексное выражение указывается без изменений, если

Во всех остальных случаях в директиве REMOTE_ACCESS вместо indj указывается “:” (все измерение).

6.3.2. Синхронная спецификация удаленных ссылок типа REMOTE

Если в директиве REMOTE_ACCESS не указано имя группы (remote-group-name), то выполнение такой директивы происходит в синхронном режиме. В пределах нижестоящего оператора или параллельного цикла компилятор заменяет все вхождения удаленной ссылки ссылкой на буфер. Пересылка удаленных данных производится перед выполнением оператора или цикла.

Пример 6.9. Синхронная спецификация удаленных ссылок типа REMOTE.

                 DIMENSION A(100,100), B(100,100)
CDVM$  DISTRIBUTE (*,BLOCK) :: A
CDVM$  ALIGN B( I, J ) WITH A( I, J )
                 
    
. . .
CDVM$  REMOTE_ACCESS ( A(50,50) )
С               замена ссылки A(50,50) ссылкой на буфер
С               рассылка значения A(50,50) по всем процессорам
1               X = A(50,50)
                    
. . .
CDVM$  REMOTE_ACCESS ( B(100,100) )
С               пересылка значения В(100,100) в буфер процессора own(A(1,1)
2               A(1,1) = B(100,100)
                     
. . .
CDVM$  PARALLEL (I,J) ON A(I,J) , REMOTE_ACCESS ( B(:,N) )
С               рассылка значений B(:,N) по процессорам own(A(:,J))
3               DO 10 I = 1, 100DO 10 J = 1, 100
10             A(I,J) = B(I,J) + B(I,N)

Первые две директивы REMOTE_ACCESS специфицируют ервые две директивы удаленные ссылки для отдельных операторов. цикле специфицирует REMOTE_ACCESS в параллельном удаленные данные которые распределен матрицы) для всех процессоров, на (столбец массив А.

6.3.3. Асинхронная спецификация удаленных ссылок типа REMOTE

Если в директиве REMOTE_ACCESS указано имя группы (remote-group-name), то выполнение директивы происходит в асинхронном режиме. Для спецификации этого режима необходимы следующие дополнительные директивы.

Описание имени группы.

remote-group-directive is      REMOTE_GROUP remote-group-name-list

Идентификатор, определенный этой директивой, может использоваться только в директивах REMOTE_ACCESS , PREFETCH и RESET. Группа remote-group представляет собой глобальный объект, областью действия которого является вся программа.

prefetch-directive is      PREFETCH remote-group-name
   
reset-directive is      RESET remote-group-name

Рассмотрим следующую типовую последовательность асинхронной спецификации удаленных ссылок типа REMOTE.

CDVM$  REMOTE_GROUP RS
10                 
. . .
CDVM$  PREFETCH RS
                 
    
. . .
C              вычисления, в которых не участвуют удаленные ссылки r1 , …,rn
                   
. . .
CDVM$  PARALLEL . . . , REMOTE_ACCESS (RS : r
1)
                  
    
. . .
CDVM$  REMOTE_ACCESS (RS : r
i)
                 
    
. . .
CDVM$  PARALLEL . . . , REMOTE_ACCESS (RS : r
n)
                
    
. . .
                 IF( P ) GO TO 10

При первом прохождении указанной последовательности операторов директива PREFETCH не выполняется. Директивы REMOTE_ACCESS выполняется в обычном синхронном режиме. При этом происходит накопление ссылок в переменной RS. После выполнения всей последовательности директив REMOTE_ACCESS значение переменной RS равно объединению подгрупп удаленных ссылок ri E ...E rn.

При втором и последующих прохождениях директива PREFETCH осуществляет упреждающую пересылку удаленных данных для всех ссылок, составляющих значение переменной RS. После директивы PREFETCH и до первой директивы REMOTE_ACCESS с тем же именем группы можно выполнять другие вычисления, которые перекрывают ожидание обработки удаленных ссылок. При этом директивы REMOTE_ACCESS никакой пересылки данных уже не вызывают.

Ограничения.

Если характеристики группы удаленных ссылок изменились, то необходимо присвоить неопределенное значение группе удаленных ссылок с помощью директивы RESET, после чего будет происходить новое накопление группы удаленных ссылок.

Рассмотрим следующий фрагмент многообластной задачи. Область моделирования разделена на 3 подобласти, как показано на рис.6.6.

Рис.6.6. Разделение области моделирования.

Пример 6.10. Использование группы регулярных удаленных ссылок.

                 REAL A1(M,N1+1), A2(M1+1,N2+1), A3(M2+1,N2+1)
CDVM$  DISTRIBUTE ( BLOCK,BLOCK) :: A1, A2, A3
CDVM$  REMOTE_GROUP RS
                 DO 1 ITER = 1, MIT
                     
. . .
C              
обмен границами по линии раздела D
CDVM$  PREFETCH RS
                 
    
. . .
CDVM$  PARALLEL ( I ) ON A1 ( I, N1+1 ), REMOTE_ACCESS ( RS: A2(I,2))
                 DO 10 I = 1, M1
10                  A1(I,N1+1) = A2(I,2)
CDVM$  PARALLEL ( I ) ON A1 ( I, N1+1 ), REMOTE_ACCESS ( RS: A3(I-M1,2))
                 DO 20 I = M1+1, M
20                  A1(I,N1+1) = A3(I-M1,2)
CDVM$  PARALLEL ( I ) ON A2 ( I, 1 ), REMOTE_ACCESS ( RS: A1(I,N1))
                 DO 30 I = 1, M1
30                  A2(I,1) = A1(I,N1)
CDVM$  PARALLEL ( I ) ON A3 ( I, 1 ), REMOTE_ACCESS ( RS: A1(I+M1,N1))
                 DO 40 I = 1, M2
40                  A3(I,1) = A1(I+M1,N1)
                    
. . .
                 IF (NOBLN) THEN
C             
перераспределение массивов с целью балансировки загрузки
                    . . .
CDVM$  RESET RS
                 END IF
                     
. . .
1              CONTINUE

6.3.4. Асинхронное копирование по ссылкам типа REMOTE

Если в параллельном цикле содержатся только операторы присваивания без вычислений, то доступ по ссылкам типа REMOTE можно выполнять более эффективно с помощью асинхронного копирования распределенных массивов.

6.3.4.1. Цикл и операторы копирования

Рассмотрим следующий цикл

DO 10 I1 = L1,H1,S1
      
.  .  .
DO 10 In = Ln,Hn,Sn
10 A(f1,…,fk) = B (g1,…,gm)

где    A, B - идентификаторы разных распределенных массивов.

Li,Hi,Si – инварианты цикла
fi = ai *Ii + bi
gj = cj *Ij + dj
ai, bi , cj, dj
– целые выражения, инварианты цикла (выражения, значения которых не изменяются в процессе выполнения цикла).

Каждая переменная цикла Il может быть использована не более чем в одном выражении fi и не более чем в одном выражении gj.

Цикл может содержать несколько операторов, удовлетворяющих вышеуказанным ограничениям. Такой цикл будем называть циклом копирования (copy-loop).

Цикл копирования может быть описан одним или несколькими операторами копирования (copy-statement) следующего вида

A(a 1,…,a k) = B(b 1,…,b m)

где
a i = li : hi : si
b j = lj : hj : sj
a i, b j - являются триплетами языка Фортран 90.

Оператор копирования является аналогом оператора присваивания секций массивов Фортран 90.

Для триплетов существуют правила сокращенной записи. Определим эти правила на примере триплета a i.

  1. Если в копировании участвует все измерение массива, то
    a
    i =  :
  2. Если si = 1, то
    a
    i = li : hi
  3. Если Li = hi , то
  4. a i = li

Для цикла копирования 10 выражения триплетов определяются следующим образом

       Для a i        Для b j
li = ai * Li + bi
hi = ai * Hi + bi
si = ai * Si
lj = cj * Lj + dj
hj = cj * Hj + dj
sj = cj * Sj

Рассмотрим следующий цикл копирования

            REAL A(N1,N2,N3), B(N1,N3)
            DO 10 I1 = 1, N1
            DO 10 I2 = 2, N3-1
10       A(I1, 5, I2+1) = B(I1, I2-1)

Этому циклу соответствует следующий оператор копирования

A( :, 5, 3:N3 ) = B( :, 1:N3-2 )

6.3.4.2. Директивы асинхронного копирования

Асинхронное копирование позволяет совместить передачу данных между процессорами с выполнением других операторов.

Асинхронное копирование определяется комбинацией директивы начала копирования (ASYNCHRONOUS  ID) и директивой ожидания окончания копирования (ASYNCWAIT  ID). Соответствие директив определяется одним идентификатором ID.

6.3.4.2.1. Директива ASYNCID

Директива ASYNCID описывает отдельный идентификатор для каждой пары директив асинхронного копирования.

Синтаксис директивы:

asyncid-directive is      ASYNCID async-name-list
   

6.3.4.2.2. Директива F90

Директива 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

6.3.4.2.3. Директивы ASYNCHRONOUS и END ASYNCHRONOUS

Директивы 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 с соответствующим оператором копирования.

6.3.4.2.4. Директива ASYNCWAIT

Синтаксис.

asyncwait-directive is      ASYNCWAIT async-name

Пример из раздела 6.3.4.1 можно специфицировать как асинхронное копирование следующим образом.

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

6.4. Удаленные ссылки типа REDUCTION

6.4.1. Синхронная спецификация удаленных ссылок типа REDUCTION

Если спецификация REDUCTION в параллельном цикле указана без имени группы, то она является синхронной спецификацией и выполняется следующим образом.

  1. Вычисление локальной редукции. В процессе выполнения цикла на каждом процессоре вычисляется локальное значение редукции для той части данных, которые распределены на процессоре.
  2. Вычисление глобальной редукции. После окончания выполнения цикла автоматически вычисляется межпроцессорная редукция локальных значений. Полученное значение присваивается редукционной переменной на каждом процессоре.

6.4.2. Асинхронная спецификация удаленных ссылок типа REDUCTION

Асинхронная спецификация позволяет:

Для асинхронной спецификации, кроме директивы 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 выглядит следующим образом.

CDVM$  REDUCTION_GROUP RD
                     
. . .
CDVM$  PARALLEL ... , REDUCTION (RD : d1)
C               
локальная редукция d1
                    
. . .
CDVM$  PARALLEL ... , REDUCTION (RD : dn)
C              
локальная редукция dn
                    
. . .
CDVM$  REDUCTION_START RD
C              
начало глобальной редукции diU...U dn
                   
. . .
CDVM$  REDUCTION_WAIT RD
C              
конец глобальной редукции di U ... U dn

Ограничения.

Пример 6.11. Асинхронная спецификация типа REDUCTION..

CDVM$   DISTRIBUTE A ( BLOCK )
CDVM$   ALIGN B( I ) WITH A( I )
CDVM$   REDUCTION_GROUP RD
                       
. . .
                   S = 0
CDVM$   PARALLEL ( I ) ON A( I ),
CDVM$* REDUCTION ( RD : SUM(S))
                  DO 10 I = 1, N
10              S = S + A(I)
                  X = 0.
CDVM$   PARALLEL ( I ) ON B( I ),
CDVM$* REDUCTION ( RD : MAX(X))
                  DO 20 I = 1, N
20              X = MAX(X, ABS( B(I) ) )
CDVM$   REDUCTION_START RD
C               
начало глобальной редукции SUM(S) и MAX(X)
CDVM$   PARALLEL ( I ) ON A( I )
                  DO 30 I = 1, N
30             A(I) = A(I) + B(I)
CDVM$  REDUCTION_WAIT RD
C               
конец глобальной редукции
                  PRINT *, S, X

На фоне выполнения групповой редукции будут вычисляться значения элементов массива А.


Fortran-DVM - оглавление Часть 1 (1-4) Часть 2
(5-6)
Часть 3 (7-12) Часть 4 (Приложения)