20090721 hpc exercise2

56
Реализация параллельного алгоритма с использованием MPI

Upload: michael-karpov

Post on 11-May-2015

815 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: 20090721 hpc exercise2

Реализация параллельного алгоритма с использованием MPI

Page 2: 20090721 hpc exercise2

Содержание

• Основы MPI• Настройка проекта Visual Studio 2008 • Основные функции MPI• Блокирующие функции обмена

сообщениями. Типы данных• Выполнение упражнения

Page 3: 20090721 hpc exercise2

Стандарт MPI

Page 4: 20090721 hpc exercise2

Стандарт MPI

Что включено в стандарт MPI?

– Парные обмены (point-to-point communications)– Коллективные операции (collective operations)– Операции над группами процессов (process groups)– Операции над коммуникационными контекстами

(communication contexts)– Топологии процессов (process topologies)– Привязки к языкам C и Fortran 77 (language binding)

Page 5: 20090721 hpc exercise2

Термины MPI

Page 6: 20090721 hpc exercise2

Термины MPI

Локальная операция – процедура, не требующая взаимодействия с другими процессами.

Нелокальная операция – процедура, выполнение которой может потребовать выполнения действий на других процессах. Такая процедура МОЖЕТ потребовать взаимодействия с другими процессами.

Коллективная операция – процедура, которая должная быть выполнена всеми процессами группы.

Page 7: 20090721 hpc exercise2

Термины MPI

Блокирующая операция – подразумевает выход из нее только после полного окончания операции, т.е. вызывающий процесс блокируется, пока операция не будет завершена

Неблокирующая операция - подразумевает совмещение операций обмена с другими операциями.Как правило, ее выполнение происходит в параллельном потоке и не вызывающий процесс не блокируется.

Page 8: 20090721 hpc exercise2

Термины MPI

Режимы выполнения

С блокировкой Без блокировки

Стандартная посылка

MPI_Send MPI_Isend

Синхронная посылка

MPI_Ssend MPI_Issend

Буферизованная посылка

MPI_Bsend MPI_Ibsend

Согласованная посылка

MPI_Rsend MPI_Irsend

Прием информации

MPI_Recv MPI_Irecv

Page 9: 20090721 hpc exercise2

Термины MPIКоммуникатор – контекст взаимодействия процессов с помощью

функций MPI. За коммуникатором закрепляется некоторая группа процессов. Также возможно определение виртуальных топологий для упрощения структуризации обменов в рамках коммуникатора. Процессы в группе (и, как следствие, коммуникаторе) нумеруются от 0 до (<размер_группы> - 1)

MPI_COMM_WORLD – предопределенная в библиотеке MPI константа, представляющая коммуникатор, включающий все процессы запущенной MPI-программы.

MPI_COMM_SELF – предопределенная в библиотеке MPI константа, представляющая коммуникатор, включающий только текущий процесс.

Page 10: 20090721 hpc exercise2

Термины MPIС:

– все функции начинаются с префикса MPI_

• int MPI_Init(int *argc, char **argv);• int MPI_Finalize(void);• int MPI_Initialized(int *flag);

– все функции имеют тип int и возвращают либо значение MPI_SUCCESS (в случае нормального завершения), либо код, соответствующий произошедшей ошибке

Page 11: 20090721 hpc exercise2

Термины MPIПри описании функций и их параметров будем

использовать следующие обозначения:

– Данные, помеченные [IN], считаются входными для функции (процедуры), то есть, используются внутри нее, но не изменяются.

– Данные, помеченные [OUT], считаются выходными и могут быть изменены.

– Данные, помеченные [INOUT], используются внутри функции и могут быть изменены.

Page 12: 20090721 hpc exercise2

Структура MPI-программы

Page 13: 20090721 hpc exercise2

Структура MPI-программы

Основные этапы жизненного цикла MPI-программы:

• Запуск• Инициализация среды выполнения MPI• Вычисления• Завершение среды выполнения MPI• Выгрузка

Page 14: 20090721 hpc exercise2

