Пособие по MPI (реферат) (2)
Описание файла
Документ из архива "Пособие по MPI (реферат) (2)", который расположен в категории "". Всё это находится в предмете "параллельные системы и параллельные вычисления" из 9 семестр (1 семестр магистратуры), которые можно найти в файловом архиве НИУ «МЭИ» . Не смотря на прямую связь этого архива с НИУ «МЭИ» , его также можно найти и в других разделах. Архив можно найти в разделе "остальное", в предмете "параллельные системы и параллельные вычисления" в общих файлах.
Онлайн просмотр документа "Пособие по MPI (реферат) (2)"
Текст из документа "Пособие по MPI (реферат) (2)"
Реферат на тему «Пособие по MPI »
Подготовил Абрамов Андрей А-05-03
26 ноября 2007 г.
-
MPI_Init(), MPI_Finalize().
Функция MPI_Init() инициализирует параллельные вычисления. В качестве входных параметров используются &argc, &argv из функции main.
MPI_Finalize() завершает выполнение программы MPI.
int MPI_Initialized(int nFlag) показывает, была ли выполнена функция MPI_Init: если nFlag не нуль, то была, иначе – нет.
Далее идет текст программы, иллюстрирующий работу этих функций.
int _tmain(int argc, _TCHAR* argv[])
{
int nRank = 0;
int nInitialized = 0;
int nRes = 0;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &nRank);
printf(" Hello, this is proces number %d\n", nRank);
nRes = MPI_Initialized(&nInitialized);
if(nRes)
{
printf(" MPI_Initialized returned error \n");
}
else
{
if(nInitialized)
{
printf(" MPI was initialized\n");
}
else
{
printf(" MPI was not initialized is \n");
}
}
MPI_Finalize();
return 0;
}
Результат работы данной программы на 3-х процессах:
Hello, this is proces number 1
MPI was initialized
Hello, this is proces number 2
MPI was initialized
Hello, this is proces number 0
MPI was initialized
-
Пример на взаимную блокировку MPI_Send/MPI_Recv.
Функция MPI_Send().
int nError MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
-
buf - начало буфера, содержащего данные, которые будут отосланы. Для C это - адрес.
-
count - число элементов, которые будут отосланы (не байт)
-
datatype - тип данных
-
dest - ранг процесса, места назначения, для сообщения
-
tag - произвольное число, которое можно использовать для отличия от других сообщений
-
comm - (определенный) коммуникатор
-
(nError - возвращаемый функцией код ошибки).
Функция MPI_Send является блокирующей, т.е. управление не вернется программе, пока функция не завершится.
Функция MPI_Recv().
int nError MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
Параметры:
-
buf - начало буфера, в котором входящие данные должны быть запомнены. Для C это - адрес.
-
count - число элементов (не байт) в вашем буфере получателя
-
datatype - тип данных
-
source - ранг процесса, от которого данные будут приняты
(Он может быть любым при задании параметром MPI_ANY_SOURCE) -
tag - произвольное число, которое можно использовать для отличия от других сообщений
(оно может быть любым при задании параметром MPI_ANY_TAG) -
comm - (определенный) коммуникатор
-
status - массив или структура возвращаемой информации.
-
(nError - возвращаемый функцией код ошибки).
Пример взаимной блокировки этих двух функций:
Д опустим, у нас есть несколько процессов, которые взаимодействуют следующим образом:
Каждый процесс содержит следующий код:
for(i=0; i { MPI_Send(…); } for(i=0; i { MPI_Recv (…); } Если запустить эти процессы, мы получим дедлок(тупик), поскольку оба процесса зайдут в функцию MPI_Send() и будут ждать ее завершения. А для ее завершения необходимо выполнение функции MPI_Recv, которая никогда не выполнится. Следующий способ позволяет избежать дедлока: Поменяем местами циклы в процессах 2 и 4 (процессы будут располагаться в шахматном порядке): for(i=0; i { MPI_Recv (…); } for(i=0; i { MPI_Send(…); } Таким образом, они будут сначала принимать данные, а потом передавать. В то же время процессы 1,2 будут действовать наоборот. В этом случае дедлока не возникнет. 3) Использование функций MPI_Wait(), MPI_Test(), MPI_Probe(). Функция MPI_Wait – функция ожидания завершения неблокирующей операции. Int nError MPI_Wait(MPI_Request *request, MPI_Status *status) nError – возвращаемый функцией код ошибки. status – информация о завершенной операции. Request – запрос обмена. Это блокирующая операция. Возврат происходит после завершения операции, связанной с запросом request. В параметре status возвращается информация о законченной операции. MPI_Test - функция проверки завершения неблокирующей операции. Int nError MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) nError – возвращаемый функцией код ошибки. status – атрибуты сообщения, если операция завершилась. Request – запрос обмена. Flag – признак завершенности проверяемой операции. Это неблокирующая операция. Если связанная с запросом request операция завершена, возвращается flag = true, а status содержит информацию о завершенной операции. Если проверяемая операция не завершена, возвращается flag = false, а значение status в этом случае не определено. int nError MPI_Probe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status) source - ранг процесса, от которого данные будут приняты tag - произвольное число, которое можно использовать для отличия от других сообщений comm - (определенный) коммуникатор status - массив или структура возвращаемой информации. flag – удовлетворяет ли сообщение всем требованиям nError - возвращаемый функцией код ошибки. Операция MPI_PROBE позволяет проверить входные сообщения без их реального приема. Пользователь затем может решить, как ему принимать эти сообщения, основываясь на информации, возвращенной при пробе (преимущественно, на информации, возвращенной аргументом status). В частности, пользователь может выделить память для приемного буфера по величине опробованного сообщения. Функция возвращает flag = true, если имеется сообщение, которое может быть получено и которое соответствует образцу, описанному аргументами source, tag, и comm. Пример программы, которая использует перечисленные функции. Все процессы, номера которых кратны 2-м рассылают целочисленный буфер процессу с номером на 1 большим, чем у них. Затем проверяем, завершилась ли передача и выводим сообщение. На принимающей стороне проверяем, соответствует ли сообщение заданным параметрам, после этого принимаем. Причем, используем блокирующую операцию MPI_Wait для того, чтобы узнать, что прием закончен и тогда выводим на экран принятые значения с помощью функции mesParam: // second_test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "mpi.h" void mesParam(MPI_Status aStatus) { printf("Message parameters: \n"); if(aStatus.cancelled) { printf("Cancelled \n"); } else { printf("Not cancelled \n"); } printf("Error: %d\n", aStatus.MPI_ERROR); printf("Parameters count: %d\n", aStatus.count); printf("Source: %d\n", aStatus.MPI_SOURCE); printf("Tag: \n", aStatus.MPI_TAG); } int _tmain(int argc, _TCHAR* argv[]) { int nRank = 0; int nSize = 0; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &nRank); MPI_Comm_size(MPI_COMM_WORLD, &nSize); if(nSize % 2 == 0) { if(nRank % 2 == 0) { int nBuf = 100; int nRes = 0; int nTestRes = 0; int nFlag = 0; MPI_Request request = MPI_REQUEST_NULL; MPI_Status* status = MPI_STATUS_IGNORE; // Асинхронная передача nRes = MPI_Isend(&nBuf, 1, MPI_INT, nRank + 1, nRank, MPI_COMM_WORLD, &request); if(nRes) { printf("MPI_Isend returned error %d\n", nRes); } //----------------------------------------MPI_Test----------------------------------------- // Проверим, что передача завершилась nTestRes = MPI_Test(&request, &nFlag, status); if(nTestRes) { printf("MPI_Test returned error %d\n", nTestRes); } else { if(nFlag) { printf("MPI_Isend completed \n"); // Если nFlag==true выведем все параметры сообщения mesParam(*status); } } } else { int nRes = 0; int nBuf = 0; int nFlag = 1; int nProbeRes = 0; MPI_Request request; MPI_Status status; status.cancelled = 0; status.count = 1; status.MPI_ERROR = 0; status.MPI_SOURCE = nRank; status.MPI_TAG = nRank; //----------------------------------------MPI_Probe---------------------------------------- // Проверим, что сообщение удовлетворяет нашим требованиям nProbeRes = MPI_Probe(nRank - 1, nRank - 1, MPI_COMM_WORLD, &nFlag, &status); if(nProbeRes) { printf("MPI_Probe returned error %d\n", nProbeRes); } else { if(nFlag) { int nWaitResult = 0; printf("Message matches requirements \n"); // Асинхронный прием nRes = MPI_Irecv(&nBuf, 1, MPI_INT, nRank - 1, nRank - 1, MPI_COMM_WORLD, &request); if(nRes) { printf("MPI_Irecv returned error %d\n", nRes); } //----------------------------------------MPI_Wait------------------------------------- // Если удовлетворяет, подождем пока закончиться прием данных nWaitResult = MPI_Wait(&request, &status); if(nWaitResult) { printf("MPI_Wait returned error %d\n", nWaitResult); } else { // Если прием нормально завершился, выведем параметры сообщения на экран mesParam(status); } } } } } MPI_Finalize(); return 0; } Результат работы программы для 2-х процессов: Message matches requirements Message parameters: Not cancelled Error: 0 Parameters count: 4 Source: 0 Tag: 0 Функции MPI_Gather, MPI_Scatter Функция MPI_Gather(). При выполнении этой функции все процессы рассылают данные корневому процессу (включая сам корневой). int nError MPI_Gather(void* sendbuf, int sendcount, sendbuf начальный адрес буфера процесса-отправителя sendcount количество элементов в отсылаемом сообщении (целое) sendtype тип элементов в отсылаемом сообщении recvbuf начальный адрес буфера процесса сборки данных (существенно только для корневого процесса) recvcount количество элементов в принимаемом сообщении (целое, имеет значение только для корневого процесса) recvtype тип данных элементов в буфере процесса-получателя root номер процесса-получателя (целое) comm коммуникатор root – номер корневого процесса nError – возвращаемое значение ошибки. Пример на функцию MPI_Gather(). Все процессы создают переменную типа int и передают ее корневому (нулевому), который сохраняет их в массив, затем выводит на экран: int _tmain(int argc, _TCHAR* argv[]) { int nError = 0; int nSize = 0; int nRank = 0; int* pReadBuf = NULL; int i=0; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nSize); MPI_Comm_rank(MPI_COMM_WORLD, &nRank); if(nRank == 0) { pReadBuf = (int *)malloc(nSize*sizeof(int)); } nError = MPI_Gather(&nRank, 1, MPI_INT, pReadBuf, 1, MPI_INT, 0, MPI_COMM_WORLD); if(nRank == 0) { printf("Принятые элементы массива: \n"); for(i=0; i { printf("%d\n", pReadBuf[i]); } } MPI_Finalize(); return 0; } Результат работы функции для 4-х процессов: Принятые элементы массива: 0 1 2 3 Функция MPI_Scatter(). Эта операция обратна MPI_Gather(), т.е. корневой процесс рассылает данные всем остальным. int MPI_Scatter(void* sendbuf, int sendcount, MPI_Datatype sendtype, sendbuf - начальный адрес буфера процесса-отправителя(используется только корневым процессом) sendcount количество элементов в отсылаемом сообщении (целое, используется только корневым процессом) sendtype тип элементов в отсылаемом сообщении(используется только корневым процессом) recvbuf начальный адрес буфера процесса сборки данных recvcount количество элементов в принимаемом сообщении recvcount - количество элементов recvtype тип данных элементов в буфере процесса-получателя root номер процесса-получателя (целое) root – номер процесса-получателя comm коммуникатор nError – возвращаемое значение ошибки. Пример использования. Функция создает массив, количество элементов которого равно количеству процессов, затем заполняет массив идущими подряд числами и рассылает их всем процессам: int _tmain(int argc, _TCHAR* argv[]) { int nRank = 0; int nResult = 0; int* pSendBuf = NULL; int nRecvBuf = 0; int nSize = 0; int i = 0; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &nRank); MPI_Comm_size(MPI_COMM_WORLD, &nSize); pSendBuf = (int *)malloc(nSize*sizeof(int)); for(i = 0; i { pSendBuf[i] = i; } nResult = MPI_Scatter(pSendBuf, 1, MPI_INT, &nRecvBuf, 1, MPI_INT, 0, MPI_COMM_WORLD); if(nResult) { printf("MPI_Scatter returned error - %d", nResult); } else { printf("Process rank - %d", nRank); printf(" nRecvBuf = %d\n", nRecvBuf); } MPI_Finalize(); return 0; } Результат работы функции для 4- процессов: Process rank - 2 nRecvBuf = 2 Process rank - 3 nRecvBuf = 3 Process rank - 0 nRecvBuf = 0 Process rank - 1 nRecvBuf = 1 Функции MPI_Reduce MPI_AllReduce Функция MPI_Reduce int nError MPI_Reduce(void* operand, void* result, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) operand- операнды функции result- результат, который сохраняется в корневом процессе count-количество ячеек в памяти, на которые ссылаются и операнд и результат datatype – тип данных op – оператор, с помощью которого производятся вычисления root- номер корневого процесса, в котором сохраняются результаты comm. – коммуникатор. MPI_Reduce() объединяет операнды, сохраненные в *operand, используя оператор op и сохраняет результат в переменной *result корневого процесса root. И операнд, и результат ссылаются на count ячеек памяти с типом datatype. MPI_Reduce() должны вызывать все процессы в коммуникаторе comm. При вызове значения count, datatype и op должны быть одинаковыми в каждом процессе. Пример использования. Функция суммирует ранги всех процессов и сохраняет их в нулевом: int _tmain(int argc, _TCHAR* argv[]) { int nSize = 0; int nRank = 0; int nResult = 0; int nError = 0; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nSize); MPI_Comm_rank(MPI_COMM_WORLD, &nRank); nError = MPI_Reduce(&nRank, &nResult, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); if(nError) { printf("MPI_Reduce returned Error %d\n", nError); } else { if(!nRank) { printf("Result is %d\n", nResult); } } MPI_Finalize(); return 0; } Результат работы функции. Вывод полученного значения суммы номеров всех процессов(для 4-х процессов): Result is 6 Функция MPI_AllReduce() отличается только тем, что сохраняет данные во всех процессах, поэтому в ней не указывается корневой процесс. Список параметров аналогичен предыдущей функции. int MPI_Allreduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
MPI_Datatype sendtype, void* recvbuf, int recvcount,
MPI_Datatype recvtype, int root, MPI_Comm comm);
void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)