Практические основы параллельного программирования. Посыпкин Михаил Анатольевич www.ispras.ru/~posypkin Параллельное программирование Приложения требуют увеличения производительности компьютеров. Производительность процессора и памяти ограничена физическими характеристиками применяемых материалов. Многие задачи содержат независимые компоненты, которые могут решаться одновременно (т.е. параллельно). Параллельное программирование Перечисленное приводит к естественному решению – увеличивать число компонент оборудования, участвующего в решении задач. В частности, увеличивается число функциональных устройств одного процессора и общее число процессоров. Многопроцессорный параллелизм В решении задачи принимает участие несколько (более одного) процессоров, взаимодействующих между собой. CPU CPU CPU CPU Спектр задач параллельного программирования Математическое моделирование: Оптимизация: Газовая и гидро-динамика. Химические реакции. Процессы в полупроводниках. Дискретное и линейное программирование. Общая задача нахождения экстремума. Оптимальный поиск: Дискретная оптимизация. Распознавание образов. Автоматическая верификация и доказательство теорем. Виды параллелизма. Общая память Распределенная память Аппаратные ресурсы МСЦ Общая память: HP V-Class HP Superdome Гибридная память: MVS-1000M (768 x Alpha 21264) MVS 15000BM (768 x IBM Power 970) кластеры Athlon, Xeon, IBM Средства параллельного программирования Общая память Распределенная память Системные средства Языки threads C/C++, Fortran 95 Специальные OpenMP библиотеки и пакеты sockets HPF, DVM, mpC, Charm ++, Occam MPI PVM Библиотека MPI Message Passing Interface Структура MPI API (варианты для Си, C++, Fortran, Java). Средства компиляции и запуска приложения. SPMD-модель. 1 2 3 4 Разные процессы выполняют разные части одного и того же кода. Сборка MPI-приложения. Сборка MPI-приложения осуществляется с помощью специальной утилиты. В случае Си – mpicc. Пример: mpicc –o mpihello mpihello.c Запуск MPI-приложения осуществляется с помощью команды mpirun. mpirun –np 4 mpihello Простейшая 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 %d\n", rank, size ); MPI_Finalize(); return 0; } Функции инициализации и завершения работы. int MPI_Init(int* argc,char*** argv) argc – указатель на счетчик аргументов командной строки argv – указатель на список аргументов int MPI_Finalize() Функции определения ранга и числа процессов. int MPI_Comm_size (MPI_Comm comm, int* size ) comm - коммуникатор size – число процессов int MPI_Comm_rank(MPI_Comm comm, int* rank) comm – коммуникатор rank – ранг процесса Простейшая пересылка. #include <mpi.h> #include <stdio.h> #define M 3 #define VAL 5 #define ID 1 static int size, rank; void initArray(int* a, int m, int v) { int i; for(i = 0; i < m; i ++) a[i] = v; } void printArray(int* a, int m) { int i; printf("[ "); for(i = 0; i < m; i ++) printf("%d ", a[i]); printf("]\n"); } int main( int argc, char **argv ) { int dta[M]; MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); if( size != 2 ) { if( rank == 0 ) { printf("Error: 2 processes required\n"); fflush(stdout); } MPI_Abort(MPI_COMM_WORLD, MPI_ERR_OTHER ); } if( rank == 0 ){ initArray(dta, M, VAL); MPI_Send(dta, M, MPI_INT, 1, ID, MPI_COMM_WORLD ); printArray(dta, M); fflush(stdout); } else { MPI_Recv(dta, M, MPI_INT, 0, ID, MPI_COMM_WORLD, &status ); printArray(dta, M); fflush(stdout); } } MPI_Finalize(); return 0; Функции обменов точкаточка int MPI_Send( buf, count, datatype, dest, tag, comm ) void *buf; int count, dest, tag; MPI_Datatype datatype; MPI_Comm comm; /* in */ /* in */ /* in */ /* in */ buf - адрес начала буфера посылаемых данных count - число пересылаемых объектов типа, соответствующего datatype dest - номер процесса-приемника tag - уникальный тэг, идентифицирующий сообщение datatype - MPI-тип принимаемых данных comm - коммуникатор int MPI_Recv( buf, count, datatype, source, tag, comm, status ) void *buf; int count, source, tag; MPI_Datatype datatype; MPI_Comm comm; MPI_Status *status; /* /* /* /* /* in */ in */ in */ in */ out */ buf - адрес буфера для приема сообщения count - максимальное число объектов типа datatype, которое может быть записано в буфер source - номер процесса, от которого ожидается сообщение tag - уникальный тэг, идентифицирующий сообщение datatype - MPI-тип принимаемых данных comm - коммуникатор status - статус завершения typedef struct { int count; int MPI_SOURCE; int MPI_TAG; int MPI_ERROR; } MPI_Status; count - число полученных элементов MPI_SOURCE - ранг процесса-передатчика данных MPI_TAG - тэг сообщения MPI_ERROR - код ошибки