О.В.Сухорослов "Параллельное программирование....
DESCRIPTION
О.В.Сухорослов "Параллельное программирование. Часть 2", 23.03.2012, место показа: МФТИ, Школа анализа данных (ШАД)TRANSCRIPT
05 Параллельное программирование
О.В. Сухорослов
23.03.2011
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 1 / 82
План лекции
Знакомство с MPI
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 2 / 82
Message Passing Interface
Стандарт де-факто для высокопроизводительных вычислений насистемах с распределенной памятью (кластерах,суперкомпьютерах)
Интерфейс прикладного программирования, основанный наобмене сообщениями между параллельными процессами
message-passing library specificationпривязки к языкам (Fortran, C, C++)
Несколько независимых реализаций (библиотек),поддерживающих большинство архитектур с распределеннойпамятью и коммуникационных интерфейсов (интерконнектов)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 3 / 82
Цели
Переносимость
Высокая производительность
Масштабируемость (?)
Надежность
Непрерывность функционирования
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 4 / 82
Краткая история
Апрель 1992 — начало работы над спецификациейоколо 60 специалистов из 40 организаций в США и Европе
Ноябрь 1992 — первый черновой вариантНоябрь 1993 — final draftМай 1994 — спецификация MPI-1Июнь 1995 — MPI-1.1Июль 1997 — MPI-2Сентябрь 2008 — MPI-2.1Сентябрь 2009 — MPI-2.2
http://www.mpi-forum.org/
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 5 / 82
Реализации
MPICH / MPICH2Argonne National Laboratory
Open MPIОбъединение нескольких реализаций в новый проект (FT-MPI,LA-MPI, LAM/MPI, PACX-MPI)Используется на учебном кластере
Поддерживают Fortran, C, C++“Нестандартные” реализации см. в конце лекции
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 6 / 82
Модель программирования
Программа состоит из N параллельных процессовПроцессы порождаются один раз при запуске программы (MPI-1)или динамически во время выполнения (MPI-2)
Каждый процесс имеет отдельное адресное пространство, общейпамяти нет
Процессы взаимодействуют путем отправки и получениясообщений
В MPI-2 добавлен доступ к памяти удаленного процесса
Процессы могут образовывать группыГруппы могут создаваться динамически и иметь произвольнуюконфигурациюКаждый процесс имеет уникальный идентификатор [0, N-1] врамках группы
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 7 / 82
Модель программирования
Программа состоит из N параллельных процессовПроцессы порождаются один раз при запуске программы (MPI-1)или динамически во время выполнения (MPI-2)
Каждый процесс имеет отдельное адресное пространство, общейпамяти нет
Процессы взаимодействуют путем отправки и получениясообщений
В MPI-2 добавлен доступ к памяти удаленного процесса
Процессы могут образовывать группыГруппы могут создаваться динамически и иметь произвольнуюконфигурациюКаждый процесс имеет уникальный идентификатор [0, N-1] врамках группы
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 7 / 82
Модель программирования
Программа состоит из N параллельных процессовПроцессы порождаются один раз при запуске программы (MPI-1)или динамически во время выполнения (MPI-2)
Каждый процесс имеет отдельное адресное пространство, общейпамяти нет
Процессы взаимодействуют путем отправки и получениясообщений
В MPI-2 добавлен доступ к памяти удаленного процесса
Процессы могут образовывать группыГруппы могут создаваться динамически и иметь произвольнуюконфигурациюКаждый процесс имеет уникальный идентификатор [0, N-1] врамках группы
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 7 / 82
Модель программирования
Программа состоит из N параллельных процессовПроцессы порождаются один раз при запуске программы (MPI-1)или динамически во время выполнения (MPI-2)
Каждый процесс имеет отдельное адресное пространство, общейпамяти нет
Процессы взаимодействуют путем отправки и получениясообщений
В MPI-2 добавлен доступ к памяти удаленного процесса
Процессы могут образовывать группыГруппы могут создаваться динамически и иметь произвольнуюконфигурациюКаждый процесс имеет уникальный идентификатор [0, N-1] врамках группы
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 7 / 82
Коммуникатор
Объект, обозначающий группу процессов, которые могутвзаимодействовать друг с другом
С точки зрения программиста аналогичен группеМогут создаваться и уничтожаться динамически
Все MPI-сообщения должны быть связаны с определеннымкоммуникатором
MPI_COMM_WORLDКоммуникатор по-умолчаниюВключает все процессы программы
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 8 / 82
Функции MPI (язык C)
Описаны в mpi.h
Имеют префикс MPI_
Как правило возвращают код выполнения операцииMPI_SUCCESS или код ошибки
Другие результаты возвращаются через аргументы функции
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 9 / 82
Общая структура программы
1 #include <mpi.h>2
3 int main(int argc , char **argv)4 {5 ...6
7 MPI_Init (&argc , &argv);8
9 // parallel part10
11 MPI_Finalize ();12
13 ...14 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 10 / 82
hello.c
1 #include <mpi.h>2 #include <stdio.h>3
4 int main(int argc , char **argv)5 {6 int rank , size , len;7 char host[MPI_MAX_PROCESSOR_NAME ];8
9 MPI_Init (&argc , &argv);10 MPI_Comm_rank(MPI_COMM_WORLD , &rank);11 MPI_Comm_size(MPI_COMM_WORLD , &size);12 MPI_Get_processor_name(host , &len);13
14 printf("Hello , world. I am %d of %d on %s\n",15 rank , size , host);16
17 MPI_Finalize ();18 return 0;19 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 11 / 82
Компиляция и запуск
Спецификация MPI не содержит конкретных требований покомпиляции и запуску программ
Open MPI и MPICH-2mpicc -o hello hello.c
Поддерживаются стандартные опции GCC
mpirun -np число_процессов hello
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 12 / 82
Запуск программы на головной машине кластера
sol@hadoop2 -00:~/ mpi$ mpirun -np 4 helloHello , world. I am 0 of 4 on hadoop2 -00Hello , world. I am 1 of 4 on hadoop2 -00Hello , world. I am 2 of 4 on hadoop2 -00Hello , world. I am 3 of 4 on hadoop2 -00
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 13 / 82
Запуск программы на нескольких узлах кластера
Запуск MPI-программы на кластере обычно осуществляется спомощью команд системы управления заданиями (batch system)
Обеспечивает эффективное использование ресурсов кластерагруппой пользователейНазначает узлы кластера для выполнения заданийУправляет очередью заданий
На учебном кластере используется система TORQUEСм. инструкцию к учебному кластеру на вики
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 14 / 82
Запуск программы на нескольких узлах кластера
sol@hadoop2 -00:~/ mpi$ qsub -l nodes=4 hello.run157. hadoop2 -00. yandex.ru
sol@hadoop2 -00:~/ mpi$ cat hello.run.o157Hello , world. I am 0 of 4 on hadoop2 -02Hello , world. I am 2 of 4 on hadoop2 -00Hello , world. I am 1 of 4 on hadoop2 -01Hello , world. I am 3 of 4 on hadoop2 -04
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 15 / 82
Модель передачи сообщений
Передача данных между процессами осуществляется путемотправки и приема сообщения
Требует совместной работы отправляющего и принимающегопроцессов
Изменение памяти принимающего процесса происходит при егоявном участии
Объединение коммуникации и синхронизации
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 16 / 82
Функции передачи сообщениями
"Точка-точка"(point-to-point)Участвует пара процессов
КоллективныеУчаствуют все процессы коммуникатора
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 17 / 82
Передача “точка-точка”
Кому отправлены данные?Где находятся данные?Какой тип имеют данные?Какой объем данных отправлен?От кого и что за данные получены?
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 18 / 82
Структура сообщения
ДанныеБуфер (непрерывный участок памяти)Число элементов в буфереТип элементов данных
Заголовок (envelope)Идентификаторы отправителя и получателяТег сообщенияКоммуникатор (группа)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 19 / 82
Стандартные блокирующие функции
int MPI_Send( void *buf , int count , MPI_Datatype type ,int dest , int tag , MPI_Comm comm )
int MPI_Recv( void *buf , int count , MPI_Datatype datatype ,int source , int tag , MPI_Comm comm , MPI_Status *status )
buf — адрес начала буфераcount — число элементов в сообщенииdatatype — тип элементов данныхdest — номер процесса-получателяsource — номер процесса-отправителя или MPI_ANY_SOURCE
tag — тег сообщения или MPI_ANY_TAG
comm — идентификатор коммуникатора или MPI_COMM_WORLD
status — параметры принятого сообщения (source, tag)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 20 / 82
Базовые типы данных
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 21 / 82
hello2.c
1 #include <mpi.h>2 #include <stdio.h>34 int main(int argc , char **argv)5 {6 int rank , size , len , tag=1;7 char host[MPI_MAX_PROCESSOR_NAME ];8 char msg [50];9
10 MPI_Init (&argc , &argv);11 MPI_Comm_rank(MPI_COMM_WORLD , &rank);12 MPI_Comm_size(MPI_COMM_WORLD , &size);13 MPI_Get_processor_name(host , &len);1415 if (rank == 0) {16 int i;17 MPI_Status status;1819 printf("Hello , world. I am %d of %d on %s\n", rank , size , host);20 for (i = 1; i < size; i++) {21 MPI_Recv(msg , 50, MPI_CHARACTER , MPI_ANY_SOURCE , tag ,22 MPI_COMM_WORLD , &status );23 printf("Msg from %d: ’%s’\n", status.MPI_SOURCE , msg);24 }25 } else {26 snprintf(msg , 50, "Hello , master. I am %d of %d on %s", rank , size , host);27 MPI_Send(msg , 50, MPI_CHARACTER , 0, tag , MPI_COMM_WORLD );28 }2930 MPI_Finalize ();31 return 0;32 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 22 / 82
Результат запуска
Hello , world. I am 0 of 10 on node -10-07Msg from 1: ’Hello , master. I am 1 of 10 on node -10-07’Msg from 2: ’Hello , master. I am 2 of 10 on node -10-07’Msg from 3: ’Hello , master. I am 3 of 10 on node -10-07’Msg from 4: ’Hello , master. I am 4 of 10 on node -10-07’Msg from 5: ’Hello , master. I am 5 of 10 on node -10-07’Msg from 6: ’Hello , master. I am 6 of 10 on node -10-07’Msg from 7: ’Hello , master. I am 7 of 10 on node -10-07’Msg from 8: ’Hello , master. I am 8 of 10 on node -10-10’Msg from 9: ’Hello , master. I am 9 of 10 on node -10-10’
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 23 / 82
Гарантии при передаче сообщений
Гарантируется сохранение порядка сообщений от каждогопроцесса-отправителя
Не гарантируется “справедливость” доставки сообщений отнескольких отправителей
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 24 / 82
Получение информации о новом сообщении
int MPI_Probe( int source , int tag , MPI_Comm comm ,MPI_Status *status)
Получение информации о структуре ожидаемого сообщения сблокировкойПараметры сообщения записываются в status
int MPI_Get_count( MPI_Status *status ,MPI_Datatype datatype , int *count)
Записывает в count число принятых (после MPI_Recv) илипринимаемых (после MPI_Probe) элементов сообщения
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 25 / 82
Что означает завершение MPI_Send ?
Буфер можно повторно использовать, не опасаясь испортитьпередаваемое сообщение?
Сообщение покинуло хост процесса-отправителя?
Сообщение принято процессом-получателем?
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 26 / 82
Один из вариантов реализации
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 27 / 82
Виды блокирующих вызовов
Стандартные прием/передачаВозврат гарантирует безопасное использование аргументов вызова(сообщение считано из / записано в буфер)
Передача с буферизацией (MPI_Bsend)Возврат после записи сообщения в системный буферНе требует вызова функции приема сообщения
Передача с синхронизацией (MPI_Ssend)Возврат после начала приема сообщения процессом-получателемГарантирует безопасное использование буфера
Передача по готовности (MPI_Rsend)Процесс-получатель должен инициировать прием сообщенияУменьшает накладные расходы на организацию передачи
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 28 / 82
Блокирующие передача-прием
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 29 / 82
Чем опасна такая ситуация?
Процесс 1
...MPI_Send
...MPI_Recv
...
Процесс 2
...MPI_Send
...MPI_Recv
...
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 30 / 82
Предотвращение взаимной блокировки
Поменять порядок операций передачи/приема в одном изпроцессов
Использовать неблокирующие функции или совмещеннуюпередачу-прием
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 31 / 82
Неблокирующие функции
Возврат происходит сразу после инициализации процессапередачи/приема
ПередачаMPI_Isend(..., MPI_Request *request)MPI_Ibsend(..., MPI_Request *request)MPI_Issend(..., MPI_Request *request)MPI_Irsend(..., MPI_Request *request)
ПриемMPI_Irecv(..., MPI_Request *request)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 32 / 82
Как узнать что прием или передача завершены?
Блокирующие функции (ожидание)
int MPI_Wait( MPI_Request *request , MPI_Status *status)
MPI_Waitall (), MPI_Waitany (), MPI_Waitsome ()
Неблокирующие функции (проверка)
int MPI_Test( MPI_Request *request ,int *flag , MPI_Status *status)
MPI_Testall (), MPI_Testany (), MPI_Testsome ()
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 33 / 82
Неблокирующие передача-прием
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 34 / 82
hello3.c
1 prev = (rank + size - 1) % size;2 next = (rank +1) % size;3
4 MPI_Irecv (&in_buf1 , 50, MPI_CHARACTER , prev , tag1 ,5 MPI_COMM_WORLD , &reqs [0]);6 MPI_Irecv (&in_buf2 , 50, MPI_CHARACTER , next , tag2 ,7 MPI_COMM_WORLD , &reqs [1]);8
9 snprintf(out_buf1 , 50, "Hello , next. I am %d of %d on %s",10 rank , size , host);11 snprintf(out_buf2 , 50, "Hello , prev. I am %d of %d on %s",12 rank , size , host);13 MPI_Isend (&out_buf1 , 50, MPI_CHARACTER , next , tag1 ,14 MPI_COMM_WORLD , &reqs [2]);15 MPI_Isend (&out_buf2 , 50, MPI_CHARACTER , prev , tag2 ,16 MPI_COMM_WORLD , &reqs [3]);17
18 MPI_Waitall (4, reqs , stats);19
20 printf("[%d] Msg from %d: ’%s’\n", rank ,21 stats [0]. MPI_SOURCE , in_buf1 );22 printf("[%d] Msg from %d: ’%s’\n", rank ,23 stats [1]. MPI_SOURCE , in_buf2 );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 35 / 82
Результат запуска
[7] Msg from 6: ’Hello , next. I am 6 of 10 on node -10-10’[7] Msg from 8: ’Hello , prev. I am 8 of 10 on node -11-03’[1] Msg from 0: ’Hello , next. I am 0 of 10 on node -10-10’[1] Msg from 2: ’Hello , prev. I am 2 of 10 on node -10-10’[2] Msg from 1: ’Hello , next. I am 1 of 10 on node -10-10’[3] Msg from 2: ’Hello , next. I am 2 of 10 on node -10-10’[3] Msg from 4: ’Hello , prev. I am 4 of 10 on node -10-10’[4] Msg from 3: ’Hello , next. I am 3 of 10 on node -10-10’[4] Msg from 5: ’Hello , prev. I am 5 of 10 on node -10-10’[5] Msg from 4: ’Hello , next. I am 4 of 10 on node -10-10’[5] Msg from 6: ’Hello , prev. I am 6 of 10 on node -10-10’[6] Msg from 5: ’Hello , next. I am 5 of 10 on node -10-10’[6] Msg from 7: ’Hello , prev. I am 7 of 10 on node -10-10’[9] Msg from 8: ’Hello , next. I am 8 of 10 on node -11-03’[9] Msg from 0: ’Hello , prev. I am 0 of 10 on node -10-10’[2] Msg from 3: ’Hello , prev. I am 3 of 10 on node -10-10’[0] Msg from 9: ’Hello , next. I am 9 of 10 on node -11-03’[0] Msg from 1: ’Hello , prev. I am 1 of 10 on node -10-10’[8] Msg from 7: ’Hello , next. I am 7 of 10 on node -10-10’[8] Msg from 9: ’Hello , prev. I am 9 of 10 on node -11-03’
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 36 / 82
Перекрытие вычислений и обмена данными
Идиома "Double Buffering"
1 void slave() {2 double *buf1 , *buf2 , *tmp;3 MPI_Status status;4 buf1 = (double *) malloc(sizeof(double) * size);5 buf2 = (double *) malloc(sizeof(double) * size);6 MPI_Recv(buf1 , size , MPI_DOUBLE , MPI_ANY_SOURCE ,7 MPI_ANY_TAG , MPI_COMM_WORLD , &status );8 while (! finished ()) {9 MPI_Request request;
10 MPI_Irecv(buf2 , size , MPI_DOUBLE , MPI_ANY_SOURCE ,11 MPI_ANY_TAG , MPI_COMM_WORLD , &request );12 /* process data in buf1 */13 MPI_Wait (&request , &status );14 tmp = buf1; buf1 = buf2; buf2 = tmp;15 }16 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 37 / 82
Cовмещенная передача-прием
int MPI_Sendrecv( void *sendbuf , int sendcount ,MPI_Datatype sendtype , int dest , int sendtag ,void *recvbuf , int recvcount ,MPI_Datatype recvtype , int source , int recvtag ,MPI_Comm comm , MPI_Status *status )
Предотвращает возникновение взаимной блокировки в описаннойранее ситуации (пары блокирующих send/receive)
Не гарантирует защиту от любых взаимных блокировок!
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 38 / 82
Неблокирующая проверка сообщений
int MPI_Iprobe( int source , int msgtag , MPI_Comm comm ,int *flag , MPI_Status *status)
в параметре flag возвращает значение1, если сообщение с подходящими атрибутами уже может бытьпринято0 - в противном случае
в параметре status возвращает информацию об обнаруженномсообщении (если flag==1)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 39 / 82
Сохраненные запросы
MPI_Send_initТочно такие же параметры, что у MPI_IsendНо отправка сразу не начинаетсяВарианты MPI_(B,S,R)send_init ...
MPI_Recv_initТочно такие же параметры, что у MPI_IrecvНо прием сразу не начинается
MPI_Start(MPI_Request *request)Запуск сохраненного запроса
MPI_Startall( int count, MPI_Request *requests)Запуск всех сохраненных запросов
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 40 / 82
Коллективные взаимодействия
Участвуют все процессы коммуникатора
Соответствующая функция должна быть вызвана каждымпроцессом
Все коллективные функции являются блокирующими и неиспользуют теги
Коллективные и взаимодействия “точка-точка” в рамках одногокоммуникатора используют различные контексты
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 41 / 82
Типы коллективных взаимодействий
Обмен данными
Коллективные вычисления
Синхронизация
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 42 / 82
Обмен данными
MPI_BcastMPI_ScatterMPI_GatherMPI_AllgatherMPI_Alltoall
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 43 / 82
MPI_Bcast
int MPI_Bcast( void *buf , int count , MPI_Datatype datatype ,int source , MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 44 / 82
MPI_Scatter
int MPI_Scatter( void *sbuf , int scount , MPI_Datatype stype ,void *rbuf , int rcount , MPI_Datatype rtype ,int source , MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 45 / 82
MPI_Gather
int MPI_Gather( void *sbuf , int scount , MPI_Datatype stype ,void *rbuf , int rcount , MPI_Datatype rtype ,int dest , MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 46 / 82
MPI_Allgather
int MPI_Allgather( void* sbuf , int scount , MPI_Datatype stype ,void *rbuf , int rcount , MPI_Datatype rtype ,MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 47 / 82
MPI_Alltoall
int MPI_Alltoall( void* sbuf , int scount , MPI_Datatype stype ,void* rbuf , int rcount , MPI_Datatype rtype ,MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 48 / 82
Дополнительные функции
MPI_ScattervMPI_GathervMPI_AllgathervMPI_Alltoallv
Поддерживают порции данных различной длины
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 49 / 82
Коллективные вычисления
MPI_ReduceMPI_AllreduceMPI_Reduce_scatterMPI_Scan
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 50 / 82
MPI_Reduce
int MPI_Reduce( void *sbuf , void *rbuf , int count ,MPI_Datatype datatype ,MPI_Op op, int root , MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 51 / 82
MPI_Allreduce
int MPI_Allreduce( void *sbuf , void *rbuf , int count ,MPI_Datatype datatype ,MPI_Op op , MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 52 / 82
MPI_Reduce_scatter
int MPI_Reduce_scatter( void* sbuf , void* rbuf , int count ,MPI_Datatype datatype ,MPI_Op op, MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 53 / 82
MPI_Scan
int MPI_Scan( void* sbuf , void* rbuf , int count ,MPI_Datatype datatype ,MPI_Op op, MPI_Comm comm )
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 54 / 82
Встроенные операции
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 55 / 82
Пользовательские операции
Только ассоциативные!
Прототип функцииtypedef void MPI_User_function( void *invec , void *inoutvec ,
int *len , MPI_Datatype *datatype )
Регистрацияint MPI_Op_create( MPI_User_function *function ,
int commute , MPI_Op *op )
Уничтожениеint MPI_Op_free(MPI_Op *op)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 56 / 82
Синхронизация
int MPI_Barrier(MPI_Comm comm)
Блокирует работу процессов, вызвавших данную функцию,до тех пор, пока все оставшиеся процессы группы commтакже не выполнят эту процедуру
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 57 / 82
Вычисление π (pi.c)
1 int n, myid , numprocs , i;2 double PI25DT = 3.141592653589793238462643;3 double mypi , pi, h, sum , x, time;45 MPI_Init (&argc ,&argv);6 MPI_Comm_size(MPI_COMM_WORLD ,& numprocs );7 MPI_Comm_rank(MPI_COMM_WORLD ,&myid);89 if (myid == 0) {
10 printf("Enter the number of intervals: "); fflush(stdout ); scanf("%d",&n);11 time = MPI_Wtime ();12 }13 MPI_Bcast (&n, 1, MPI_INT , 0, MPI_COMM_WORLD );1415 h = 1.0 / (double) n;16 sum = 0.0;17 for (i = myid + 1; i <= n; i += numprocs) {18 x = h * (( double)i - 0.5);19 sum += 4.0 / (1.0 + x*x);20 }21 mypi = h * sum;2223 MPI_Reduce (&mypi , &pi , 1, MPI_DOUBLE , MPI_SUM , 0, MPI_COMM_WORLD );2425 if (myid == 0) {26 time = MPI_Wtime () - time;27 printf("pi is approximately %.16f, Error is %.16f, Run time is %fs\n",28 pi, fabs(pi - PI25DT), time);29 }3031 MPI_Finalize ();
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 58 / 82
Обработка изображения (contrast.c)
1 #include <mpi.h>2 #include <stdio.h>3 #include <math.h>4 int main(int argc , char *argv [])5 {6 int width = 256, height = 256, rank , comm_size;7 int sum , my_sum , numpixels , my_count , i, val;8 unsigned char pixels [65536] , recvbuf [65536];9 double rms;
1011 MPI_Init (&argc , &argv);12 MPI_Comm_rank(MPI_COMM_WORLD , &rank);13 MPI_Comm_size(MPI_COMM_WORLD , &comm_size );1415 if (rank == 0) {16 numpixels = width * height;1718 /* Load the Image */19 for (i=0; i<numpixels; i++) pixels[i] = rand() % 255;2021 /* Calculate the number of pixels in each sub image */22 my_count = numpixels / comm_size;23 }2425 /* Broadcasts my_count to all the processes */26 MPI_Bcast (&my_count , 1, MPI_INT , 0, MPI_COMM_WORLD );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 59 / 82
Обработка изображения (contrast.c, 2)
1 /* Scatter the image */2 MPI_Scatter(pixels , my_count , MPI_UNSIGNED_CHAR , recvbuf ,3 my_count , MPI_UNSIGNED_CHAR , 0, MPI_COMM_WORLD );45 /* Take the sum of the squares of the partial image */6 my_sum = 0;7 for (i=0; i< my_count; i++) {8 my_sum += recvbuf[i] * recvbuf[i];9 }
1011 /* Find the global sum of the squares */12 MPI_Reduce( &my_sum , &sum , 1, MPI_INT , MPI_SUM , 0, MPI_COMM_WORLD );1314 /* rank 0 calculates the root mean square */15 if (rank == 0) {16 rms = sqrt (( double) sum / (double) numpixels );17 printf("RMS = %lf\n", rms);18 }1920 /* Rank 0 broadcasts the RMS to the other nodes */21 MPI_Bcast (&rms , 1, MPI_DOUBLE , 0, MPI_COMM_WORLD );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 60 / 82
Обработка изображения (contrast.c, 3)
1 /* Do the contrast operation */2 for (i=0; i< my_count; i++) {3 val = 2* recvbuf[i] - rms;4 if (val < 0 )5 recvbuf[i] = 0;6 else if (val > 255)7 recvbuf[i] = 255;8 else9 recvbuf[i] = val;
10 }1112 /* Gather back to root */13 MPI_Gather(recvbuf , my_count , MPI_UNSIGNED_CHAR , pixels ,14 my_count , MPI_UNSIGNED_CHAR , 0, MPI_COMM_WORLD );1516 /* Dump the Image (only in process 0) */17 MPI_Finalize ();18 return 0;19 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 61 / 82
Пересылка разнотипных данных
Пользовательские типы данных
Упаковка данных
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 62 / 82
Пользовательские типы данных (mpi_type.c)
1 struct { int a; double b; } value;2 MPI_Datatype mystruct;3 int blocklens [2];4 MPI_Aint indices [2];5 MPI_Datatype old_types [2];6
7 MPI_Init( &argc , &argv );8 MPI_Comm_rank( MPI_COMM_WORLD , &rank );9
10 /* One value of each type */11 blocklens [0] = 1;12 blocklens [1] = 1;13 /* The base types */14 old_types [0] = MPI_INT;15 old_types [1] = MPI_DOUBLE;16 /* The locations of each element */17 MPI_Address( &value.a, &indices [0] );18 MPI_Address( &value.b, &indices [1] );19 /* Make relative */20 indices [1] = indices [1] - indices [0];21 indices [0] = 0;22 MPI_Type_struct( 2, blocklens , indices , old_types , &mystruct );23 MPI_Type_commit( &mystruct );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 63 / 82
Пользовательские типы данных (mpi_type.c, 2)
1 do {2 if (rank == 0)3 scanf( "%d %lf", &value.a, &value.b );4 MPI_Bcast( &value , 1, mystruct , 0, MPI_COMM_WORLD );5 printf( "Process %d got %d and %lf\n", rank ,6 value.a, value.b );7 } while (value.a >= 0);8
9 /* Clean up the type */10 MPI_Type_free( &mystruct );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 64 / 82
Упаковка данных (mpi_pack.c)
1 int rank;2 int packsize , position;3 int a;4 double b;5 char packbuf [100];67 MPI_Init( &argc , &argv );8 MPI_Comm_rank( MPI_COMM_WORLD , &rank );9
10 do {11 if (rank == 0) {12 scanf( "%d %lf", &a, &b );13 packsize = 0;14 MPI_Pack( &a, 1, MPI_INT , packbuf , 100, &packsize , MPI_COMM_WORLD );15 MPI_Pack( &b, 1, MPI_DOUBLE , packbuf , 100, &packsize , MPI_COMM_WORLD );16 }17 MPI_Bcast( &packsize , 1, MPI_INT , 0, MPI_COMM_WORLD );18 MPI_Bcast( packbuf , packsize , MPI_PACKED , 0, MPI_COMM_WORLD );19 if (rank != 0) {20 position = 0;21 MPI_Unpack( packbuf , packsize , &position , &a, 1, MPI_INT , MPI_COMM_WORLD );22 MPI_Unpack( packbuf , packsize , &position , &b, 1, MPI_DOUBLE , MPI_COMM_WORLD );23 }24 printf( "Process %d got %d and %lf\n", rank , a, b );25 } while (a >= 0);2627 MPI_Finalize( );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 65 / 82
Виртуальные топологии
Позволяют задать удобную схему адресации процессов,соответствующую структуре алгоритма
Не связаны с физической топологией сети
Могут использоваться для оптимизации распределения процессовпо процессорам
Поддерживаемые типы топологийДекартова топология (N-мерная решетка)Граф
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 66 / 82
Двумерная решетка 4x4 (topology.c)
1 #include "mpi.h"2 #include <stdio.h>3 #define SIZE 164 #define UP 05 #define DOWN 16 #define LEFT 27 #define RIGHT 389 int main(argc ,argv)
10 int argc;11 char *argv []; {12 int numtasks , rank , source , dest , outbuf , i, tag=1,13 inbuf [4]={ MPI_PROC_NULL ,MPI_PROC_NULL ,MPI_PROC_NULL ,MPI_PROC_NULL ,},14 nbrs[4], dims [2]={4 ,4} ,15 periods [2]={0 ,0} , reorder=0, coords [2];1617 MPI_Request reqs [8];18 MPI_Status stats [8];19 MPI_Comm cartcomm;2021 MPI_Init (&argc ,&argv);22 MPI_Comm_size(MPI_COMM_WORLD , &numtasks );2324 if (numtasks == SIZE) {25 MPI_Cart_create(MPI_COMM_WORLD , 2, dims , periods , reorder , &cartcomm );26 MPI_Comm_rank(cartcomm , &rank);27 MPI_Cart_coords(cartcomm , rank , 2, coords );28 MPI_Cart_shift(cartcomm , 0, 1, &nbrs[UP], &nbrs[DOWN ]);29 MPI_Cart_shift(cartcomm , 1, 1, &nbrs[LEFT], &nbrs[RIGHT ]);
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 67 / 82
Двумерная решетка 4x4 (topology.c, 2)
1 outbuf = rank;23 for (i=0; i<4; i++) {4 dest = nbrs[i];5 source = nbrs[i];6 MPI_Isend (&outbuf , 1, MPI_INT , dest , tag ,7 MPI_COMM_WORLD , &reqs[i]);8 MPI_Irecv (& inbuf[i], 1, MPI_INT , source , tag ,9 MPI_COMM_WORLD , &reqs[i+4]);
10 }1112 MPI_Waitall (8, reqs , stats);1314 printf("rank= %d coords= %d %d neighbors(u,d,l,r)= %d %d %d %d\n",15 rank ,coords [0], coords [1],nbrs[UP],nbrs[DOWN],nbrs[LEFT],16 nbrs[RIGHT ]);17 printf("rank= %d inbuf(u,d,l,r)= %d %d %d %d\n",18 rank ,inbuf[UP],inbuf[DOWN],inbuf[LEFT],inbuf[RIGHT ]);19 }20 else21 printf("Must specify %d processors. Terminating .\n",SIZE);2223 MPI_Finalize ();24 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 68 / 82
Численное решение уравнения Лапласа методом Якоби
1 while (not converged) {2 for (i,j)3 xnew[i][j] = (x[i+1][j] + x[i-1][j] + x[i][j+1] + x[i][j -1])/4;4 for (i,j)5 x[i][j] = xnew[i][j];6 }7 }
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 69 / 82
Алгоритм пульсации
Отправить свои границы соседямПолучить границы от соседейВычислить значения внутри своей полосы
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 70 / 82
jacobi.c (1)
1 /* 12 x 12 mesh , 4 processors */2 #define maxn 123 ...4 /* xlocal [][0] is lower ghostpoints */5 /* xlocal [][ maxn +2] is upper */6 double xlocal [(12/4)+2][12];7 double xnew [(12/3)+2][12];8 double x[maxn][maxn];9
10 MPI_Init( &argc , &argv );11 MPI_Comm_rank( MPI_COMM_WORLD , &rank );12 MPI_Comm_size( MPI_COMM_WORLD , &size );13
14 /* Read the data from the named file */15 if (rank == 0) {16 ...17 MPI_Scatter( x[0], maxn * (maxn/size), MPI_DOUBLE ,18 xlocal [1], maxn * (maxn/size), MPI_DOUBLE ,19 0, MPI_COMM_WORLD );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 71 / 82
jacobi.c (2)
1 itcnt = 0;2 do {3 /* Send up unless I’m at the top , then receive from below */4 if (rank > 0)5 MPI_Send( xlocal [1], maxn , MPI_DOUBLE , rank - 1, 1,6 MPI_COMM_WORLD );7 if (rank < size - 1)8 MPI_Recv( xlocal[maxn/size+1], maxn , MPI_DOUBLE , rank + 1, 1,9 MPI_COMM_WORLD , &status );
10 /* Send down unless I’m at the bottom */11 if (rank < size - 1)12 MPI_Send( xlocal[maxn/size], maxn , MPI_DOUBLE , rank + 1, 0,13 MPI_COMM_WORLD );14 if (rank > 0)15 MPI_Recv( xlocal [0], maxn , MPI_DOUBLE , rank - 1, 0,16 MPI_COMM_WORLD , &status );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 72 / 82
jacobi.c (3)
1 /* Compute new values (but not on boundary) */2 itcnt ++;3 diffnorm = 0.0;4 for (i=i_first; i<= i_last; i++)5 for (j=1; j<maxn -1; j++) {6 xnew[i][j] = (xlocal[i][j+1] + xlocal[i][j-1] +7 xlocal[i+1][j] + xlocal[i-1][j]) / 4.0;8 diffnorm += (xnew[i][j] - xlocal[i][j]) *9 (xnew[i][j] - xlocal[i][j]);
10 }11 /* Only transfer the interior points */12 for (i=i_first; i<= i_last; i++)13 for (j=1; j<maxn -1; j++)14 xlocal[i][j] = xnew[i][j];15 MPI_Allreduce( &diffnorm , &gdiffnorm , 1, MPI_DOUBLE , MPI_SUM ,16 MPI_COMM_WORLD );17 gdiffnorm = sqrt( gdiffnorm );18 if (rank == 0) printf( "At iteration %d, diff is %e\n", itcnt ,19 gdiffnorm );20 } while (gdiffnorm > 1.0e-2 && itcnt < 100);
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 73 / 82
jacobi.c (4)
1 /* Collect the data into x and print it */2 MPI_Gather( xlocal [1], maxn * (maxn/size), MPI_DOUBLE ,3 x, maxn * (maxn/size), MPI_DOUBLE ,4 0, MPI_COMM_WORLD );5 if (rank == 0) {6 printf( "Final solution is\n" );7 ...8 }9 MPI_Finalize( );
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 74 / 82
Оптимизации
Сокращение обменовОбмениваться границами через итерацию
2D-декомпозицияПочему?
Совмещение вычислений и обмена даннымиКак?
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 75 / 82
Влияние декомпозиции
Время передачи n данных между процессами
T = L+n
B
1D
T = 2(L+n
B)
2D
T = 4(L+n√pB
)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 76 / 82
Совмещение вычислений и обмена данными
Обновить края своей полосыПриготовиться к приему краев соседей (MPI_Irecv)Отправить свои края соседям (MPI_Isend)Обновить внутренние клетки своей полосыПринять края от соседей (MPI_Waitall)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 77 / 82
MPI-2
Динамическое создание/уничтожение процессов
Односторонние взаимодействияНе требуют участия обеих сторонЗапись/чтение из памяти удаленного процесса
Коллективные операцииНеблокирующие модификацииВзаимодействие между процессами из разных коммуникаторов
Параллельный ввод/вывод
Интерфейс для C++
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 78 / 82
Средства отладки и анализа MPI-программ
Vampirhttp://vampir.eu/
TAU (Tuning and Analysis Utilities)http://www.cs.uoregon.edu/Research/tau/home.php
KOJAKhttp://icl.cs.utk.edu/kojak/
Paraverhttp://www.bsc.es/computer-sciences/performance-tools/paraver/
Intel R© Trace Analyzer and Collectorhttp://software.intel.com/en-us/articles/intel-trace-analyzer/
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 79 / 82
Нестандартные реализации MPI
C++Альтернативный API Boost.MPI
Pythonmpi4py, pypar, pyMPI, Scientific Python, Boost.MPI Python
JavaСпецификации Java API: mpiJava 1.2, MPJПроекты: mpiJava, MPJ Express, MPJ/Ibis, P2P-MPIБлизкие проекты: Parallel Java, ProActive ...
.NETPure Mpi.NET, MPI.NET
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 80 / 82
Преимущества и недостатки MPI?
Идеален для параллельных алгоритмов с регулярнымивзаимодействиями
Плохо приспособлен для большого количества слабо- илинезависимых задач
Низкоуровневый процедурный стиль программированияНет удобных объектно-ориентированных интерфейсов
Плохо работает на гетерогенных системахНет встроенной балансировки нагрузки
Низкая живучестьНет встроенного восстановления от отказов
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 81 / 82
Преимущества и недостатки MPI?
Идеален для параллельных алгоритмов с регулярнымивзаимодействиями
Плохо приспособлен для большого количества слабо- илинезависимых задач
Низкоуровневый процедурный стиль программированияНет удобных объектно-ориентированных интерфейсов
Плохо работает на гетерогенных системахНет встроенной балансировки нагрузки
Низкая живучестьНет встроенного восстановления от отказов
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 81 / 82
Домашнее задание (ДЗ №2, Задача 2)
Реализуйте параллельную версию игры “Жизнь”1 сиспользованием MPI
Загрузка начальной конфигурации клеток из файла, выполнениезаданного числа шагов эволюции, сохранение полученнойконфигурации в файлВизуализация не требуется
Измерьте время выполнения, ускорение и эффективность дляразличного числа процессоров и размера задачи
Ускорение следует измерять относительно последовательнойпрограммы без MPIВремя работы последовательной программы на тестовом наборедолжно быть не менее 10 секундДля всех запусков с одним размером задачи надо использоватьодинаковый набор данных
Прокомментируйте полученные результаты1http://ru.wikipedia.org/wiki/Жизнь_(игра)
О.В. Сухорослов ()05 Параллельное программирование 23.03.2011 82 / 82