MPI 2.0: Односторонние коммуникации

В MPI 1.1 коммуникации «точка-точка» происходят по схеме двустороннего рандеву. То есть, для каждого сообщения должны быть явно определены процесс-отправитель и процесс-получатель (возможно, они совпадают). Это не всегда бывает удобно. Например, в случае распараллеливания перебора (Лабораторная работа 1), если один процесс нашел решение, то для того, чтобы была возможность сообщить об этом остальным процессам, в коде остальных процессов должна присуствовать проверка: а не пришло ли сообщение о том, что какой-то процесс закончил работу. Это добавляет необходимость дополнительных синхронизаций и отрицательно влияет на производительность. Для того, чтобы избавиться от этого, в MPI 2.0 добавлена поддержка односторонних коммуникаций: отправитель вызывает функцию отправки сообщения, а получателю, для того, чтобы получить данные, не нужно вызывать функцию приема сообщения. Отправитель просто обращается по соответствующему адресу в памяти и получает пришедшие значения, если сообщение пришло до момента обращения, либо исходные значения.

Создание и удаление окна

Перед использованием двусторонних коммуникаций в каждом процессе коммуникатора необходимо инициализировать «окно» — область памяти, доступную для записи другим процессам коммуникатора.

int MPI_Win_create(void *base, MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, MPI_Win *win)

base — начальный адрес, по которому будут располагаться данные в окне (базовый адрес);

size — размер окна в байтах;

disp_unit — величина смещения одного элемента окна относительно другого;

info — Объект MPI_Info (на самом деле int);

comm — Коммуникатор, в котором происходит действо;

win — адрес, по которому создается объект окна;

По завершении работы нужно уничтожить окно:

int MPI_Win_free(MPI_Win *win)

Получение атрибутов окна

Атрибуты окон реализованы в виде ассоциативного массива.

int MPI_Win_get_attr(MPI_Win win, int win_keyval, void *attribute_val, int *flag)

win — окно, атрибут которого нужно получить

key — ключ атрибута. Есть несколько предопределенных ключей

MPI_WIN_BASE - базовый адрес окна.

MPI_WIN_SIZE - размер окна.

MPI_WIN_DISP_UNIT - displacement unit associated with the window.

Коммуникационные вызовы

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

MPI_Get — Получает значение из удаленной памяти в локальную

MPI_Put — Записывает значение из локальной памяти в удаленную

MPI_Accumulate — изменяет значения в удаленной памяти, например, добавляя к ним значения, отправленные из локальной памяти

MPI_Get

int MPI_Get(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,

MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win)

orig_addr — адрес, по которому принимаются данные

orig_count — число принимаемых элементов

orig_datatype — тип принимаемых данных

target_rank — ранг процесса, которому отправляются данные

target_disp — смещение относительно начала окна адреса принимаемых данных

target_type — тип принимаемых данных

win — Объект окна, в котором происходит односторонняя коммуникация

MPI_Put

int MPI_Put(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank,

MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win)

orig_addr — адрес, по которому находятся отправляемые данные

orig_count — число отправляемых элементов

orig_datatype — тип отправляемых данных

target_rank — ранг процесса, которому отправляются данные

target_disp — смещение относительно начала окна адреса принимаемых данных

target_type — тип принимаемых данных

win — Объект окна, в котором происходит односторонняя коммуникация

MPI_Accumulate

int MPI_Accumulate(void *origin_addr, int origin_count, MPI_Datatype origin_datatype,

int target_rank, MPI_Aint target_disp, int target_count,

MPI_Datatype target_datatype, MPI_Op op, MPI_Win win)

orig_addr — адрес, по которому находятся отправляемые данные

orig_count — число отправляемых элементов

orig_datatype — тип отправляемых данных

target_rank — ранг процесса, которому отправляются данные

target_disp — смещение относительно начала окна адреса принимаемых данных

target_type — тип принимаемых данных

op — редукционная операция. Добавлен новый вид редукции MPI_REPLACE(a,b)=b

win — Объект окна, в котором происходит односторонняя коммуникация

Синхронизация

Существуют два типа RMA коммуникаций:

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

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

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

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

Во второй модели удаленный процесс не вызывает функции синхронизации RMA и нет концепции эпохи предоставления доступа Существуют три вида механизмов синхронизации:

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

int MPI_Win_fence(int assert, MPI_Win win)

assert — Значение 0 всегда работает. Далее будет подробное описание

win — Окно.

Следующие 4 функции: MPI_Win_start, MPI_Win_complete, MPI_Win_post и MPI_Win_wait используются для сведения синхронизации к минимуму: синхронизируются только пары взаимодействующих процессов. Синхронизации происходят только при необходимости упорядочения локальных и удаленных обращений к окну. Этот механизм удобен в случаях, когда каждый процесс взаимодействует с небольшим числом процессов и граф коммуникаций не меняется или меняется редко.