Структура MPI-программы

MPI_Init(argc, argv)– [INOUT] argc – количество параметров командной строки запуска

программы– [INOUT] argv – параметры командной строки, используемые для

передачи параметров в программу

C: int MPI_Init(int *argc, char ***argv)

• Функция MPI_Init создает группу процессов, в которой содержатся все процессы MPI-программы, и соответствующий этой группе коммуникатор MPI_COMM_WORLD.

• Может быть вызвана только один раз, попытка повторной инициализации завершится ошибкой.

Page 15: 20090721 hpc exercise2

Структура MPI-программы

MPI_Finalize()– Без параметров

• C: int MPI_Finalize(void)

Функция MPI_Finalize освобождает ресурсы, занятые средой выполнения MPI.

Page 16: 20090721 hpc exercise2

Структура MPI-программы

#include <stdio.h>#include <mpi.h>

int main(int argc, char* argv[]){

int ierr;

ierr = MPI_Init(&argc, &argv); // Инициализация среды MPI

if (ierr != MPI_SUCCESS)return ierr;

printf("Hello world\n"); // Полезная работа

MPI_Finalize(); // Завершение среды MPI}

Page 17: 20090721 hpc exercise2

Основные функции MPI

Page 18: 20090721 hpc exercise2

Основные функции MPI

MPI_Initialized(flag)– [OUT] flag – возвращает 0, если среда выполнения MPI

не была еще инициализирована

C: int MPI_Initialized(int *flag)

Функция MPI_Initialized позволяет выяснить, была ли среда выполнения MPI уже инициализирована.

Page 19: 20090721 hpc exercise2

Основные функции MPI

MPI_Comm_size(comm, size)– [IN] comm – коммуникатор, размер которого хотим определить.– [OUT] size – количество процессов в коммуникаторе comm

C: int MPI_Comm_size(MPI_Comm comm, int *size)

Функция MPI_Comm_size возвращает в переменную size количество процессов в коммуникаторе comm.

Page 20: 20090721 hpc exercise2

Основные функции MPI

MPI_Comm_rank(comm, rank)– [IN] comm – коммуникатор, относительно которого мы хотим

определить ранг текущего процесса.– [OUT] rank – ранг текущего процесса в коммуникаторе comm

C: int MPI_Comm_rank(MPI_Comm comm, int *rank)

• Функция MPI_Comm_rank возвращает в переменную rank ранг текущего процесса в коммуникаторе comm.

• В различных коммуникаторах ранги одного и того же процесса могут быть различны, но обязательно уникальны в рамках каждого коммуникатора.

Page 21: 20090721 hpc exercise2

Блокирующие функции обмена сообщениями

Page 22: 20090721 hpc exercise2

Блокирующие функции обмена сообщениями

• Сообщения – данные, передаваемые между процессами, вместе с дополнительной информацией – их описанием

• Сообщения помечаются тегом – произвольно задаваемым программистом целым числом

• Тег и дополнительная информация передаются в оболочке сообщения

• Каждой операции отправки сообщения должна соответствовать операция приема.

Отправка сообщения: - оболочка - данные

Прием сообщения: - сравнить оболочки - принять данные=?

Page 23: 20090721 hpc exercise2

Блокирующие функции обмена сообщениями

Оболочка сообщения содержит:– Ранг процесса-источника сообщения– Ранг процесса-получателя сообщения– Количество передаваемых в сообщении данных– Тег сообщения– Коммуникатор, в рамках которого происходит

отправка

Отправка сообщения: - оболочка - данные

Прием сообщения: - сравнить оболочки - принять данные=?

Page 24: 20090721 hpc exercise2

Блокирующие функции обмена сообщениями

MPI_Send(buf, count, datatype, dest, tag, comm)– [IN] buf – указатель на буфер отправляемых данных– [IN] count – количество данных типа datatype в буфере buf– [IN] datatype – тип отправляемых данных– [IN] dest – ранг процесса, которому отсылаем данные– [IN] tag – тэг отсылаемых данных– [IN] comm – коммуникатор

• С: MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, • int tag, MPI_Comm comm)

