Основы параллельного программирования вычислительных систем с распределенной и разделяемой памятью

Автор работы: Пользователь скрыл имя, 05 Июня 2013 в 22:25, курсовая работа

Краткое описание

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

Содержание

Введение 4
1 Общие представления о параллельном программировании 6
2 Архитектура параллельных компьютеров 8
2.1 Развитие архитектуры компьютера 8
2.2 Организация памяти параллельных компьютеров 10
2.3 Сети межсоединений 15
2.3.1 Свойства сетей межсоединений. Статические сети межсоединений 16
2.3.2 Динамические сети межсоединений 19
3 Введение в программирование с использованием передачи сообщений 22
3.1 Введение в MPI 22
3.1.1 MPI-коммуникация типа «точка-точка» 25
3.1.2 Тупиковые ситуации при коммуникациях типа «точка-точка» 30
3.1.3 Неблокирующие операции и режимы коммуникации 33
3.1.4 Коммуникационный режим 35
3.2 Групповые коммуникационные операции 36
3.3 Группы процессов и коммуникаторы 41
3.3.1 Группы процессов в MPI 41
3.3.2 Топологии процессов 45
3.3.3 Временные и прерывающие процессы 49
4 Введение в потоковое программирование в OpenMP 50
4.1 Проблемы поточной обработки цикла 52
4.2 Условия гонок 52
4.3 Управление общими и приватными данными 53
4.4 Планирование и разбиение циклов 55
4.5 Библиотечные функции ОреnМР 57
4.6 Отладка 58
4.7 Производительность 59
4.8 Основные моменты 61
5 Протокол сеансового уровня SSH 63
6 Удаленный вход на кластер 66
7 Операционная система Linux 68
7.1 Интерфейс ОС Linux 68
7.2 Некоторые команды Linux 68
8 Компилирование последовательных программ (Fortran/C/C++) 71
9 Основные команды 72
10 Работа с кластером 74
Список использованных источников информации 83

Вложенные файлы: 1 файл

Cluster.doc

— 829.00 Кб (Скачать файл)

Используя MPI_Sendrecv(), программисту не нужно беспокоиться о порядке операций передачи и приема. Исполнительная система MPI гарантирует отсутствие тупиковых ситуаций (независимо от того, используются ли системные буферы или нет).

Имеется вариант MPI_Sendrecv(), для которого буферы передатчика и приемника идентичны. Эта операция также является блокирующей. Ее синтаксис:

int MPI_Sendrecv_replace (void *buffer,

int count,

MPI_Datatype type,

int dest,

int sendtag,

int source,

int recvtag,

MPI_Comm comm,

MPI_Status *status)

Здесь buffer определяет буфер, используемый как в качестве буфера передатчика, так и в качестве буфера приемника. Для этой цели используется count – число элементов, которые должны быть переданы и получены.

3.1.3 Неблокирующие операции и режимы коммуникации

Использование блокирующих  коммуникационных операций ведет к  непродуктивному ожиданию в течение  времени, пока заблокированный процесс  не исполняет никаких полезных задач. Например, процесс, выполняющий блокирующую операцию передачи, должен ждать завершения копирования информации из буфера отправителя в системный буфер или даже прихода сообщения к принимающему процессу, если системные буферы не используются. Часто желательно заполнить времена ожиданий выполнением каких-либо полезных операций ожидающим процессом. Это может быть достигнуто путем использования неблокирующих коммуникационных операций.

Неблокирующая операция передачи обладает преимуществом: вызывающему ее процессу управление возвращается сразу, как только это возможно, так что он может быстрее приступить к выполнению полезных операций. Неблокирующая передача осуществляется путем вызова следующей MPI-функции:

int MPI_Isend ( void *buffer,

     int count,

MPI Datatype type,

int dest,

int tag,

MPI_Comm comm,

MPI_Request *request)

Параметры данной функции  аналогичны параметрам функции MPI_Send(). Имеется один дополнительный параметр типа MPI_Request, который может быть использован для идентификации определенной коммуникационной операции. Данный объект также используется исполнительной системой MPI для сообщения статуса коммуникационной операции.

Неблокирующая операция приема инициирует получение сообщения и возвращает управление получающему процессу, как только это возможно. По этому возврату, операция приема уже запущена, и исполнительная система осведомлена о том, что определенный буфер приемника готов к приему информации. Но возврат не говорит о том, что буфер приемника уже содержит данные, то есть сообщение, которое должно быть принято, еще не может быть использовано. Неблокирующий прием обеспечивается вызовом следующей функции:

