Библиотека MPI
Message Passing Interface
История MPI
Стандарт MPI 1.0 1995 год, MPI 2.0 1998
год. Определяет API (варианты для Си,
C++, Fortran, Java).
«Комплект поставки» MPI
• Библиотека.
• Средства компиляции и запуска
приложения.
SPMD-модель.
0
1
2
3
Разные процессы
выполняют разные части
одного и того же кода.
Сборка MPI-приложения.
Сборка MPI-приложения осуществляется с помощью
специальной утилиты. В случае Си – mpicc. Пример:
mpicc –o mpihello mpihello.c
Запуск MPI-приложения осуществляется с помощью
команды mpirun.
mpirun –np 4 mpihello
Функции инициализации и
завершения работы.
int MPI_Init(int* argc,char*** argv)
argc – указатель на счетчик аргументов командной строки
argv – указатель на список аргументов
int MPI_Finalize()
Тоже простая MPI-программа
#include <mpi.h>
#include <stdio.h>
int main( int argc, char *argv[] )
{
int rank, size;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
printf( "I am %d of %dn", rank, size );
MPI_Finalize();
return 0;
}
Функции определения ранга и
числа процессов.
int MPI_Comm_size (MPI_Comm comm, int* size )
comm - коммуникатор
size – число процессов
int MPI_Comm_rank(MPI_Comm comm, int* rank)
comm – коммуникатор
rank – ранг процесса
Пример простейшей пересылки
#include <stdio.h>
#include <mpi.h>
main(int argc, char* argv[])
{
int rank;
MPI_Status st;
char buf[64];
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank == 0) {
sprintf(buf, "Hello from processor 0");
MPI_Send(buf, 64, MPI_CHAR, 1, 0, MPI_COMM_WORLD);
} else {
MPI_Recv(buf, 64, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &st);
printf("Process %d received %s n", rank, buf);
}
MPI_Finalize();
}
Функции обменов точка-точка
int MPI_Send( buf, count, datatype, dest, tag, comm )
void *buf; /* in */
int count, dest, tag; /* in */
MPI_Datatype datatype; /* in */
MPI_Comm comm; /* in */
buf - адрес начала буфера посылаемых данных
count - число пересылаемых объектов типа, соответствующего datatype
dest - номер процесса-приемника
tag - уникальный тэг, идентифицирующий сообщение
datatype - MPI-тип принимаемых данных
comm - коммуникатор
int MPI_Recv( buf, count, datatype, source, tag, comm, status )
void *buf; /* in */
int count, source, tag; /* in */
MPI_Datatype datatype; /* in */
MPI_Comm comm; /* in */
MPI_Status *status; /* out */
buf - адрес буфера для приема сообщения
count - максимальное число объектов типа datatype, которое
может быть записано в буфер
source - номер процесса, от которого ожидается сообщение
tag - уникальный тэг, идентифицирующий сообщение
datatype - MPI-тип принимаемых данных
comm - коммуникатор
status - статус завершения
MPI-программа численного
интегрирования
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &r);
MPI_Comm_size(MPI_COMM_WORLD, &p);
if(r == 0)
t = MPI_Wtime();
MPI_Barrier(MPI_COMM_WORLD);
sum = 0.0;
h = (b - a) / n;
for(i = r; i < n; i += p)
sum += f(a + (i + 0.5) * h);
sum *= h;
MPI_Send(&sum, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
sum = 0;
MPI-программа численного
интегрирования
if(r == 0) {
double s;
for(i = 0; i < p; i ++) {
MPI_Recv(&s, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &st);
sum += s;
}
t = MPI_Wtime() - t;
printf("Integral value = %lf. Time = %lf sec.n", sum, t);
}
MPI_Finalize();
}
Виды точечных
взаимодействий
MPI_Send блокирующая пересылка
функция возвращает управление тогда, когда
исходный буфер можно освобождать (т.е. данные
или скопированы в промежуточный или
отправлены)
MPI_Bsend буферизованная пересылка
функция возвращает управление тогда, когда
данные скопированы в буфер, выделяемый
пользователем
MPI_Ssend синхронная пересылка
функция возвращает управление тогда, когда
процесс-приемник преступил к выполнению
соответствующей операции приема
MPI_Rsend интерактивная пересылка
поведение функции не определено, если
соответствующая операция приема не начала
выполнения (для увеличения
производительности)
Неблокирующие пересылки
• Предназначены для
перекрытия обменов
и вычислений.
• Операция
расщепляется на две:
инициация и
завершение.
Завершение:
int MPI_Wait (MPI_Request * request, MPI_Status * status)
int MPI_Test(MPI_Request *request, int *flag,
MPI_Status *status)
int MPI_Waitall(int count, MPI_Request array_of_requests[],
MPI_Status array_of_statuses[] )
int MPI_Waitany(int count, MPI_Request array_of_requests[],
int* index, MPI_Status *status )
Коллективные взаимодействия
процессов
int MPI_Bcast ( buffer, count, datatype, root,
comm )
void* buffer - начальный адрес буфера для передачи
собщений
int count - число передаваемых элементов данных
MPI_Datatype datatype - тип передаваемых данных
int root - ранг процесса, посылающего данные
MPI_Comm comm - коммуникатор
int MPI_Reduce ( sendbuf, recvbuf, count,
datatype, op, root, comm )
void *sendbuf; буфер операндов
void *recvbuf; буфер приема
int count; число данных
MPI_Datatype datatype; тип данных
MPI_Op op; операция
int root; ранг процесса, содержащего результат
MPI_Comm comm; коммуникатор
op
MPI_MAX максимум
MPI_MIN минимум
MPI_SUM сумма
MPI_PROD произведение
MPI_LAND логическое "и"
MPI_BAND побитовое "и"
MPI_LOR логическое "или"
MPI_BOR побитовое "или"
MPI_LXOR логическое исключающее "или"
MPI_BXOR побитовое исключающее "или"
Вычисление числа Pi
#include "mpi.h"
#include <math.h>
int main(argc,argv)
int argc;
char *argv[];
{
int n, myid, numprocs, i;
double PI25DT = 3.141592653589793238462643;
double mypi, pi, h, sum, x, a;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
while (1)
{
if (myid == 0) {
printf("Enter the number of intervals: (0 quits) ");
scanf("%d",&n);
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (n == 0) break;
h = 1.0 / (double) n;
sum = 0.0;
for (i = myid + 1; i <= n; i += numprocs) {
x = h * ((double)i - 0.5);
sum += 4.0 / (1.0 + x*x);
}
mypi = h * sum;
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0,
MPI_COMM_WORLD);
if (myid == 0)
printf("pi is approximately %.16f, Error is %.16fn",
pi, fabs(pi - PI25DT));
}
MPI_Finalize();
Интер- и интра-
коммуникаторы
Интра-
коммуникаторы
Интер-
коммуникатор
Интра-коммуникаторы
объединяют процессы
из одной группы.
Интер-коммуникатор
позволяет передавать
данные между процессами из
разных интра-коммуникаторов.
Интер-коммуникаторы
не могут использоваться в
коллективных взаимодействиях.
01
2
3
4
1
0
3
2
1
1
Назначение коммуникаторов
• Поддержка параллельных библиотек.
• Поддержка коллективных операций на
части вычислительного пространства.
• Повышение уровня абстракции
параллельных приложений.
Информационные функции для
работы с группами
Определение размера группы:
int MPI_Group_size(MPI_Group group, int *size)
group – группа;
size – указатель на область памяти для записи информации о
количестве процессов в группе;
Определение номера процесса, выполняющего вызов функции, в
группе:
int MPI_Group_rank(MPI_Group group, int *rank)
group – группа;
rank – указатель на область памяти для сохранения номера
процесса;
Разность двух групп:
int MPI_Group_difference(MPI_Group gr1, MPI_Group
g2, MPI_Group* gr3)
gr1 – первая группа;
gr2 – вторая группа;
gr3 – указатель на область для сохранения
результата операции;
Группа gr3 составлена из процессов, входящих в gr1,
но не входящих в gr2, расположенных в том же
порядке, что и в gr1.
Переупорядочивание (с возможным удалением) процессов
в существующей группе:
int MPI_Group_incl(MPI_Group* group, int n, int*
ranks, MPI_Group* newgroup)
group – исходная группа;
n – число элементов в массиве ranks;
ranks – массив номеров процессов, из которых
будет создана новая группа;
newgroup – указатель на область для сохранения
результата операции;
Созданная группа newgroup содержит элементы группы
group, перечисленные в массиве ranks: i-й процесс
создаваемой группы newgroup совпадает с процессом,
имеющим номер ranks[i] в группе group.
Система типов сообщений MPI
Типы в MPI
БАЗОВЫЕ ТИПЫ
MPI_CHAR
MPI_SHORT
MPI_INT
MPI_LONG
MPI_UNSIGNED_CHAR
MPI_UNSIGNED_SHORT
MPI_UNSIGNED
MPI_UNSIGNED_LONG
MPI_FLOAT
MPI_DOUBLE
MPI_LONG_DOUBLE
ПРОИЗВОДНЫЕ ТИПЫ
MPI_TYPE_CONTIGUOUS
MPI_TYPE_VECTOR
MPI_TYPE_HVECTOR
MPI_TYPE_INDEXED
MPI_TYPE_HINDEXED
MPI_TYPE_STRUCT
MPI_PACKED
БАЗОВЫЕ ТИПЫ
тип MPI тип Си
MPI_CHAR signed char
MPI_SHORT signed short int
MPI_INT signed int
MPI_LONG signed long int
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED_SHORT unsigned short
MPI_UNSIGNED unsigned int
MPI_UNSIGNED_LONG unsigned long int
MPI_FLOAT float
MPI_DOUBLE double
MPI_LONG_DOUBLE long double
Назначение производных
типов
• пересылка данных, расположенных в
несмежных областях памяти в одном
сообщении;
• пересылка разнотипных данных в одном
сообщении;
• облегчение понимания программы;
ХАРАКТЕРНЫЕ ОШИБКИ В
MPI-ПРОГРАММАХ
ВИДЫ ОШИБОК
• Ошибки последовательных программ.
• Ошибки несоответствия типов.
• Ошибки работы с MPI-объектами.
• Взаимные блокировки.
• Недетерминизм.
Недетерминизм за счет разницы в
относительных скоростях процессов (race
condition)
Deadlock
if(rank == 0) {
MPI_Ssend(… 1 …)
MPI_Recv(…1…)
} else {
MPI_Ssend(… 0 …)
MPI_Recv(…0…)
}
«Недетерминированный»
deadlock
if(rank == 0) {
MPI_Send(… 1 …)
MPI_Recv(…1…)
} else {
MPI_Send(… 0 …)
MPI_Recv(…0…)
}
20140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture10

20140420 parallel programming_kalishenko_lecture10

  • 1.
  • 2.
    История MPI Стандарт MPI1.0 1995 год, MPI 2.0 1998 год. Определяет API (варианты для Си, C++, Fortran, Java).
  • 3.
    «Комплект поставки» MPI •Библиотека. • Средства компиляции и запуска приложения.
  • 4.
  • 5.
    Сборка MPI-приложения. Сборка MPI-приложенияосуществляется с помощью специальной утилиты. В случае Си – mpicc. Пример: mpicc –o mpihello mpihello.c Запуск MPI-приложения осуществляется с помощью команды mpirun. mpirun –np 4 mpihello
  • 6.
    Функции инициализации и завершенияработы. int MPI_Init(int* argc,char*** argv) argc – указатель на счетчик аргументов командной строки argv – указатель на список аргументов int MPI_Finalize()
  • 7.
    Тоже простая MPI-программа #include<mpi.h> #include <stdio.h> int main( int argc, char *argv[] ) { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); printf( "I am %d of %dn", rank, size ); MPI_Finalize(); return 0; }
  • 8.
    Функции определения рангаи числа процессов. int MPI_Comm_size (MPI_Comm comm, int* size ) comm - коммуникатор size – число процессов int MPI_Comm_rank(MPI_Comm comm, int* rank) comm – коммуникатор rank – ранг процесса
  • 9.
    Пример простейшей пересылки #include<stdio.h> #include <mpi.h> main(int argc, char* argv[]) { int rank; MPI_Status st; char buf[64]; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if(rank == 0) { sprintf(buf, "Hello from processor 0"); MPI_Send(buf, 64, MPI_CHAR, 1, 0, MPI_COMM_WORLD); } else { MPI_Recv(buf, 64, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &st); printf("Process %d received %s n", rank, buf); } MPI_Finalize(); }
  • 10.
    Функции обменов точка-точка intMPI_Send( buf, count, datatype, dest, tag, comm ) void *buf; /* in */ int count, dest, tag; /* in */ MPI_Datatype datatype; /* in */ MPI_Comm comm; /* in */ buf - адрес начала буфера посылаемых данных count - число пересылаемых объектов типа, соответствующего datatype dest - номер процесса-приемника tag - уникальный тэг, идентифицирующий сообщение datatype - MPI-тип принимаемых данных comm - коммуникатор
  • 11.
    int MPI_Recv( buf,count, datatype, source, tag, comm, status ) void *buf; /* in */ int count, source, tag; /* in */ MPI_Datatype datatype; /* in */ MPI_Comm comm; /* in */ MPI_Status *status; /* out */ buf - адрес буфера для приема сообщения count - максимальное число объектов типа datatype, которое может быть записано в буфер source - номер процесса, от которого ожидается сообщение tag - уникальный тэг, идентифицирующий сообщение datatype - MPI-тип принимаемых данных comm - коммуникатор status - статус завершения
  • 12.
    MPI-программа численного интегрирования MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD,&r); MPI_Comm_size(MPI_COMM_WORLD, &p); if(r == 0) t = MPI_Wtime(); MPI_Barrier(MPI_COMM_WORLD); sum = 0.0; h = (b - a) / n; for(i = r; i < n; i += p) sum += f(a + (i + 0.5) * h); sum *= h; MPI_Send(&sum, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); sum = 0;
  • 13.
    MPI-программа численного интегрирования if(r ==0) { double s; for(i = 0; i < p; i ++) { MPI_Recv(&s, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &st); sum += s; } t = MPI_Wtime() - t; printf("Integral value = %lf. Time = %lf sec.n", sum, t); } MPI_Finalize(); }
  • 14.
    Виды точечных взаимодействий MPI_Send блокирующаяпересылка функция возвращает управление тогда, когда исходный буфер можно освобождать (т.е. данные или скопированы в промежуточный или отправлены) MPI_Bsend буферизованная пересылка функция возвращает управление тогда, когда данные скопированы в буфер, выделяемый пользователем
  • 15.
    MPI_Ssend синхронная пересылка функциявозвращает управление тогда, когда процесс-приемник преступил к выполнению соответствующей операции приема MPI_Rsend интерактивная пересылка поведение функции не определено, если соответствующая операция приема не начала выполнения (для увеличения производительности)
  • 16.
    Неблокирующие пересылки • Предназначеныдля перекрытия обменов и вычислений. • Операция расщепляется на две: инициация и завершение.
  • 17.
    Завершение: int MPI_Wait (MPI_Request* request, MPI_Status * status) int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) int MPI_Waitall(int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[] ) int MPI_Waitany(int count, MPI_Request array_of_requests[], int* index, MPI_Status *status )
  • 18.
  • 19.
    int MPI_Bcast (buffer, count, datatype, root, comm ) void* buffer - начальный адрес буфера для передачи собщений int count - число передаваемых элементов данных MPI_Datatype datatype - тип передаваемых данных int root - ранг процесса, посылающего данные MPI_Comm comm - коммуникатор
  • 20.
    int MPI_Reduce (sendbuf, recvbuf, count, datatype, op, root, comm ) void *sendbuf; буфер операндов void *recvbuf; буфер приема int count; число данных MPI_Datatype datatype; тип данных MPI_Op op; операция int root; ранг процесса, содержащего результат MPI_Comm comm; коммуникатор op
  • 21.
    MPI_MAX максимум MPI_MIN минимум MPI_SUMсумма MPI_PROD произведение MPI_LAND логическое "и" MPI_BAND побитовое "и" MPI_LOR логическое "или" MPI_BOR побитовое "или" MPI_LXOR логическое исключающее "или" MPI_BXOR побитовое исключающее "или"
  • 22.
    Вычисление числа Pi #include"mpi.h" #include <math.h> int main(argc,argv) int argc; char *argv[]; { int n, myid, numprocs, i; double PI25DT = 3.141592653589793238462643; double mypi, pi, h, sum, x, a; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid);
  • 23.
    while (1) { if (myid== 0) { printf("Enter the number of intervals: (0 quits) "); scanf("%d",&n); } MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (n == 0) break; h = 1.0 / (double) n; sum = 0.0; for (i = myid + 1; i <= n; i += numprocs) { x = h * ((double)i - 0.5); sum += 4.0 / (1.0 + x*x); } mypi = h * sum; MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (myid == 0) printf("pi is approximately %.16f, Error is %.16fn", pi, fabs(pi - PI25DT)); } MPI_Finalize();
  • 24.
    Интер- и интра- коммуникаторы Интра- коммуникаторы Интер- коммуникатор Интра-коммуникаторы объединяютпроцессы из одной группы. Интер-коммуникатор позволяет передавать данные между процессами из разных интра-коммуникаторов. Интер-коммуникаторы не могут использоваться в коллективных взаимодействиях. 01 2 3 4 1 0 3 2 1 1
  • 25.
    Назначение коммуникаторов • Поддержкапараллельных библиотек. • Поддержка коллективных операций на части вычислительного пространства. • Повышение уровня абстракции параллельных приложений.
  • 26.
    Информационные функции для работыс группами Определение размера группы: int MPI_Group_size(MPI_Group group, int *size) group – группа; size – указатель на область памяти для записи информации о количестве процессов в группе; Определение номера процесса, выполняющего вызов функции, в группе: int MPI_Group_rank(MPI_Group group, int *rank) group – группа; rank – указатель на область памяти для сохранения номера процесса;
  • 27.
    Разность двух групп: intMPI_Group_difference(MPI_Group gr1, MPI_Group g2, MPI_Group* gr3) gr1 – первая группа; gr2 – вторая группа; gr3 – указатель на область для сохранения результата операции; Группа gr3 составлена из процессов, входящих в gr1, но не входящих в gr2, расположенных в том же порядке, что и в gr1.
  • 28.
    Переупорядочивание (с возможнымудалением) процессов в существующей группе: int MPI_Group_incl(MPI_Group* group, int n, int* ranks, MPI_Group* newgroup) group – исходная группа; n – число элементов в массиве ranks; ranks – массив номеров процессов, из которых будет создана новая группа; newgroup – указатель на область для сохранения результата операции; Созданная группа newgroup содержит элементы группы group, перечисленные в массиве ranks: i-й процесс создаваемой группы newgroup совпадает с процессом, имеющим номер ranks[i] в группе group.
  • 29.
  • 30.
    Типы в MPI БАЗОВЫЕТИПЫ MPI_CHAR MPI_SHORT MPI_INT MPI_LONG MPI_UNSIGNED_CHAR MPI_UNSIGNED_SHORT MPI_UNSIGNED MPI_UNSIGNED_LONG MPI_FLOAT MPI_DOUBLE MPI_LONG_DOUBLE ПРОИЗВОДНЫЕ ТИПЫ MPI_TYPE_CONTIGUOUS MPI_TYPE_VECTOR MPI_TYPE_HVECTOR MPI_TYPE_INDEXED MPI_TYPE_HINDEXED MPI_TYPE_STRUCT MPI_PACKED
  • 31.
    БАЗОВЫЕ ТИПЫ тип MPIтип Си MPI_CHAR signed char MPI_SHORT signed short int MPI_INT signed int MPI_LONG signed long int MPI_UNSIGNED_CHAR unsigned char MPI_UNSIGNED_SHORT unsigned short MPI_UNSIGNED unsigned int MPI_UNSIGNED_LONG unsigned long int MPI_FLOAT float MPI_DOUBLE double MPI_LONG_DOUBLE long double
  • 32.
    Назначение производных типов • пересылкаданных, расположенных в несмежных областях памяти в одном сообщении; • пересылка разнотипных данных в одном сообщении; • облегчение понимания программы;
  • 33.
  • 34.
    ВИДЫ ОШИБОК • Ошибкипоследовательных программ. • Ошибки несоответствия типов. • Ошибки работы с MPI-объектами. • Взаимные блокировки. • Недетерминизм.
  • 35.
    Недетерминизм за счетразницы в относительных скоростях процессов (race condition)
  • 36.
    Deadlock if(rank == 0){ MPI_Ssend(… 1 …) MPI_Recv(…1…) } else { MPI_Ssend(… 0 …) MPI_Recv(…0…) }
  • 37.
    «Недетерминированный» deadlock if(rank == 0){ MPI_Send(… 1 …) MPI_Recv(…1…) } else { MPI_Send(… 0 …) MPI_Recv(…0…) }