Функция MPI_Send отсылает сообщение из буфера buf процессу с рангом dest.

Page 25: 20090721 hpc exercise2

Блокирующие функции обмена сообщениями

MPI_Recv(buf, count, datatype, source, tag, comm, status)– [OUT] buf – указатель на буфер, в который будут сохранены полученные данные – [IN] count – количество принимаемых данных типа datatype– [IN] datatype – тип принимаемых данных– [IN] source – ранг процесса, от которого принимаем данные, или MPI_ANY_SOURCE– [IN] tag – тэг принимаемых данных или MPI_ANY_TAG– [IN] comm – коммуникатор– [OUT] status – статус полученного сообщения

• С: MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

Функция MPI_Recv принимает сообщение от процесса с рангом source. В случае, если ранг не известен или не важен, можно указать значение MPI_ANY_SOURCE. Если неизвестен или неважен тэг сообщения, можно указать значение MPI_ANY_TAG.

Page 26: 20090721 hpc exercise2

Типы данныхMPI C

MPI_CHAR signed charMPI_SHORT signed short intMPI_INT signed intMPI_LONG signed long intMPI_UNSIGNED_CHAR unsigned charMPI_UNSIGNED_SHORT unsigned short intMPI_UNSIGNED unsigned intMPI_UNSIGNED_LONG unsigned long intMPI_FLOAT floatMPI_DOUBLE doubleMPI_LONG_DOUBLE long double

Page 27: 20090721 hpc exercise2

Настройка проекта в Visual Studio 2008

Page 28: 20090721 hpc exercise2

Настройка проекта в Visual Studio 2008

1) Project -> Project Properties-> C\C++-> General –> Additional Include Directories :

• затем нажмите на икону и выберите папку: C:\Program Files\Microsoft HPC Pack 2008 SDK\Include

2) Project -> Project Properties-> Linker -> General -> Additional Library Directories :

• C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\i386 3) Project -> Project Properties-> Linker -> Input: msmpi.lib Ws2_32.lib

• Для платформы x64, и введите папки: • C:\Program Files\Microsoft HPC Pack 2008 SDK\Include • C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\amd64

Page 29: 20090721 hpc exercise2

Настройка проекта в Visual Studio 2008

Page 30: 20090721 hpc exercise2

Настройка проекта в Visual Studio 2008

Page 31: 20090721 hpc exercise2

Настройка проекта в Visual Studio 2008

Page 32: 20090721 hpc exercise2

Настройка проекта в Visual Studio 2008•

Page 33: 20090721 hpc exercise2

Выполнение упражнения

Page 34: 20090721 hpc exercise2

Выполнение упражнения

MasterMaster

WorkerWorker WorkerWorkerMasterMaster

MasterMaster

Send / Recv

WorkerWorker

Page 35: 20090721 hpc exercise2

Выполнение упражения1. Запустите проект в папке Exercises\03 MPI\MPIContrastStretch. Настройте проект для создания

MPI приложений как сказано выше. Выберите архитектуру процессора (Win32 или x64). Добавьте в файл “app.h” строку #include <mpi.h>. В самом начале главной функции добавьте вызовы функций MPI_Init, MPI_Comm_size, MPI_Comm_rank, и gethostname. Для более простого способа отладки объявите связанные с ними переменные как глобальные. Например :int myRank;int numProcs;char host[256];

int main(int argc, char *argv[]){

MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &numProcs);

MPI_Comm_rank(MPI_COMM_WORLD, &myRank); gethostname(host, sizeof(host)/sizeof(host[0]));

…MPI_Finalize();return 0;

}

Page 36: 20090721 hpc exercise2

Выполнение упражнения 2. Cоздайте тип данных MPI_PIXEL_T ,добавив вызов функции CreateMPIPixelDatatype

после вызова MPI_Init. Новый тип MPI данных назовем MPI_PIXEL_T:

…gethostname(host,sizeof(host)/sizeof(host[0]));MPI_Datatype MPI_PIXEL_T = CreateMPIPixelDatatype();

