Вычислительный центр им. А.А. Дородницына РАНРаздел виртуального курса
|
|
---|
До настоящего времени в нашем курсе мы полагали, что все процессоры доступны для всех событий обмена сообщениями. Это – результат использования коммуникатора MPI_COMM_WORLD, который включает все процессоры, задействованные в передаче сообщений.
Чтобы ограничивать коммуникацию на подмножество процессоров, программист может создать группу, и связать коммуникатор с этой группой. Новый коммуникатор может использоваться в попарных или коллективных функциях коммуникации. И группы и коммуникаторы - объекты MPI (сохраняемые в системном пространстве), к которым обращаются по маркерам (возвращаемым из функций MPI или посылаемым к ним).
Группа - это упорядоченный набор процессов. Каждый процесс в группе связан с уникальным целочисленным рангом. Ранг принимает значения от нуля до N-1, где N - число процессов в группе.
Коммуникатор – это механизм создания самостоятельного (замкнутого в себе) коммуникационного "мира". Право получить сообщение, отправленное с данным коммуникатором, имеет только процесс, указавший тот же самый коммуникатор.
Коммуникатор включает случай группы и также включает контексты. О контексте можно думать как об уникальном тэге, который назначен системой. Чтобы получить сообщение, оно должно соответствовать контексту и тэгу сообщения. Коммуникатор включает два отдельных контекста: один для попарной коммуникации и один для коллективной коммуникации. Эти операции могут поэтому произойти одновременно в пределах одного коммуникатора, для попарной коммуникации без получения коллективного сообщения, или наоборот.
Коммуникаторы и контексты особенно важны для библиотек. Никто не может гарантировать, что библиотечный разработчик выберет тэг сообщения, который не используется прикладным программистом. Если библиотека создает свой собственный коммуникатор, это дает гарантию уникального контекста и отсутствие вмешательств от других коммуникационных событий.
Есть две дополнительных проблемы, связанные с коммуникаторами, которые пока находятся за границами нашего обсуждения.Во-первых, коммуникатор может кэшировать (припрятать) атрибутную информацию, чтобы сделать переход между последующими вызовами функции. Используя кэшируемые атрибуты осуществляют виртуальные топологии в MPI. Во вторых, в дополнение к внутреним коммуникаторам (обсуждаемым в этом модуле), могут быть созданы внешние коммуникаторы, чтобы разрешить попарную коммуникацию между группами.
MPI включает функции для доступа к информации по группам или коммуникаторам, для того, чтобы создавать новые группы или коммуникаторы из существующих, и для того, чтобы удалять группы или коммуникаторы. Список приведен ниже. Пожалуйста, см. страницы руководства (с помощью программы man в Linux) или стандарт MPI для информации относительно синтаксиса. Команды, которые будут проиллюстрированы позднее в этом модуле и лабораторной работе, отмечены курсивом.
Функции создания коммуникатора являются коллективными. Они требуют, чтобы все процессы во входном коммуникаторе участвовали, и могут требовать коммуникацию среди процессов. Все другие функции группы и коммуникатора являются локальными. Позднее обсудим, что часто имеет смысл для всех членов входной группы иметь запрос функции создания группы, если позже будет создан коммуникатор для такой группы.
В моделях динамики леса рост поперечного разреза области листа определяется количеством доступного света. В некоторых моделях, диффузионный свет в данном пункте сетки зависит от данных в пунктах сетки по кардинальным направлениям (север - N, восток - E, юг - S, запад - W). Рассматрим процессоры, расположенные на 2-мерной сетке, с целью обменять данные среди процессоров, совместно использующих одну и ту же строку, и среди процессоров, совместно использующих один и тот же столбец. Это можно достичь используя группы процессоров.
Предположим, что мы имеем 12 процессоров, расположенных на сетке 3x4, в которой число, указанное в поле есть номер процессора.
Так как данные должны быть обменены среди строк и столбцов процессоров, мы должны создать группу для каждой строки и группу для каждого столбца. Таким образом, в нашем примере, должно быть сгенерировано семь различных групп. Тем не менее, определенный процессор будет принадлежать только двум из этих групп --- одной группе по строке и одной группе по столбцу.
В этом модуле будут продемонстрированы два метода для создания групп в модели динамики леса. Первый метод является наиболее приемлемым в общем случае, но не самым компактным.
Вначале следует отметить, тем не менее, что MPI не обеспечивает механизм формирования групп на пустом месте; они могут быть разработаны только из предварительно определенных групп. Это приводит к очевидному вопросу: Как можно сформировать первую группу? Вы должны начать с основной группы всех процессов (MPI_GROUP_WORLD), которая связана с коммуникатором MPI_COMM_WORLD.
Здесь даны этапы формирования групп первым методом:
Следующий отрывок кода на C показывает как установить группы для строк и столбцов.
#include#include "mpi.h" #define NROW 3 #define NCOL 4 void set_groups(MPI_Comm *, MPI_Comm *); void set_groups(MPI_Comm *row_comm, MPI_Comm *col_comm) { MPI_Group base_grp, grp; MPI_Comm temp_comm; int row_list[NCOL], col_list[NROW], irow, icol, rank_in_world, i, j; /* ------------------------------------------------ Get base group from MPI_COMM_WORLD communicator ------------------------------------------------ */ MPI_Comm_group(MPI_COMM_WORLD,&base_grp); /* ------------------------------------------------------------ Establish the row and column to which this processor belongs ------------------------------------------------------------ */ MPI_Comm_rank(MPI_COMM_WORLD,&rank_in_world); irow = (rank_in_world % NROW); icol = (rank_in_world/NROW); /* ------------------------- Build row groups -------------------------- */ row_list[0] = 0; for (i=1; i max_row) max_row=row_hgt[i]; max_col = col_hgt[1]; for (i=1; i max_col) max_col=col_hgt[i]; printf("%d, %d, %d\n", rank_in_world, max_row, max_col); }
Вы могли бы задаться вопросом, почему каждый процессор вовлечен в создание всех групп,
даже если он принадлежит только двум из них. Это потому, что стандарт MPI утверждает, что запрос
MPI_Comm_create нужно выполнять всем процессам во входном коммуникаторе
(в нашем случае, в MPI_COMM_WORLD
), и что все процессы должны передать
одно и тоже значение в качестве параметра группы (grp
),
даже если они не принадлежат новой группе.
Коммуникаторы группы row_comm
и col_comm
можно использовать множеством способов.
Возвратимся снова к модели динамики леса, в которой каждый процессор вычисляет максимальную
высоту дерева среди деревьев его территории.
Этой информацией следует обменяться со всеми другими процессорами,
совместно использующими как ту же самую строку, так и тот же столбец,
так что в итоге каждый процессор может вычислить максимальную высоту дерева в полной строке и столбце.
Если maxht
--- есть локальный максимум высоты дерева,
то следующий отрывок кода иллюстрирует, как можно определить максимум для столбца и строки:
#include#include "mpi.h" #define NROW 3 #define NCOL 4 int row_hgt[NCOL], col_hgt[NROW], max_row, max_col, maxht; MPI_Allgather(&maxht,1,MPI_INT,&row_hgt,1,MPI_INT,row_comm); MPI_Allgather(&maxht,1,MPI_INT,&col_hgt,1,MPI_INT,col_comm); max_row = row_hgt[0]; for (i = 1; i < NCOL, i++){ if (row_hgt[i] > max_row) max_row = row_hgt[i]; } max_col = col_hgt[0]; for (i = 1; i < NROW, i++){ if (col_hgt[i] > max_col) max_col = col_hgt[i]; }
Для коллективной коммуникации, все процессы в указанном коммуникаторе должны участвовать. Процессы не в коммуникаторе не должны вызывать эту функцию. В приведенном примере все процессы принадлежат правильному row_comm и правильному col_comm, так что все вызывают MPI_Allgather. В некоторых кодах с коллективной коммуникацией требуется использовать условное выражение для проверки членства в группе коммуникатора. В этой ситуации, все процессы могут вызвать MPI_Group_rank, чтобы узнать их ранг в группе. Те процессы, ранг которых равняется MPI_UNDEFINED, не должны вызывать коллективную подпрограмму коммуникации.
Альтернативный подход состоит в том, чтобы использовать функцию MPI_Comm_split, которая разделяет один коммуникатор на множество непересекающихся коммуникаторов. Все манипуляции групп происходят за сценой. Этот подход, вообще говоря, меньше применим, чем использование MPI_Comm_create, но производит более компактный код для регулярных декомпозиционных задач, типа задачи динамики леса.
В функции приведенной ниже, первый вызов MPI_Comm_split
разделяет MPI_COMM_WORLD
на три коммуникатора, соответствующие
трем строкам в сетке 3x4. Один коммуникатор включает все процессы, для которых
color
= 1 (строка 1), другой включает все процессы, для которых
color
= 2 (строка 2), третий включает все процессы, для которых
color
= 3 (строка 3). Внутри новых коммуникаторов процессы
ранжированы в порядке увеличения значения key
(в данном случае, в соответствии с
увеличением ранга в оригинальном коммуникатореMPI_COMM_WORLD
).
#include#include "mpi.h" #define NROW 3 #define NCOL 4 void set_groups(MPI_Comm *, MPI_Comm *); void set_groups(MPI_Comm *row_comm, MPI_Comm *col_comm) { int irow, icol, color, key, rank_in_world; /* ------------------------------------------------------------ Establish the row and column to which this processor belongs ------------------------------------------------------------ */ MPI_Comm_rank(MPI_COMM_WORLD,&rank_in_world); irow = (rank_in_world % NROW); icol = (rank_in_world/NROW); /* ------------------------- Build row communicators -------------------------- */ color = irow; key = rank_in_world; MPI_Comm_split (MPI_COMM_WORLD, color, key, row_comm); /* -------------------------- Build column communicators -------------------------- */ color = icol; MPI_Comm_split (MPI_COMM_WORLD, color, key, col_comm); } main(int argc, char **argv) { MPI_Comm row_comm, col_comm; int row_hgt[NCOL], col_hgt[NROW], max_row, max_col, rank_in_world, maxht,i; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank_in_world); /* --------------------------------------------------------------- A real simulation would calculate a meaning maxht here --------------------------------------------------------------- */ maxht = rank_in_world; set_groups(&row_comm, &col_comm); MPI_Allgather(&maxht,1,MPI_INT,&row_hgt,1,MPI_INT,row_comm); MPI_Allgather(&maxht,1,MPI_INT,&col_hgt,1,MPI_INT,col_comm); max_row = row_hgt[0]; for (i=1; i max_row) max_row=row_hgt[i]; max_col = col_hgt[1]; for (i=1; i max_col) max_col=col_hgt[i]; printf("%d, %d, %d\n", rank_in_world, max_row, max_col); }
Литература
Домашняя страница MPI в Argonne National Labs http://www.mcs.anl.gov/mpi
Message Passing Interface Forum (1995) MPI: A Message Passing Interface Standard. June 12, 1995. Доступен на русском языке в pdf-формате из сайта http://www.cluster.bsu.by/MPI_ALL.htm
© 2003
Вычислительный центр им. А.А.Дородницына
Все права защищены. |
|