Современные
информационные технологии /Вычислительная техника и программирование
Хмельницкий национальный университет, Украина
Анализ
эффективности использования MPI для пересылки массива данных в системах с
двуядерными процессорами
В
настоящее время существуют различные методы классификации архитектур
параллельных вычислительных систем. Одна из возможных классификаций состоит в
разделении параллельных вычислительных систем по типу памяти (классификация
Джонсона). В этом случае в качестве одного из классов можно выделить
параллельные вычислительные системы с распределенной памятью. Их также
называют массивно-параллельными
системами (MPP). Узлы в массивно-параллельных системах связаны между собой
через коммуникационную среду (например, высокоскоростную сеть с использованием
сетевых карт и коммутаторов).
В
качестве второго класса можно выделить архитектуры параллельных вычислительных
систем с общей памятью (shared memory) или симметричные мультипроцессорные
системы (SMP). Такие системы состоят из нескольких однородных процессоров и
массива общей памяти. Каждый из процессоров имеет прямой доступ к любой ячейке
памяти, причем скорость доступа к памяти для всех процессоров одинакова. Обычно
процессоры подключаются к памяти с помощью общей шины.
В
настоящее время началось широкое использование двуядерных и четырехядерных
микропроцессоров фирм Intel, AMD
и др. Представители компании Intel уже объявили о предстоящем начале выпуска в
ближайшее время 6-ядерных процессоров
При создании параллельных программ,
которые предназначены для многопроцессорных вычислительных систем MPP с
распределенной памятью, для обмена данными между параллельными процессами,
работающими в разных узлах системы, широко применяется интерфейс обмена
сообщениями (Message Passing Interface, MPI). При использовании этого
интерфейса обмен данными между различными процессами в программе осуществляется
с помощью механизма передачи и приемки сообщений. Необходимо отметить, что MPI возможно использовать и для систем с организацией
памяти SMP. В этой работе сопоставляется использование MPI для систем с MPP и SMP. В качестве
первой системы рассматривается кластер из двух компьютеров, соединенных с
помощью сети Fast Ethernet. Программным обеспечением является учебный кластер BCCD, построенный на базе Linux. Для SMP
рассматривается компьютеры с двуядерными процессорами Athlon 64x2 4000+ и Pentium E2160 под
управлением ASP Linux 11.2 с скомпилированным для него пакетом MPICH версии 1.2.7.
Основными алгоритмическими языками параллельного программирования
с использованием MPI в настоящее время являются
Fortran и C/C++. В работе программы представлены на языке Fortran 77.
Рассмотрим установку MPICH на компьютере с двуядерным процессором. На кластере BCCD он установлен и настроен с компилятором Fortran
77 по умолчанию.
Получить исходные коды пакета MPICH можно с сайта – разработчиков: http://www-unix.mcs.anl.gov/mpi. После его получения необходимо создать каталог и
распаковать его там. Далее запустить скрипт конфигурации configure:
configure --with-arch=LINUX --with-device=ch_shmem \
--prefix=/usr/local/mpi/ch_shmem/
Здесь определяется тип архитектуры машины (LINUX), использование разделяемой памяти для внутримашинных
пересылок (--with-device=ch_shmem), путь к каталогу, в котором будет установлен пакет.
Следующим шагом является компиляция и установка MPI:
make
make install
После
установки пакета выполняется описание кластерной системы. Поскольку
используется компьютер с двуядерным процессором в каталоге, где будут
находиться программы, необходимо создать файл с именем machines с содержимым:
komp.tup:2
Здесь komp.tup – доменное имя компьютера (может быть указан его ip – адрес), модификатор “:2” означает использование
двухпроцессорной (SMP) машины. Следует отметить, что ядро LINUX должно быть скомпилировано для поддержки SMP машин.
Процесс
компиляции и исполнения MPI программ
выполняется для простоты с помощью специализированных скриптов. Компиляция программ на языке Fortran выполняется скриптом mpi77:
/usr/local/mpi/ch_shmem/bin/mpif77 ex4.f -o ex4
Здесь ex4.f – исходный
текст программы, ex4 – исполняемый модуль, полученный в результате
компиляции.
Запуск
параллельных программ на исполнение производится с помощью скрипта mpirun:
/usr/local/mpi/ch_shmem/bin/mpirun
-np 2 -machinefile machines ex4
Параметр -np задает количество процессоров кластера (SMP машины), на которых будет запущена программа.
Дополнительный параметр -machinefile
указывает на файл machines, содержащий описание кластера (SMP машины).
Рассмотрим
общую организацию MPI и основные функции MPI, необходимые для составления программы для анализа
эффективности использования MPI в SMP системах.
MPI - это библиотека функций, обеспечивающая
взаимодействие параллельных процессов с помощью механизма передачи сообщений.
Это достаточно объемная и сложная библиотека, состоящая примерно из 130
функций. Однако любая параллельная программа может быть написана с
использованием всего шести MPI функций.
Любая прикладная MPI-программа должна начинаться с
вызова функции инициализации MPI: функции MPI_INIT. В
результате выполнения этой функции создается группа процессов, в которую
помещаются все процессы приложения, и создается область связи, описываемая
коммуникатором MPI_COMM_WORLD. Эта
область связи объединяет все процессы-приложения. Синтаксис функции
инициализации MPI_INIT:
MPI_INIT (IERROR)
Функция
завершения MPI программ: MPI_ FINALIZE:
MPI_FINALIZE (IERROR)
Функция закрывает все MPI-процессы и ликвидирует все области связи. Параметр IERROR является выходным и возвращает код ошибки.
Функция
определения числа процессов в области связи MPI_COMM_SIZE:
MPI_COMM_SIZE
(MPI_COMM_WORLD, SIZE, IERROR)
MPI_COMM_WORLD - коммуникатор;
SIZE - число процессов в области связи коммуникатора MPI_COMM_WORLD.
Функция
определения номера процесса MPI_COMM_RANK:
MPI_COMM_RANK
(MPI_COMM_WORLD, RANK, IERROR)
MPI_COMM_WORLD - коммуникатор;
RANK - номер процесса, вызвавшего функцию.
Номера процессов лежат в диапазоне 0..SIZE-1 (значение SIZE
может быть определено с помощью предыдущей функции).
В минимальный набор следует включить также две функции
передачи и приема сообщений.
Функция
передачи сообщения MPI_SEND:
MPI_SEND (BUF,
COUNT, DATATYPE, DEST, TAG, MPI_COMM_WORLD, IERROR)
BUF - адрес начала
расположения пересылаемых данных (массив или скалярная величина);
COUNT - число пересылаемых элементов (для скалярной
величины COUNT=1);
DATATYPE -
тип посылаемых элементов (MPI_REAL, MPI_DOUBLE_PRECISION, MPI_INTEGER);
DEST - номер процесса-получателя в группе,
связанной с коммуникатором MPI_COMM_WORLD;
TAG - идентификатор сообщения;
MPI_COMM_WORLD - коммуникатор области связи.
Функция
приема сообщения - MPI_RECV
MPI_RECV (BUF,
COUNT, DATATYPE, SOURCE,TAG,MPI_COMM_WORLD,
STATUS, IERROR)
BUF - адрес начала расположения принимаемого сообщения;
COUNT - максимальное число принимаемых элементов;
DATATYPE - тип элементов принимаемого сообщения;
SOURCE - номер процесса-отправителя;
TAG - идентификатор сообщения;
MPI_COMM_WORLD - коммуникатор области связи;
STATUS (MPI_STATUS_SIZE) - массив атрибутов приходящего сообщения. В Фортране параметр STATUS является целочисленным массивом размера MPI_STATUS_SIZE. Константы MPI_SOURCE, MPI_TAG, MPI_ERROR - являются индексами
по данному массиву для доступа к значениям соответствующих полей:
STATUS (MPI_SOURCE) - номер процесса-отправителя сообщения;
STATUS (MPI_TAG)
- идентификатор сообщения;
STATUS (MPI_ERROR) – код ошибки.
Рассмотрим функцию времени -
таймер, которая важна для разработки
эффективных программ. Ее синтаксис:
MPI_WTIME()
Функция возвращает
астрономическое время в секундах, прошедшее с некоторого момента в прошлом
(точки отсчета). Гарантируется, что эта точка отсчета не будет изменена в
течение жизни процесса. Для хронометража участка программы вызов функции
делается в начале и конце участка и определяется разница между показаниями
таймера.
Рассмотрим программу, написанную с
использованием MPI, которая позволяет определить время пересылки блока данных
двойной точности (DOUBLE PRECISION) с одного процесса на другой и определить
время присваивания одному массиву значений другого массива внутри одного
процесса при работе с памятью. Считается, что каждый процесс выполняется на
одном узле (для кластерной системы) и на одном ядре процессора (для SMP
системы). Ниже представлен текст этой программы с поясняющими ее работу комментариями.
program
example4
include 'mpif.h'
integer ierr, rank, size
DOUBLE PRECISION
b(1000000),a(1000000),c(1000000)
double precision time_start, time,
time_finish
integer status(MPI_STATUS_SIZE)
parameter (mm=1000, mm0=10000)
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, size,
ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank,
ierr)
c Присвоение значений массиву b из mm
элементов
if(rank.eq.0)
then
do i=1,mm
b(i)=i/1.0d0
enddo
print *, ' BEGIN', ' b=(mm)',b(mm),'
rank=',rank
time_start = MPI_WTIME(ierr)
endif
c Передача значений b(i) от 0-го
процессора 1-му.
c Процесс передачи выполняется mm0 раз
do
i=1,mm0
if (rank .eq. 0) then
call MPI_SEND(b, mm,
MPI_DOUBLE_PRECISION,
&1,5,MPI_COMM_WORLD, ierr)
endif
c Прием массива b в массив c
if (rank.eq.1) then
call MPI_RECV(c,mm,MPI_DOUBLE_PRECISION,
&0,5,MPI_COMM_WORLD, status,ierr)
endif
end do
c Определение времени на передачу данных
if
(rank.eq.0) then
time_finish = MPI_WTIME(ierr)
time=(time_finish-time_start)/mm0
print *, ' time=', time
endif
c Распечатываем, те ли значения получены
1-м процессором
if
(rank.eq.1) then
print *, ' c(mm)=',c(mm),' proc=',rank
endif
c В 0-м процессоре выполняем пересылку
массива b в массив a
c mm0 раз и определяем время такой
пересылки
if
(rank.eq.0) then
time_start = MPI_WTIME(ierr)
do m=1,mm0
do i=1,mm
a(i)=b(i)
enddo
enddo
time_finish = MPI_WTIME(ierr)
time=(time_finish-time_start)/mm0
print *, ' a(mm)=',a(mm),' time=',time,'
rank=', rank
endif
c
call MPI_FINALIZE(ierr)
end
Эта
программа запускалась на кластере BCCD 2.2.1.c7, который был построен на базе
2-х компьютерах с процессорами Pentium IV 3.0GHz/1024/800MHz,
соединенных сетью Fast Ethernet. Размер блока данных варьировался от 5
элементов двойной точности до 4000. В таблице 1 представлены результаты замеров
длительности пересылок. Видно, что время пересылок данных между
компьютерами более чем в 160 раз больше
времени работа процессора с собственной памятью. Таким образом, процесс
распараллеливания будет эффективным, если время работы параллельной части
программы на одном узле кластера будет
не менее чем в 300-400 раз больше времени пересылки блока данных размером более
100 элементов внутри одного процессора. Или, если пересылается между узлами
кластера массив размером 1000 элементов двойной точности, то время выполнения
параллельной части программы для представленных в эксперименте технических
средств должно быть более 756 мкс. Иначе за счет большой латентности, которая определяется временем подготовки
передачи данных и временем передачи данных, распараллеливание процесса
вычислений будет нецелесообразным.
Таблица 1.
Число
пересылаемых элементов массива |
Время
пересылки между двумя процессорами в мкс |
Время
присваивания значений другому массиву на 0-м процессоре в мкс |
Во
сколько раз время пересылки MPI больше
времени работы одного процессора с памятью |
5 |
23.3 |
0.028 |
832 |
10 |
24.0 |
0.05 |
480 |
100 |
80 |
0.47 |
170.8 |
500 |
381 |
2.3 |
165.7 |
1000 |
756 |
4.6 |
164.3 |
2000 |
1507 |
8.9 |
169.3 |
3000 |
2288 |
13.9 |
164.6 |
4000 |
3064 |
17.5 |
175.0 |
В таблице 2 представлены результаты
работы этой программы на компьютере с двуядерным процессором Athlon 64x2 4000+ .
Программа выполнялась под управлением операционной системы ASP Linux
11.2. Видно, что пересылки массива между процессорами выполняются существенно
быстрее, чем между узлами кластера. Однако время пересылки массива между
процессорами с помощью MPI для любого
числа элементов более чем в два раза больше времени работы одного процессора с
памятью для Athlon 64x2 4000+.
Таблица 2.
Число
пересылаемых элементов массива |
Время
пересылки между двумя процессорами в мкс |
Время
присваивания значений другому массиву на 0-м процессоре в мкс |
Во
сколько раз время пересылки MPI больше
времени работы одного процессора с памятью |
1 |
3.5 |
0.01 |
350.0 |
10 |
3.2 |
0.076 |
42.1 |
100 |
4.5 |
0.64 |
7.0 |
500 |
11.8 |
3.4 |
3.5 |
1000 |
16.9 |
6.2 |
2.7 |
2000 |
28.9 |
12.4 |
2.3 |
3000 |
46.2 |
19.0 |
2.4 |
4000 |
61.1 |
25.5 |
2.4 |
5000 |
73.1 |
32.7 |
2.2 |
10000 |
139.0 |
70.3 |
2.0 |
В таблице 3 представлены результаты
работы представленной программы на компьютере с двуядерным процессором Pentium E2160.
Программа выполнялась под управлением операционной системы ASP Linux
11.2.
Таблица 3.
Число пересылаемых элементов массива |
Время пересылки между двумя процессорами в мкс |
Время присваивания значений другому массиву на 0-м
процессоре в мкс |
Во сколько раз время пересылки MPI больше времени работы одного процессора с памятью |
1 |
5.3 |
0.013 |
406.9 |
10 |
5.2 |
0.073 |
71.2 |
100 |
5.7 |
0.73 |
7.8 |
500 |
8.4 |
3.60 |
2.3 |
1000 |
8.9 |
7.20 |
1.2 |
2000 |
13.4 |
14.2 |
0.9 |
3000 |
14.2 |
15.10 |
0.9 |
4000 |
16.4 |
19.60 |
0.8 |
5000 |
18.5 |
26.80 |
0.7 |
10000 |
52.8 |
49.20 |
1.1 |
20000 |
84.7 |
98.90 |
0.9 |
30000 |
169.6 |
147.60 |
1.1 |
40000 |
207.0 |
210.10 |
1.0 |
В отличии от процессора Athlon 64x2 4000+ время
пересылок для больших массивов примерно одинаковое и для некоторых размерностей
массивов(2000-5000) межпроцессорные пересылки с помощью MPI более эффективны, чем работа одного процессора
напрямую с памятью. На основании анализа таблиц 2 и 3 можно сделать предварительный вывод, что многоядерные процессоры Pentium лучше подходят для параллельных вычислений.
Литература.
1.Ю.Сбитнев. Серия Линукс. Параллельные
вычисления (практическое руководство по параллельным вычислениям). http://linux-cluster.org.ru/
2.Антонов А.С. Введение в
параллельные вычисления (методическое пособие). Москва, НИВЦ МГУ, 2002, -69 c.
3.В.П. Гергель.Теория и практика
параллельных вычислений. http://www.intuit.ru/department/calculate/paralltp/