Глава 2. Системные программные средства
СИСТЕМЫ ПРОГРАММИРОВАНИЯ ДЛЯ КЛАСТЕРОВ
Основными средствами программирования для многопроцеccорных систем являются две библиотеки, оформленные как стандарты: библиотека OpenMP для систем с общей памятью (для SMPсистем) и библиотека MPI для систем с индивидуальной памятью.
Определенное распространение получила и библиотека PVM
(Parallel Virtual Machine), которая также предназначена для параллельных вычислений на машинах с индивидуальной памятью [13].
Она близка по значению и набору функций к библиотеке MPI, однако спецификация PVM не регламентируется каким-либо из общепринятых стандартов, поэтому PVM не используется в крупных проектах.
Документация с описанием по библиотеки PVM доступна в по адресу:
http://www.csm.ornl.gov/pvm/pvm_home.html.
2.1.1. Стандарт OpenMp вставка лекции
Библиотека OpenMP [1,8] является стандартом для программирования на масштабируемых SMP-системах. В стандарт входят описания набора директив компилятора, переменных среды и процедур. За счет идеи «инкрементального распараллеливания» OpenMP идеально подходит для разработчиков, желающих быстро распараллелить свои вычислительные программы с большими параллельными циклами.
Разработчик не создает новую параллельную программу, а просто добавляет в текст последовательной программы директивы OpenMP.
Предполагается, что программа OpenMP на однопроцессорной платформе может быть использована в качестве последовательной программы, т.е. нет необходимости поддерживать последовательную и параллельную версии. Директивы OpenMP просто игнорируются последовательным компилятором, а для вызова процедур OpenMP могут быть поставлены заглушки, текст которых приведен в спецификациях.
В OpenMP любой процесс состоит из нескольких нитей управления, которые имеют общее адресное пространство, но разные потоки команд и раздельные стеки. В простейшем случае процесс состоит из одной нити.
Обычно для демонстрации параллельных вычислений используют простую программу вычисления числа π. Число π можно определить следующим образом:
1 dx
∫ = arctg(1) – arctg(0) = π/4.
0 1+ x2
Вычисление интеграла затем заменяют вычислением суммы:
1 4 1 n 4
∫ 2
dx ≈ ∑ ,
0 1+ x n i =1 1 + xi 2
где xi = 1/n(i – 0,5).
В последовательную программу вставляются две строки, и она становится параллельной.
program compute_pi
parameter (n = 1000)
integer i
double precision w,x,sum,pi,f,a
f(a) = 4.d0/(1.d0+a*a)
w = 1.0d0/n
sum = 0.0d0;
!$OMP PARALLEL DO PRIVATE(x), SHARED(w)
!$OMP& REDUCTION(+:sum)
do i=1,n
x = w*(i-0.5d0)
sum = sum + f(x)
enddo
pi = w*sum
print *,'pi = ',pi
stop
end
Программа начинается как единственный процесс на головном процессоре. Он исполняет все операторы до первой директивы типа PARALLEL. В данном примере это оператор PARALLEL DO, после исполнения которого следующий за ним цикл do ... enddo становится параллельным, т. е. в нем порождается множество процессов с соответствующим каждому процессу окружением.
В рассматриваемом примере окружение состоит из локальной переменной х (PRIVATE), переменной sum редукции (REDUCTION) и одной разделяемой переменной w (SHARED). Переменные х и sum локальны в каждом процессе без разделения между несколькими процессами. Переменная w располагается в головном процессе. Оператор редукции REDUCTION имеет в качестве атрибута операцию, которая применяется к локальным копиям параллельных процессов в конце каждого процесса для вычисления значения переменной в головном процессе. Переменная цикла n определяет общее количество итераций цикла. Эти итерации разбиваются на блоки смежных итераций и каждый блок назначается отдельному процессу. Параллельные процессы завершаются оператором enddo, выступающим как синхронизирующий барьер для порожденных процессов. После завершения всех процессов продолжается только головной процесс.
Директивы OpenMP с точки зрения Фортрана являются комментариями и начинаются с комбинации символов «!$OMP». Директивы можно разделить на три категории: определение параллельной секции, разделение работы, синхронизация. Каждая директива может иметь несколько дополнительных атрибутов − клауз. Отдельно специфицируются клаузы для назначения классов переменных, которые могут быть атрибутами различных директив.
Директивы определения параллельной секции PARALLEL приводят к порождению N–1 новых процессов, называемых в OpenMP нитями, а порождающая нить получает номер 0 и становится основной нитью команды («master thread»). При выходе из параллельной области основная нить дожидается завершения остальных нитей и продолжает выполнение в одном экземпляре. Значение N обычно равно числу процессоров в системе.
Блоки итераций между нитями (процессорами) могут распределяться по разному:
• STATIC, m – статически, блоками по m итераций;
• DYNAMIC, m – динамически, блоками по m (каждая нить берет
на выполнение первый еще не взятый блок итераций);
• GUIDED, m – размер блока итераций уменьшается экспоненциально до величины m;
• RUNTIME – выбирается во время выполнения.
Директивы синхронизации обеспечивают как корректность работы нитей над общей памятью, так и барьерную синхронизацию, при которой каждая нить дожидается всех остальных, перед или после завершения параллельного участка программы.
Переменные OpenMP в параллельных областях программы разделяются на два основных класса: SHARED (общие − под именем A все
нити видят одну переменную) и PRIVATE (приватные − под именем
A каждая нить видит свою переменную).