book
.pdf
|
131 |
OUT newtype |
– новый производный тип данных. |
Графическая интерпретация работы конструктора MPI_Type_hvector приведена на рис. 10.3.
Рис. 10.3. Графическая интерпретация работы конструктора
MPI_Type_hvector.
Конструктор типа MPI_Type_indexed является более универсальным конструктором по сравнению с MPI_Type_vector, так как элементы создаваемого типа состоят из произвольных по длине блоков с произвольным смещением блоков от начала размещения элемента. Смещения измеряются в элементах старого типа.
C:
int MPI_Type_indexed(int count, int *array_of_blocklengths,
int *array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype)
FORTRAN:
MPI_TYPE_INDEXED(COUNT, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*),
ARRAY_OF_DISPLACEMENTS(*), OLDTYPE, NEWTYPE, IERROR
IN |
count |
– число блоков; |
IN |
array_of_blocklengths – массив, содержащий число элементов |
|
|
|
базового типа в каждом блоке; |
IN |
array_of_displacements – массив смещений каждого блока от |
|
|
|
начала размещения элемента нового типа, |
|
|
смещения измеряются числом элементов |
|
|
базового типа; |
IN |
oldtype |
– базовый тип данных; |
OUT newtype |
– новый производный тип данных. |
Эта функция создает тип newtype, каждый элемент которого состоит из count блоков, где i-ый блок содержит array_of_blocklengths[i]
элементов базового типа и смещен от начала размещения элемента нового типа на array_of_displacements[i] элементов базового типа.
132
Графическая интерпретация работы конструктора MPI_Type_indexed приведена на рис. 10.4.
Рис. 10.4. Графическая интерпретация работы конструктора
MPI_Type_indexed.
Конструктор типа MPI_Type_hindexed идентичен конструктору MPI_Type_indexed за исключением того, что смещения измеряются в байтах.
C:
int MPI_Type_hindexed(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements,
MPI_Datatype oldtype, MPI_Datatype *newtype)
FORTRAN:
MPI_TYPE_HINDEXED(COUNT, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*),
ARRAY_OF_DISPLACEMENTS(*), OLDTYPE, NEWTYPE, IERROR
IN |
count |
– число блоков; |
IN |
array_of_blocklengths |
– массив, содержащий число элементов |
|
|
базового типа в каждом блоке; |
IN |
array_of_displacements |
– массив смещений каждого блока от |
|
|
начала размещения элемента нового |
|
|
типа, смещения измеряются в байтах; |
IN |
oldtype |
– базовый тип данных; |
OUT newtype |
– новый производный тип данных. |
Элемент нового типа состоит из count блоков, где i-ый блок содержит array_of_blocklengths[i] элементов старого типа и смещен от начала размещения элемента нового типа на array_of_displacements[i] байт. Графическая интерпретация работы конструктора MPI_Type_hindexed приведена на рис. 10.5.
133
Рис. 10.5. Графическая интерпретация работы конструктора
MPI_Type_hindexed.
Конструктор типа MPI_Type_struct – самый универсальный из всех конструкторов типа. Создаваемый им тип является структурой, состоящей из произвольного числа блоков, каждый из которых может содержать произвольное число элементов одного из базовых типов и может быть смещен на произвольное число байтов от начала размещения структуры.
C:
int MPI_Type_struct(int count, int *array_of_blocklengths,
MPI_Aint *array_of_displacements, MPI_Datatype *array_of_types, MPI_Datatype *newtype)
FORTRAN:
MPI_TYPE_STRUCT(COUNT, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, ARRAY_OF_TYPES, NEWTYPE, IERROR)
INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*), ARRAY_OF_DISPLACEMENTS(*), ARRAY_OF_TYPES(*), NEWTYPE, IERROR
IN |
count |
– число блоков; |
IN |
array_of_blocklength |
– массив, содержащий число элементов |
|
|
одного из базовых типов в каждом |
|
|
блоке; |
IN |
array_of_displacements |
– массив смещений каждого блока от |
|
|
начала размещения структуры, |
|
|
смещения измеряются в байтах; |
IN |
array_of_types |
– массив, содержащий тип элементов в |
|
|
каждом блоке; |
OUT newtype |
– новый производный тип данных. |
Функция создает тип newtype, элемент которого состоит из count блоков, где i-ый блок содержит array_of_blocklengths[i] элементов типа
134
array_of_types[i]. Смещение i-ого блока от начала размещения элемента нового типа измеряется в байтах и задается в array_of_displacements[i]. Графическая интерпретация работы конструктора MPI_Type_struct приведена на рис. 10.6.
Рис. 10.6. Графическая интерпретация работы конструктора
MPI_Type_struct.
Функция MPI_Type_commit регистрирует созданный производный тип. Только после регистрации новый тип может использоваться в коммуникационных операциях.
C:
int MPI_Type_commit(MPI_Datatype *datatype)
FORTRAN:
MPI_TYPE_COMMIT(DATATYPE, IERROR) INTEGER DATATYPE, IERROR
INOUT datatype – новый производный тип данных.
Функция MPI_Type_free уничтожает описатель производного
типа.
C:
int MPI_Type_free(MPI_Datatype *datatype)
FORTRAN:
MPI_TYPE_FREE(DATATYPE, IERROR) INTEGER DATATYPE, IERROR
INOUT datatype – уничтожаемый производный тип.
Функция MPI_Type_free устанавливает описатель типа в состояние MPI_DATATYPE_NULL. Это не повлияет на выполняющиеся в данный момент коммуникационные операции с этим типом данных и на производные типы, которые ранее были определены через уничтоженный тип.
135
Для определения длины сообщения используются две функции: MPI_Get_count и MPI_Get_elements. Для сообщений из простых типов они возвращают одинаковое число. Подпрограмма MPI_Get_count возвращает число элементов типа datatype, указанного в операции получения. Если получено не целое число элементов, то она возвратит константу MPI_UNDEFINED (функция MPI_Get_count рассматривалась в главе 8, посвященной коммуникационным операциям типа точка-точка).
Функция MPI_Get_elements возвращает число элементов простых типов, содержащихся в сообщении.
C:
int MPI_Get_elements(MPI_Status *status, MPI_Datatype datatype, int *count)
FORTRAN:
MPI_GET_ELEMENTS(STATUS, DATATYPE, COUNT, IERROR) INTEGER STATUS(MPI_STATUS_SIZE), DATATYPE, COUNT, IERROR
IN |
status |
– статус сообщения; |
IN |
datatype |
– тип элементов сообщения; |
OUT count |
– число элементов простых типов, содержащихся в |
|
|
|
сообщении. |
10.2. Передача упакованных данных
Функция MPI_Pack упаковывает элементы предопределенного или производного типа MPI, помещая их побайтное представление в выходной буфер.
C:
int MPI_Pack(void* inbuf, int incount, MPI_Datatype datatype, void *outbuf, int outsize, int *position, MPI_Comm comm)
FORTRAN:
MPI_PACK(INBUF, INCOUNT, DATATYPE, OUTBUF, OUTSIZE, POSITION, COMM, IERROR)
<type> INBUF(*), OUTBUF(*)
INTEGER INCOUNT, DATATYPE, OUTSIZE, POSITION, COMM, IERROR
INOUT inbuf |
– адрес начала области памяти с элементами, которые |
|
|
|
требуется упаковать; |
IN |
incount |
– число упаковываемых элементов; |
|
|
136 |
IN |
datatype |
– тип упаковываемых элементов; |
OUT |
outbuf |
– адрес начала выходного буфера для упакованных |
|
|
данных; |
IN |
outsize |
– размер выходного буфера в байтах; |
INOUT position – текущая позиция в выходном буфере в байтах; IN comm – коммуникатор.
Функция MPI_Pack упаковывает incount элементов типа datatype из области памяти с начальным адресом inbuf. Результат упаковки помещается в выходной буфер с начальным адресом outbuf и размером outsize байт. Параметр position указывает текущую позицию в байтах, начиная с которой будут размещаться упакованные данные. На выходе из подпрограммы значение position увеличивается на число упакованных байт, указывая на первый свободный байт. Параметр comm при последующей посылке упакованного сообщения будет использован как коммуникатор.
Функция MPI_Unpack извлекает заданное число элементов некоторого типа из побайтного представления элементов во входном массиве.
C:
int MPI_Unpack(void* inbuf, int insize, int *position, void *outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm)
FORTRAN:
MPI_UNPACK(INBUF, INSIZE, POSITION, OUTBUF, OUTCOUNT, DATATYPE, COMM, IERROR)
<type> INBUF(*), OUTBUF(*)
INTEGER INSIZE, POSITION, OUTCOUNT, DATATYPE, COMM, IERROR
IN |
inbuf |
– адрес начала входного буфера с упакованными |
|
|
данными; |
IN |
insize |
– размер входного буфера в байтах; |
INOUT position – текущая позиция во входном буфере в байтах;
OUT |
outbuf |
– адрес начала области памяти для размещения |
|
|
распакованных элементов; |
IN |
outcount– число извлекаемых элементов; |
|
IN |
datatype – тип извлекаемых элементов; |
|
IN |
comm |
– коммуникатор. |
137
Функция MPI_Unpack извлекает outcount элементов типа datatype из побайтного представления элементов в массиве inbuf, начиная с адреса position. После возврата из функции параметр position увеличивается на размер распакованного сообщения. Результат распаковки помещается в область памяти с начальным адресом outbuf.
Для посылки элементов разного типа из нескольких областей памяти их следует предварительно запаковать в один массив, последовательно обращаясь к функции упаковки MPI_Pack. При первом вызове функции упаковки параметр position, как правило, устанавливается в 0, чтобы упакованное представление размещалось с начала буфера. Для непрерывного заполнения буфера необходимо в каждом последующем вызове использовать значение параметра position, полученное из предыдущего вызова.
Упакованный буфер пересылается любыми коммуникационными операциями с указанием типа MPI_PACKED и коммуникатора comm, который использовался при обращениях к функции MPI_Pack.
Полученное упакованное сообщение распаковывается в различные массивы или переменные. Это реализуется последовательными вызовами функции распаковки MPI_Unpack с указанием числа элементов, которое следует извлечь при каждом вызове, и с передачей значения position, возвращенного предыдущим вызовом. При первом вызове функции параметр position следует установить в 0. В общем случае, при первом обращении должно быть установлено то значение параметра position, которое было использовано при первом обращении к функции упаковки данных. Очевидно, что для правильной распаковки данных очередность извлечения данных должна быть той же самой, как и упаковки.
Функция MPI_Pack_size помогает определить размер буфера, необходимый для упаковки некоторого количества данных типа datatype.
138
C:
int MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *size)
FORTRAN:
MPI_PACK_SIZE(INCOUNT, DATATYPE, COMM, SIZE, IERROR) INTEGER INCOUNT, DATATYPE, COMM, SIZE, IERROR
IN |
incount |
– число элементов, подлежащих упаковке; |
IN |
datatype |
– тип элементов, подлежащих упаковке; |
IN |
comm |
– коммуникатор; |
OUT size |
– размер сообщения в байтах после его упаковки. |
Первые три параметра функции MPI_Pack_size такие же, как у функции MPI_Pack. После обращения к функции параметр size будет содержать размер сообщения в байтах после его упаковки.
Рассмотрим пример рассылки разнотипных данных из 0-го процесса с использованием функций MPI_Pack и MPI_Unpack.
char buff[100]; double x, y;
int position, a[2];
{
MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (myrank == 0)
{ /* Упаковка данных*/ position = 0;
MPI_Pack(&x, 1, MPI_DOUBLE, buff, 100, &position, MPI_COMM_WORLD);
MPI_Pack(&y, 1, MPI_DOUBLE, buff, 100, &position, MPI_COMM_WORLD);
MPI_Pack(a, 2, MPI_INT, buff, 100, &position, MPI_COMM_WORLD);
}
/* Рассылка упакованного сообщения */
MPI_Bcast(buff, position, MPI_PACKED, 0, MPI_COMM_WORLD); /* Распаковка сообщения во всех процессах */
if (myrank != 0) position = 0;
MPI_Unpack(buff, 100, &position, &x, 1, MPI_DOUBLE, MPI_COMM_WORLD);
MPI_Unpack(buff, 100, &position, &y, 1, MPI_DOUBLE, MPI_COMM_WORLD);
MPI_Unpack(buff, 100, &position, a, 2, MPI_INT, MPI_COMM_WORLD);
139
Глава 11.
РАБОТА С ГРУППАМИ И КОММУНИКАТОРАМИ
11.1. Определение основных понятий
Часто в приложениях возникает потребность ограничить область коммуникаций некоторым набором процессов, которые составляют подмножество исходного набора. Для выполнения каких-либо коллективных операций внутри этого подмножества из них должна быть сформирована своя область связи, описываемая своим коммуникатором. Для решения таких задач MPI поддерживает два взаимосвязанных механизма. Во-первых, имеется набор функций для работы с группами процессов как упорядоченными множествами, и, во-вторых, набор функций для работы с коммуникаторами для создания новых коммуникаторов как описателей новых областей связи.
Группа представляет собой упорядоченное множество процессов. Каждый процесс идентифицируется переменной целого типа. Идентификаторы процессов образуют непрерывный ряд, начинающийся с 0. В MPI вводится специальный тип данных MPI_Group и набор функций для работы с переменными и константами этого типа. Существует две
предопределенных группы: |
|
MPI_GROUP_EMPTY |
– группа, не содержащая ни одного процесса; |
MPI_GROUP_NULL |
– значение, возвращаемое в случае, |
|
когда группа не может быть создана. |
Созданная группа не может быть модифицирована (расширена или усечена), может быть только создана новая группа. Интересно отметить, что при инициализации MPI не создается группы, соответствующей коммуникатору MPI_COMM_WORLD. Она должна создаваться специальной функцией явным образом.
Коммуникатор представляет собой скрытый объект с некоторым набором атрибутов, а также правилами его создания, использования и уничтожения. Коммуникатор описывает некоторую область связи. Одной и
140
той же области связи может соответствовать несколько коммуникаторов, но даже в этом случае они не являются тождественными и не могут участвовать во взаимном обмене сообщениями. Если данные посылаются через один коммуникатор, процесс-получатель может получить их только через тот же самый коммуникатор.
В MPI существует два типа коммуникаторов:
intracommunicator – описывает область связи некоторой группы процессов;
intercommunicator – служит для связи между процессами двух различных групп.
Тип коммуникатора можно определить с помощью специальной
функции MPI_Comm_test_inter.
С:
MPI_Comm_test_inter(MPI_Comm comm, int *flag)
FORTRAN:
MPI_COMM_TEST_INTER(COMM, FLAG, IERROR) INTEGER COMM, IERROR
LOGICAL FLAG
IN comm |
– коммуникатор; |
OUT flag |
– возвращает true, если comm – intercommunicator. |
Функция возвращает значение "истина", если коммуникатор является inter коммуникатором.
При инициализации MPI создается два предопределенных
коммуникатора: |
|
MPI_COMM_WORLD |
– описывает область связи, содержащую все |
|
процессы; |
MPI_COMM_SELF |
– описывает область связи, состоящую из |
|
одного процесса. |
11.2. Функции работы с группами
Функция определения числа процессов в группе MPI_Group_size
С:
MPI_Group_size(MPI_Group group, int *size)
FORTRAN:
MPI_GROUP_SIZE(GROUP, SIZE, IERROR) INTEGER GROUP, SIZE, IERROR