Вперед: 1.4.3. Эффективность параллельных программ
Назад: 1.4.2.3. Совместное использование MPI и OpenMP
К содержанию: Оглавление


1.4.2.4. Язык параллельного программирования HPF

HPF (High Performance Fortran) является расширением языка Фортран 90 для многопроцессорных вычислительных систем [18]. HPF реализует модель программирования, базирующуюся на параллелизме данных. Параллелизм данных означает, что одна и та же операция применяется к части или всему ансамблю данных, поэтому HPF существенным образом ориентирован на обработку массивов. Массивы распределяются по вычислительным узлам, и каждый узел выполняет обработку своей части массива. От программиста требуется только задать распределение данных, а компилятор автоматически вставит необходимые операции обменов и синхронизаций. Эффективность HPF программы существенным образом зависит от того, насколько удачно выбрано распределение данных. Процедура распределения данных плохо формализуется, поэтому она возлагается на программиста. Для обеспечения параллельной обработки данных в язык HPF по сравнению с Фортран 90 добавлены следующие расширения:

Основная часть расширений реализована в виде директив компилятору. Директивы HPF имеют вид комментариев, начинающихся с символов !HPF$. Директивы не выполняют никаких действий, а лишь задают компилятору дополнительную информацию, требуемую для генерации эффективного кода. Важнейшие из директив связаны с размещением данных и призваны минимизировать коммуникационные операции. Кроме того, имеются директивы для явного указания режимов выполнения циклов. Язык HPF реализует идею <инкрементального распараллеливания> для систем с распределенной памятью и с точки зрения организации и идеологии очень похож на OpenMP.

Разработкой стандарта HPF занимается High Performance Fortran Forum (HPFF). Первая версия HPF 1.0 вышла в 1993 году. Текущей версией является HPF 2.0, разработанной в 1997 г. На сегодняшний день доступно несколько коммерческих версий и несколько версий с открытым кодом. На объединенном кластере механико-математического комплекса ЮФУ (установлена свободно распространяемая система компиляции Adaptor [19].

Посмотрим, как выглядит наша программа на языке HPF.

Программа pi_hpf.f

program pi_hpf
   integer n, i
   double precision d, s, pi
   double precision, dimension (:),
   $      allocatable :: x, y
!HPF$ PROCESSORS procs(4)
!HPF$ DISTRIBUTE x(CYCLIC) ONTO procs
!HPF$ ALIGN y(i) WITH x(i)
   write(*,*) 'n?'
   read(*,*) n
   allocate(x(n))
   allocate(y(n))
   d = 1.0/n
!HPF$ INDEPENDENT
   FORALL (i = 1:n)
    x(i) = (i-0.5)*d
    y(i) = 4.0/(1.0 + x(i)*x(i))
   end FORALL
   pi = d*SUM(y)
   write (*, 100) pi
 100 format(' pi = ', f20.15)
   deallocate(x)
   deallocate(y)
   end

Бросается в глаза, что параллельная программа действительно очень похожа на программу, разработанную средствами OpenMP. Сама программа мало чем отличается от обычной последовательной программы, кроме вставки директив HPF и замены цикла DO на цикл FORALL. Однако, это не принципиальная замена, поскольку оператор цикла FORALL уже давно вошел в стандарты современных версий Фортрана. Кроме того, директива INDEPENDENT воздействует и на обычный цикл DO, заставляя его выполняться в параллельном режиме.

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

Директива "PROCESSORS procs(4)" определяет форму сетки абстрактных процессоров. Подразумевается использование 4-х процессоров с линейной топологией. В данном случае эта директива не обязательна, поскольку линейная топология подразумевается по умолчанию. В тех случаях, когда требуется более сложная топология, то ее необходимо задавать явно. Например, директива ''!HPF$ PROCESSORS procs(6,2)'' описывает двумерную сетку 6?2 из 12 процессоров. При этом программа теряет некоторую универсальность - она может запускаться только на 12 процессорах.

Директива DISTRIBUTE определяет распределение по процессорам массива x. В данном случае принято циклическое распределение - каждый последующий элемент циклически привязывается к следующему процессору. Альтернативный способ x(BLOCK) будет распределять по процессорам непрерывные блоки примерно равной длины.

Директива ALIGN используется для выравнивания распределений массивов x и y. В данном случае требуется, чтобы каждый i-й элемент массива y находился в том же процессоре, где i-й элемент x. При такой схеме размещения заведомо не потребуется пересылок.

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

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

В программе pi_hpf.f искусственно введены массивы x и y, чтобы подчеркнуть присущую HPF парадигму параллелизма данных. Мы векторизуем цикл, затем вектор распределяем по процессорам и производим параллельную обработку частей вектора. Однако некоторые реализации HPF позволяют напрямую производить распараллеливание циклов в стиле OpenMP. В частности, такую возможность допускает система компиляции Adaptor. В этом случае оказалось, что для распараллеливания нашей последовательной программы достаточно добавить всего одну строку - директиву HPF, выделенную жирным шрифтом.

Программа pi_adp.f

program pi_adp
   integer i, n
   double precision w, gsuM
   double precision v

   print *, 'Input number of stripes : '
   read *, n
   w = 1.0 / n
   gsum = 0.0d0
!hpf$ independent, new (v), reduction (gsum)
   do i = 1, n
    v = (i - 0.5d0 ) * w
    v = 4.0d0 / (1.0d0 + v * v)
    gsum = gsum + v
   end do

   print *, 'pi ist approximated with ', gsum *w
   end

Распараллеливание программ с помощью HPF выглядит очень привлекательным. Переделки последовательной программы минимальны, программа очень компактна, однако эффективность программ оставляет желать лучшего. Даже для такой простой задачи, программа на HPF работает в два раза медленнее, чем MPI программа. Причем на любом числе процессоров, даже на одном. Возможно, это относится к конкретной реализации системы компиляции, но в любом случае, из-за низкой эффективности HPF пока не получил такого распространения и признания как MPI.



Вперед: 1.4.3. Эффективность параллельных программ
Назад: 1.4.2.3. Совместное использование MPI и OpenMP
К содержанию: Оглавление