int MPI_Irecv ( void *buffer,

int count,

MPI_Datatype type,

int source,

int tag,

MPI_Comm comm,

MPI_Request *request)

Параметры данной функции аналогичны параметрам функции MPI_Recv().

Для определения завершенности  неблокирующей коммуникационной операции может быть использована следующая  функция:

int MPI_Test (MPI_Request *request,

     int *flag,

   MPI_Status *status)

Функция возвращает flag = 1, если коммуникационная операция, определенная параметром request, завершилась. В противном случае функция возвратит flag = 0.

MPI-функция

int MPI_Wait (MPI_Request *request, MPI_Status *status)

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

 

3.1.4 Коммуникационный режим

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

Стандартный режим. Коммуникационные операции, объясненные выше, использовались в стандартном режиме. При использовании данного режима исполняющая система MPI решает, помещаются ли исходящие сообщения в локальные системные буферы или нет. Для программиста это оборачивается тем, что он не может полагаться на буферизацию сообщений. Следовательно, программы должны быть написаны так, чтобы они работали даже при отсутствии буферизации.

Синхронный режим. В стандартном режиме операция передачи может быть завершена, даже если соответствующая ей операций приема еще не началась (если используются системные буферы). В синхронном режиме операция передачи не завершится, пока принимающий процесс не начнет приме данных. Таким образом, исполнение операций передачи и приема в синхронном режиме ведет к некоторой форме синхронизации между передающим и принимающим процессами. Блокирующая операция передачи в синхронном режиме осуществляется вызовом MPI-функции MPI_Ssend(), имеющей те же параметры, что и функция MPI_Send(). Неблокирующая операция передачи в синхронном режиме осуществляется вызовом MPI-функции MPI_Issend(), имеющей те же параметры, что и функция MPI_Isend(). Аналогично неблокирующей операции, используемой в стандартном режиме, вызывающему процессу управление возвращается как только это возможно, то есть в синхронном режиме нет синхронизации между MPI_Issend() и MPI_Irecv(). Синхронизация между передатчиком и приемником осуществляется путем вызова передатчиком функции MPI_Wait().

Буферизированный  режим. В данном режиме на локальное исполнение и завершение операции передачи не влияют никакие нелокальные события. При запуске операции передачи в буферизированном режиме, управление вызвавшему функцию процессу будет возвращено, даже если соответствующая операция приема еще не началась. Более того, буфер передатчика может быть использован заново сразу же после возврата управления, даже если используется неблокирующая передача. Если соответствующая операция приема еще не началась, исполняющая система должна поместить исходящее сообщение в буфер. Блокирующая операция передачи в буферизированном режиме осуществляется вызовом MPI-функции MPI_Bsend(), имеющей те же параметры, что и функция MPI_Send(). Неблокирующая операция передачи в буферизированном режиме осуществляется вызовом MPI-функции MPI_Ibsend(), имеющей те же параметры, что и функция MPI_Isend(). В буферизированном режиме пространство под буферы, которое будет использовано исполняющей системой, должно быть обеспечено программистом, который должен следить, в частности, за тем, чтобы буфер не был слишком маленьким. Буфер для буферизации сообщений передатчиком выделяется путем вызова MPI-функции

int MPI_Buffer_attach (void *buffer, int buffersize)

Здесь – buffersize размер буфера buffer в байтах. С процессом в каждый момент времени может быть связан только один буфер. Ранее выделенный буфер можно отделить от процесса вызовом функции

int MPI_Buffer_detach (void *buffer, int *buffersize)

Для операций приема MPI предоставляет только стандартный режим.

3.2 Групповые коммуникационные операции

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

Широковещательная операция (Broadcast Operation)

При широковещательной операции один процесс из некоторой группы отправляет один и тот же блок данных всем процессам  данной группы. В MPI широковещательная операция осуществляется путем вызова следующей MPI-функции:

int MPI_Bcast ( void *message,

                 int count,

                 MPI_Datatype type,

                int root,

                MPI_Comm comm)

Здесь root обозначает процесс (является рангом процесса), отсылающий блок данных message. Остальные процессы определяют поле message в качестве своих приемных буферов. Параметр count – количество элементов с типом данных type в блоке данных. MPI_Bcast() является операцией групповой коммуникации, то есть каждый процесс коммуникатора comm должен вызвать эту функцию. Блоки данных, отправленные с помощью MPI_Bcast() не могут быть приняты с помощью операции MPI_Recv().

