Современные информационные технологии /Вычислительная техника и программирование

 Мясищев А.А.

Хмельницкий национальный университет, Украина

Анализ эффективности использования 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/