• Для его уничтожения необходимо перед вызовом функции MPI_Finalize все процессы должны вызвать функцию MPI_Type_free:

…MPI_Type_free(&MPI_PIXEL_T);MPI_Finalize();return 0;

Page 37: 20090721 hpc exercise2

Выполнение упражнения3. Найдите в файле место, где происходит вызов ContrastStretch и закомментируйте его.

добавьте ниже:

PIXEL_T **chunk = NULL;int myrows = 0;int mycols = 0;

// разделение матрицы на частиchunk = DistributeImage(image, rows, cols, myrows, mycols, MPI_PIXEL_T); assert(chunk != NULL); assert(rows > 0); assert(cols > 0);assert(myrows > 0); assert(mycols > 0);// chunk = ContrastStretch(chunk, myrows, mycols, steps, stepby, MPI_PIXEL_T); // собирание матрицыimage = CollectImage(image, rows, cols, chunk, myrows, mycols, MPI_PIXEL_T);

Page 38: 20090721 hpc exercise2

Выполнение упражнения5. Добавьте в проект файлы Distribute.cpp и Collect.cpp. Добавьте в файл Distribute.cpp

функцию DistributeImage для распределения частей матрицы между вычислительными узлами :#include "app.h”#include "mpi.h"PIXEL_T **DistributeImage(PIXEL_T **image, int &rows, int &cols, int &myrows, int &mycols, MPI_Datatype MPI_PIXEL_T){

return NULL;}

• добавьте в файл Collect.cpp функцию CollectImage для сбора частей матрицы в единую матрицу. :#include "app.h”#include "mpi.h"PIXEL_T **CollectImage(PIXEL_T **image, int rows, int cols, PIXEL_T **chunk, int myrows, int mycols, MPI_Datatype MPI_PIXEL_T){

return NULL;}

Page 39: 20090721 hpc exercise2

Выполнение упражнения

• Добавьте в файл “app.h” определения функций:

PIXEL_T **DistributeImage(PIXEL_T **image, int &rows, int &cols, int &myrows, int &mycols, MPI_Datatype MPI_PIXEL_T);PIXEL_T **CollectImage(PIXEL_T **image, int rows, int cols, PIXEL_T **chunk, int myrows, int mycols, MPI_Datatype MPI_PIXEL_T);

• Также в файле “app.h” необходимо объявить внешними (external) переменные:

extern int myRank;extern int numProcs;extern char host[256];

Page 40: 20090721 hpc exercise2

Выполнение упражения6. В файле Main.cpp добавим код, для того чтобы ввод и вывод файлов осуществлялся только главным

узлом. Находим строку где выводится "** Reading bitmap from '" и добавляем выше и ниже:

double time = 0.0;

if (myRank == 0){

cout << "** Reading bitmap from '" << infile << "'..." << endl;image = ReadBitmapFile(infile, bitmapFileHeader, bitmapInfoHeader, rows, cols);if (image == NULL){

cout << endl;cout << "** Failed to open image file, halting..." << endl; MPI_Abort(MPI_COMM_WORLD, 1);

}cout << "** Bitmap size is " << rows << " rows, " << cols << " cols, " << rows*cols << " pixels..." << endl;

cout << endl; startTime = clock();

}

//image = ContrastStretch(image, rows, cols, steps, stepby);

Page 41: 20090721 hpc exercise2

Выполнение упражнения7. Изменим функцию DistributeImage:PIXEL_T **chunk = NULL; int tag = 0;int params[2] = {0, 0};cout << myRank << " (" << host << "): Distributing image..." << endl;if (myRank == 0) // выполняется главным узлом:{int rowsPerProc = rows / numProcs;int leftOverRows = rows % numProcs;params[0] = rows;params[1] = cols; for (int dest=1; dest < numProcs; dest++) // послание каждому процессу размера матрицы MPI_Send(params, sizeof(params)/sizeof(params[0]), MPI_INT, dest, tag, MPI_COMM_WORLD); for (int dest=1; dest < numProcs; dest++) // послание части матрицы MPI_Send(image[leftOverRows + dest*rowsPerProc], rowsPerProc*cols, MPI_PIXEL_T, dest, tag,

