Вычислительный центр им. А.А. Дородницына РАН    

Раздел виртуального курса
Параллельное программирование в интерфейсе MPI


Управление группами и коммуникаторами в MPI


Содержание

  1. Обзор
  2. Функции MPI
  3. Динамическая модель леса
    3.1 Проблема
    3.2 Этапы программирования
    3.3 Код
    3.4 Альтернативный подход

Литература


1. Обзор

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

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

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

Коммуникатор – это механизм создания самостоятельного (замкнутого в себе) коммуникационного "мира". Право получить сообщение, отправленное с данным коммуникатором, имеет только процесс, указавший тот же самый коммуникатор.

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

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

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


2. Функции MPI

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

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

Средства доступа группы
MPI_Group_size возвращает число процессов в группе
MPI_Group_rank возвращает ранг вызываемого процесса в группе
MPI_Group_translate_ranks переводит (транслирует) ранги процессов в одной группе к процессам в другой группе
MPI_Group_compare сравнивает членов группы и порядок группы
Конструкторы Группы
MPI_Comm_group возвращает группу, связанную с коммуникатором
MPI_Group_union создает группу, комбинируя две группы
MPI_Group_intersection создает группу изт пересечения двух групп
MPI_Group_difference создает группу из разницы (различия) между двумя группами
MPI_Group_incl creates a group from listed members of an existing group
MPI_Group_excl создает группу из перечисленных членов существующей группы
MPI_Group_range_incl создает группу по первому рангу, шагу, последнему рангу
MPI_Group_range_excl создает группу посредством удаления по первому рангу, шагу, последнему рангу
Деструкторы (разрушители) группы
MPI_Group_free отмечает группу для освобождения
Средства доступа коммуникатора
MPI_Comm_size возвращает число процессов в группе коммуникатора
MPI_Comm_rank возвращает ранг вызываемого процесса в группе коммуникатора
MPI_Comm_compare сравнивает два коммуникатора
Конструкторы коммуникатора
MPI_Comm_dup дублирует коммуникатор
MPI_Comm_create создает новый коммуникатор для группы
MPI_Comm_split разбивает коммуникатор на множество непересекающихся коммуникаторов
Деструкторы (разрушители) коммуникатора
MPI_Comm_free отмечает коммуникатор для освобождения


3. Динамическая модель леса

3.1 Проблема

В моделях динамики леса рост поперечного разреза области листа определяется количеством доступного света. В некоторых моделях, диффузионный свет в данном пункте сетки зависит от данных в пунктах сетки по кардинальным направлениям (север - N, восток - E, юг - S, запад - W). Рассматрим процессоры, расположенные на 2-мерной сетке, с целью обменять данные среди процессоров, совместно использующих одну и ту же строку, и среди процессоров, совместно использующих один и тот же столбец. Это можно достичь используя группы процессоров.

Предположим, что мы имеем 12 процессоров, расположенных на сетке 3x4, в которой число, указанное в поле есть номер процессора.

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


3.2 Этапы программирования

В этом модуле будут продемонстрированы два метода для создания групп в модели динамики леса. Первый метод является наиболее приемлемым в общем случае, но не самым компактным.

Вначале следует отметить, тем не менее, что MPI не обеспечивает механизм формирования групп на пустом месте; они могут быть разработаны только из предварительно определенных групп. Это приводит к очевидному вопросу: Как можно сформировать первую группу? Вы должны начать с основной группы всех процессов (MPI_GROUP_WORLD), которая связана с коммуникатором MPI_COMM_WORLD.

Здесь даны этапы формирования групп первым методом:

  1. Обратитесь к основной группе всех процессов через вызов MPI_Comm_group
  2. Создайте новую группы через вызов MPI_Group_incl
  3. Создайте коммуникатор для новой группы через вызов MPI_Comm_create
Последний этап существенен, так как все события коммуникации в пределах группы активизированы коммуникатором группы, а не объектом группы непосредственно.


3.3 Код

Следующий отрывок кода на 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, не должны вызывать коллективную подпрограмму коммуникации.


3.4 Альтернативный подход

Альтернативный подход состоит в том, чтобы использовать функцию 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 Вычислительный центр им. А.А.Дородницына Все права защищены.
Прочтите наше Copyright руководство.