Украина |
Группы и коммуникаторы
В MPI существуют широкие возможности для операций над группами процессов и коммуникаторами. Это бывает необходимо, во-первых, чтобы дать возможность некоторой группе процессов работать над своей независимой подзадачей. Во-вторых, если особенность алгоритма такова, что только часть процессов должна обмениваться данными, бывает удобно завести для их взаимодействия отдельный коммуникатор. В-третьих, при создании библиотек подпрограмм нужно гарантировать, что пересылки данных в библиотечных модулях не пересекутся с пересылками в основной программе. Решение этих задач можно обеспечить в полном объеме только при помощи создания нового независимого коммуникатора.
Операции с группами процессов
Группа - это упорядоченное множество процессов. Каждому процессу в группе сопоставлено целое число - ранг или номер. MPI_GROUP_EMPTY -пустая группа, не содержащая ни одного процесса. MPI_GROUP_NULL - значение, используемое для ошибочной группы.
Новые группы можно создавать как на основе уже существующих групп, так и на основе коммуникаторов, но в операциях обмена могут использоваться только коммуникаторы. Базовая группа, из которой создаются все остальные группы процессов, связана с коммуникатором MPI_COMM_WORLD, В нее входят все процессы приложения. Операции над группами процессов являются локальными, в них вовлекается только вызвавший процедуру процесс, а выполнение не требует межпроцессного обмена данными. Любой процесс может производить операции над любыми группами, в том числе над такими, которые не содержат данный процесс. При операциях над группами может получиться пустая группа MPI_GROUP_EMPTY.
MPI_COMM_GROUP(COMM, GROUP, IERR) INTEGER COMM, GROUP, IERR
Получение группы GROUP, соответствующей коммуникатору сомм. В языке Си параметр GROUP имеет предопределенный тип MPi_Group. Поскольку изначально существует единственный нетривиальный коммуникатор MPI_COMM_WORLD, сначала нужно получить соответствующую ему группу процессов. Это можно сделать при помощи следующего вызова:
call MPI_COMM_GROUP(MPI_COMM_WORLD, group, ierr) MPI_GROUP_INCL(GROUP, N, RANKS, NEWGROUP, IERR) INTEGER GROUP, N, RANKS(*), NEWGROUP, IERR
Создание группы NEWGROUP из N процессов прежней группы GROUP с рангами RANKS (l),...,RANKS (N) , причем рангу RANKS (I) в старой группе соответствует ранг i-l в новой группе. При N=0 создается пустая группа MPI_GROUP_EMPTY. Возможно использование этой процедуры для задания нового порядка процессов в группе.
MPI_GROUP_EXCL(GROUP, N, RANKS, NEWGROUP, IERR) INTEGER GROUP, N, RANKS(*), NEWGROUP, IERR
Создание группы NEWGROUP ИЗ процессов группы GROUP, исключая процессы с рангами RANKS (1),...,RANKS (N) , причем порядок оставшихся процессов в новой группе соответствует порядку процессов в старой группе. При N=0 создается группа, идентичная старой группе.
В следующем примере создается две непересекающихся группы процессов groupl и group2 на основе процессов группы group. В каждую из создаваемых групп войдет примерно половина процессов прежней группы (при нечетном числе процессов в группу group2 войдет на один процесс больше). Порядок нумерации процессов во вновь создаваемых группах сохранится.
size1 = size/2 do i = 1, size1 ranks(i) = i-1 enddo call MPI_GROUP_INCL(group, size1, ranks, group1, ierr) call MPI_GROUP_EXCL(group, size1, ranks, group2, ierr)
Следующие три процедуры определяют операции над группами процессов, как над множествами. Из-за особенностей нумерации процессов ни объединение, ни пересечение групп не коммутативны, но ассоциативны.
MPI_GROUP_INTERSECTION(GROUP1, GROUP2, NEWGROUP, IERR) INTEGER GROUP1, GROUP2, NEWGROUP, IERR
Создание группы NEWGROUP из пересечения групп GROUP 1 и GROUP 2. Полученная группа содержит все процессы группы GROUP 1, входящие также в группу GROUP2 и упорядоченные, как в первой группе.
MPI_GROUP UNION(GROUP1, GROUP2, NEWGROUP, IERR) INTEGER GROUP1, GROUP2, NEWGROUP, IERR
Создание группы NEWGROUP ИЗ объединения групп GROUP 1 и GROUP 2. Полученная группа содержит все процессы группы GROUP l в прежнем порядке, за которыми следуют процессы группы GROUP 2, не вошедшие в группу GROUP 1, также в прежнем порядке.
MPI_GROUP_DIFFERENCE(GROUP1, GROUP2, NEWGROUP, IERR) INTEGER GROUP1, GROUP2, NEWGROUP, IERR
Создание группы NEWGROUP ИЗ разности групп GROUP 1 и GROUP 2. Полученная группа содержит все элементы группы GROUP 1, не входящие в группу GROUP 2 и упорядоченные, как в первой группе.
Например, пусть в группу grl входят процессы о, 1, 2, 4, 5, а в группу gr2 -процессы 0, 2, 3 (нумерация процессов задана в группе, соответствующей коммуникатору MPI_COMM_WORLD ). Тогда после вызовов
- call MPI_GROUP_INTERSECTION(gr1, gr2, newgr1, ierr)
- call MPI_GROUP_UNION(gr1, gr2, newgr2, ierr)
- call MPI_GROUP_DIFFERENCE(gr1, gr2, newgr3, ierr)
- в группу newgrl входят процессы 0, 2;
- в группу newgr2 входят процессы 0, 1, 2, 4, 5, 3;
- в группу newgr3 входят процессы 1, 4, 5.
Порядок нумерации процессов в полученных группах соответствует порядку их перечисления.
MPI_GROUP_SIZE(GROUP, SIZE, IERR) INTEGER GROUP, SIZE, IERR
Определение количества SIZE процессов в группе GROUP.
MPI_GROUP_RANK(GROUP, RANK, IERR) INTEGER GROUP, RANK, IERR
Определение номера процесса RANK В группе GROUP. ЕСЛИ вызвавший процесс не входит в группу GROUP, ТО возвращается значение MPI_UNDEFINED.
MPI_GROUP_TRANSLATE_RANKS(GROUP1, N, RANKS1, GROUP2, RANKS2, IERR) INTEGER GROUP1, N, RANKS1(*), GROUP2, RANKS2(*), IERR
В массиве RANKS2 возвращаются ранги в группе GROUP2 процессов с рангами RANKS 1 в группе GROUP 1. Параметр N задает число процессов, для которых нужно определить ранги.
МРI_GROUP_COMPARE(GROUP1, GROUP2, RESULT, IERR) INTEGER GROUP1, GROUP2, RESULT, IERR
Сравнение групп GROUP l и GROUP 2. Если группы GROUP l и GROUP 2 полностью совпадают, то в параметре RESULT возвращается значение MPI_IDENT. ЕСЛИ группы отличаются только рангами процессов, то возвращается значение MPI_SIMILAR. Иначе возвращается значение MPI_UNEQUAL.
МРI_GROUP_FREE(GROUP, IERR) INTEGER GROUP, IERR
Уничтожение группы GROUP. После выполнения процедуры переменная GROUP принимает значение MPI_GROUP_NULL. Если с этой группой к моменту вызова процедуры уже выполняется какая-то операция, то она будет завершена.
В следующем примере все процессы приложения разбиваются на две непересекающиеся примерно равные группы groupl и group2. При нечетном числе процессов в группе group2 может оказаться на один процесс больше, тогда последний процесс из данной группы не должен обмениваться данными ни с одним процессом из группы groupl. С помощью вызовов процедуры MPI_GROUP_TRANSLATE_RANKS каждый процесс находит процесс с тем же номером в другой группе и обменивается с ним сообщением через коммуникатор mpi_comm_world при помощи вызова процедуры mpi_sendrecv. В конце программы не нужные далее группы уничтожаются с помощью вызовов процедур MPI_GROUP_FREE.
program example16 include 'mpif.h' integer ierr, rank, i, size, size1 integer a(4), b(4) integer status(MPI_STATUS_SIZE) integer group, group1, group2 integer ranks(128), rank1, rank2, rank3 call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_GROUP(MPI_COMM_WORLD, group, ierr) size1 = size/2 do i = 1, size1 ranks(i) = i-1 enddo call MPI_GROUP_INCL(group, size1, ranks, group1, ierr) call MPI_GROUP_EXCL (group, size1, ranks, group2, ierr) call MPI_GROUP_RANK (group1, rank1, ierr) call MPI_GROUP_RANK(group2, rank2, ierr) if (rank1 .eq. MPI_UNDEFINED) then if(rank2 .lt. size1) then call MPI_GROUP_TRANSLATE_RANKS (group1, 1, rank2, & group, гапкЗ, ierr) else гапкЗ = MPI_UNDEFINED end if else call MPI_GROUP_TRANSLATE_RANKS(group2, 1, rank1, & group, гапкЗ, ierr) end if a(1) = rank a(2) = rank1 a(3) = rank2 a(4) = rank3 if (rank3 .ne. MPI UNDEFINED) then call MPI_SENDRECV(a, 4, MPI_INTEGER, rank3, 1, & b, 4, MPI_INTEGER, rank3, 1, & MPI_COMM_WORLD, status, ierr) end if call MPI_GROUP_FREE(group, ierr) call MPI_GROUP_FREE(group1, ierr) call MPI_GROUP_FREE(group2, ierr) print *, 'process ', rank, ' a=', a, ' b=', b call MPI_FINALIZE(ierr) endЛистинг 5.1.