MPI_COMM_WORLD);myrows = rowsPerProc + leftOverRows;mycols = cols;chunk = New2dMatrix<PIXEL_T>(myrows+2, mycols); // почему на две строки

// больше? Смотри функцию изменения контрастностиmemcpy_s(chunk[1], myrows*mycols*sizeof(PIXEL_T), image[0], myrows*mycols*sizeof(PIXEL_T));

}•

Page 42: 20090721 hpc exercise2

Выполнение упражненияelse //выполняется вычислительными узлами{MPI_Status status;MPI_Recv(params, sizeof(params)/sizeof(params[0]), MPI_INT, 0 /*master*/, tag, MPI_COMM_WORLD,

&status);rows = params[0];cols = params[1];myrows = rows / numProcs; // размер части матрицы

mycols = cols;

chunk = New2dMatrix<PIXEL_T>(myrows+2, mycols); // почему на две строки // больше? Смотри функцию изменения контрастности

MPI_Recv(chunk[1], myrows*mycols, MPI_PIXEL_T, 0 /*master*/, tag, MPI_COMM_WORLD, &status);}

return chunk;

Page 43: 20090721 hpc exercise2

Выполнение упражнения8. Изменим функцию CollectImage :

assert(chunk != NULL); assert(rows > 0); assert(cols > 0); assert(myrows > 0); assert(mycols > 0);

int tag = 0;

cout << myRank << " (" << host << "): Collecting image..." << endl;if (myRank > 0) // вычислительные узлы{

int dest = 0; // to masterMPI_Send(chunk[1], myrows*mycols, MPI_PIXEL_T, dest, tag,

MPI_COMM_WORLD);}

Page 44: 20090721 hpc exercise2

else // главный вычислительный узел{

assert(image != NULL); MPI_Status status;

memcpy_s(image[0], myrows*mycols*sizeof(PIXEL_T), chunk[1], myrows*mycols*sizeof(PIXEL_T));

int rowsPerProc = rows / numProcs; int leftOverRows = rows % numProcs;

// получение данных от узлов for (int src=1; src < numProcs; src++)

MPI_Recv(image[leftOverRows + src*rowsPerProc], rowsPerProc*cols, MPI_PIXEL_T, src, tag, MPI_COMM_WORLD, &status);

}Delete2dMatrix<PIXEL_T>(chunk);

return image;

Page 45: 20090721 hpc exercise2

Выполнение упражнения Скомпилируйте приложение, скопируйте изображение в папку с EXE файлом и

запустите приложение. С помощью программы WinDiff сравните полученные изображения.

Page 46: 20090721 hpc exercise2

9. В файле “Main. cpp” уберите комментарии для строки chunk = ContrastStretch(chunk, myrows, mycols, steps, stepby, MPI_PIXEL_T);

Измените определение функций ContrastStretch в файл “app.h” :

PIXEL_T **ContrastStretch(PIXEL_T **image, int rows, int cols, int steps, int stepby, MPI_Datatype MPI_PIXEL_T);

Откройте файл ContrastStretch.cpp и измените код в соответствии с

PIXEL_T **ContrastStretch(PIXEL_T **image, int rows, int cols, int steps, int stepby, MPI_Datatype MPI_PIXEL_T)