Исполняющая система MPI гарантирует, что широковещательные сообщения будут получены в том же порядке, в котором они были отправлены root-процессом.

Групповые коммуникационные операции MPI всегда являются блокирующими.

Операция свертки (Reduction Operation)

При выполнении такой операции каждый процесс предоставляет блок данных, который затем комбинируется с блоками данных от остальных процессов с помощью двоичной операции свертки. Результат сохраняется в root-процессе. В MPI коллективная операция свертки осуществляется путем вызова следующей функции:

int MPI_Reduce ( void *sendbuf,

                 void *recvbuf,

              int count,

            MPI_Datatype type

      MPI_Op op,

      int root,

      MPI_Comm comm)

Здесь sendbuf – буфер отправки, в который каждый процесс записывает данные, которые впоследствии будут подвергнуты свертке. Параметр recvbuffer – приемный буфер, предоставляемый процессом root. Параметр count – количество элементов данных, предоставляемых каждым процессом, type – тип данных каждого из этих элементов. Параметр op определяет осуществляемую операцию свертки. Такая операция обязательно должна быть ассоциативной операцией. В таблице 3 приведены предопределенные операции свертки MPI, являющиеся еще и коммутативными.

Таблица 3 – Операции свертки MPI

Название

Результат

MPI_MAX

максимум

MPI_MIN

минимум

MPI_SUM

сумма

MPI_PROD

произведение

MPI_LAND

логическое И

MPI_BAND

поразрядное И

MPI_LOR

логическое ИЛИ

MPI_BOR

поразрядное ИЛИ

MPI_LXOR

логическое исключающее ИЛИ

MPI_BXOR

поразрядное исключающее ИЛИ

MPI_MAXLOC

максимальное значение и соответствующий индекс

MPI_MINLOC

минимальное значение и соответствующий  индекс


С помощью MPI-функции

int MPI_Op_create ( MPI_User function *function,

                    int commute,

                    MPI_Op *op)

пользователь  может определить свою операцию свертки.

Операция накопления (Gather Operation)

Для этой операции каждый процесс  предоставляет блок данных, сохраняемых  затем в root-процессе. Операция осуществляется путем вызова следующей MPI-функции:

 

int MPI_Gather (void *sendbuf,

                 int sendcount,

                 MPI_Datatype sendtype,

                 void *recvbuf,

                 int recvcount,

                 MPI_Datatype recvtype,

                 int root,

                 MPI_Comm comm)

Параметр sendbuf – буфер передачи, обеспечиваемый всеми принимающими в операции участие процессами. Каждый процесс предоставляет sendcount элементов типа sendtype. параметр recvbuf – буфер приемника, выделяемый root-процессом. root-процесс принимает recvcount элементов типа recvtype от каждого процесса, входящего в коммуникатор comm  и сохраняет их в порядке рангов процессов.

Также существует вариант функции  MPI_Gather(), для которой каждый процесс может предоставить различное количество элементов – функция MPI_Gatherv().

Операция распределения (Scatter Operation)

При выполнении операции распределения root-процесс снабжает каждый участвующий в операции процесс блоком данных, предназначенным только для этого процесса. В MPI операция распределения осуществляется путем вызова функции

int MPI_Scatter (void *sendbuf,

 int sendcount,

 MPI_Datatype sendtype,

void *recvbuf,

int recvcount,

 MPI_Datatype recvtype,

int root,

MPI_Comm comm)

Обобщенная версия этой функции, позволяющая root-процессу распределять блоки различных размеров  – функция MPI_Scatterv(). 

Мультишироковещательная операция (Multi-broadcast Operation)

Для данной операции каждый процесс  предоставляет блок данных, который  может быть, например, результатом  локальных вычислений. При выполнении операции, все блоки данных будут доставлены всем процессам. Здесь не выделяется root-процесса. В MPI мультишироковещательная операция осуществляется путем вызова функции

int MPI_Allgather (void *sendbuf,

   int sendcount,

   MPI_Datatype sendtype,

   void *recvbuf,

   int recvcount,

   MPI_Datatype recvtype,

   MPI_Comm comm)

 В следующем примере каждый процесс заполняет свой буфер отправки 100 целыми числами, которые затем принимаются всеми процессами при выполнении мультишироковещательной операции:

int sbuf[100], gsize, *rbuf;

MPI_Comm_size (comm, &gsize);

rbuf = (int*) malloc (gsize*100*sizeof(int));

Информация о работе Основы параллельного программирования вычислительных систем с распределенной и разделяемой памятью