Эти вызовы используются для первой модели коммуникаций. Каждая эпоха доступа начинается в локальном процессе с вызова MPI_Win_start и заканчивается вызовом MPI_Win_complete. Один из аругментов MPI_Win_start определяет группу удаленных процессов, участвующих в RMA коммуникациях в течение этй эпохи. Эпоха предоставления доступа в удаленном процессе начинается с вызова MPI_Win_post и заканчивается вызовом MPI_Win_wait. Один из аргументов MPI_win_post определяет группу процессов, предоставляющих свое адресное пространство для RMA.

int MPI_Win_start(MPI_Group group, int assert, MPI_Win win)

group — Группа процессов, собирающихся обращаться к удаленным данные

assert — Специальный параметр (потом будет раздел)

win — Окно

int MPI_Win_complete(MPI_Win win)

win — Окно

int MPI_Win_post(MPI_Group group, int assert, MPI_Win win)

group — Группа процессов, предоставляющих доступ к своим данным

assert — Специальный параметр (потом будет раздел)

win — Окно

int MPI_Win_wait(MPI_Win win)

win — Окно

Завершает эпоху предоставления доступа. Возврат управления не происходит до тех пор, пока не будут завершены все вызовы RMA, которые были вызваны в течение соответствующей эпохи доступа.

int MPI_Win_test(MPI_Win win, int *flag)

Неблокирующая версия MPI_Win_wait

Функции MPI_Win_lock и MPI_Win_unlock используются для второй модели RMA. Это используется при эмуляции разделяемой памяти. Эпоха доступа начинается вызовом MPI_Win_lock и заканчивается MPI_Win_unlock. В течение одной эпохе возможен доступ только к одному окну.

int MPI_Win_lock(int lock_type, int rank, int assert, MPI_Win win)

lock_type — тип блокировки: может быть MPI_LOCK_EXCLUSIVE или MPI_LOCK_SHARED

rank — ранг удаленного процесса, в группе ассоциированной с окном

assert — Специальный параметр (потом будет раздел)

win — окно

int MPI_Win_unlock(int rank,MPI_Win win)

rank — ранг удаленного процесса, в группе ассоциированной с окном

win — окно

Assertions

В качестве аргумента assertion в функции MPI_Win_fence, MPI_Win_start,MPI_Win_post и MPI_Win_lock передается комбинация флагов, обозначающая выполнение определенных условий, которая призвана улучшить производительность.

MPI_Win_start:

MPI_MODE_NOCHECK — Соответствующий вызов MPI_Win_post уже завершился на всех удаленных процессах до момента вызова MPI_Win_start Флаг MPI_MODE_NOCHECK может быть указан в MPI_Win_start тогда и только тогда, когда он указан в соответствующем вызове MPI_Win_post

MPI_Win_post:

MPI_MODE_NOCHECK — Соответствующие функции MPI_Win_start еще не были вызваны ни одним из процессов, намеревающимся осуществить доступ к данным до момента вызова MPI_Win_post .

MPI_MODE_NOSTORE — Локальный процесс не изменил данные окна с момента последней синхронизации. Отменяет необходимость синхронизации кэшей

MPI_MODE_NOPUT — Данные локального окна не буду изменены вызовами MPI_Put и MPI_Accumulate до вызова MPI_WAIT

MPI_Win_fence:

MPI_MODE_NOSTORE — Локальный процесс не изменил данные окна с момента последней синхронизации. Отменяет необходимость синхронизации кэшей

MPI_MODE_NOPUT — Данные локального окна не буду изменены вызовами MPI_Put и MPI_Accumulate до вызова MPI_WAIT

MPI_MODE_NOPRECEDE — До этого вызова не было других вызовов RMA. Если один из процессов окна устанавливает этот флаг, все остальные процессы группы должны тоже установить его.

MPI_MODE_NOSUCCEED — После этого вызова не будет других вызовов RMA. Если один из процессов окна устанавливает этот флаг, все остальные процессы группы должны тоже установить его.

MPI_Win_lock:

MPI_MODE_NOCHECK — Ни один из процессов не удерживает или не будет обращаться к окну, во время удерживания блокировки. Это бывает полезно, в случаях, когда взаимное исключение обеспечивается другими способами, но поддержка когерентности все равно необходима.

Задание 8

Сделать задание лабораторной работы 1 с использованием односторонних коммуникаций. Процесс, первым нашедший какое-либо решение, должен передать остальным результат, чтобы они завершили перебор.

Наши рекомендации