{cout << myRank << " (" << host << "): Processing " << rows << "rows,"

<< cols << " cols..." << endl;PIXEL_T **image2 = New2dMatrix<PIXEL_T>(rows+2, cols); MPI_Status status; int tag = 0;//Обратите внимание на два дополнительных строки

Выполнение упражнения

Page 47: 20090721 hpc exercise2

Выполнение упражнения int firstRow = 1; // это справедливо для всех узлов кроме главного

int lastRow = rows;

if (myRank == 0) // главный узел начинает вычисления со второй строкиfirstRow = 2;

if (myRank == numProcs-1) // последний узел не вычисляет значения для //последней строки

lastRow = rows-1;

bool converged = false;

Page 48: 20090721 hpc exercise2

Выполнение упражнения10. Для добавления возможности обмена строками необходимо добавить код в самом начале цикла while в файле ContrastStretch.cpp:

cout << myRank << " (" << host << "): ** Step " << step << "..." << endl;

if (myRank < numProcs-1) // все посылают «вниз» последнюю (строку кроме последнего узла): MPI_Send(image[lastRow], cols, MPI_PIXEL_T, myRank+1, tag, MPI_COMM_WORLD);

if (myRank > 0) // все получают строку кроме первого узла MPI_Recv(image[firstRow-1], cols, MPI_PIXEL_T, myRank-1, tag, MPI_COMM_WORLD, &status);if (myRank > 0) // все посылают вверх первую строку (кроме //первого узла):

MPI_Send(image[1], cols, MPI_PIXEL_T, myRank-1, 0 /*tag*/, MPI_COMM_WORLD);if (myRank < numProcs-1) // все получают первую строку (кроме последнего узла

MPI_Recv(image[rows+1], cols, MPI_PIXEL_T, myRank+1, 0 /*tag*/, MPI_COMM_WORLD, &status);

0

1

2

3

Page 49: 20090721 hpc exercise2

Выполнение упражнения

11. Изменение цикла for для вычисления переменной diffs :

if (myRank > 0) // вычислительные узлы:{

MPI_Send(&diffs, 1, MPI_LONG_LONG, 0 /*master*/, 0 /*tag*/, MPI_COMM_WORLD);MPI_Recv(&diffs, 1, MPI_LONG_LONG, 0 /*master*/, 0 /*tag*/, MPI_COMM_WORLD, &status);

}

Page 50: 20090721 hpc exercise2

Выполнение упражненияelse // главный узел:{long long temp;for (int src=1; src < numProcs; src++) // получение значений от все вычислительных

//узлов:{MPI_Recv(&temp, 1, MPI_LONG_LONG, MPI_ANY_SOURCE, 0 /*tag*/,

MPI_COMM_WORLD, &status);diffs += temp; // суммирование}

for (int dest=1; dest < numProcs; dest++) // отправка вычислительным узлам //нового значения

MPI_Send(&diffs, 1, MPI_LONG_LONG, dest, 0 /*tag*/, MPI_COMM_WORLD);}

cout << " (diffs until convergence: " << diffs << ")" << endl;

Page 51: 20090721 hpc exercise2

Выполнение упражнения12. Обновление циклов копирования матрицы:

for (int row = firstRow; row <= lastRow; row++)for (int col = 1; col < cols-1; col++)

image[row][col] = image2[row][col];

13.И в цикле while diffs = 0;

for (int row = firstRow; row < lastRow; row++){

for (int col = 1; col < cols-1; col++){

Page 52: 20090721 hpc exercise2

14.Скомпилируйте проект и запустите локальной машинеmpiexec –n 4 MPIApp.exe

14. Запишите полученные значения.

Выполнение упражнения

Page 53: 20090721 hpc exercise2

Выполнение упражнения1. Скомпилируйте приложение для выполнения на процессоре x64 и

скопируйте его вместе с изображением в своем папку на кластере2. Для выполнения MPI-приложения на кластере запустите Job Manager,

выберите адрес кластера: HN.PRACTICUM ( 193.232.2.150, <username>: <userpassword>,CLUSTER)

3. Добавьте новое задание, указав в командной строкеmpiexec.exe MPIContrastStretch.exe Sunset.bmp out.bmp 10 10

1. Добавьте в качестве настроек:– \\hn\apps\<username>– \\hn\apps\<username>\out.txt– \\hn\apps\<username>\err.txt

Page 54: 20090721 hpc exercise2

Выполнение упражнения

Page 55: 20090721 hpc exercise2

Заключение

Page 56: 20090721 hpc exercise2

© 2008 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as

of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation.

MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.