Производные типы данных
Производные типы MPI не являются в полном смысле типами данных, как это понимается в языках программирования. Они не могут использоваться ни в каких других операциях, кроме коммуникационных. Производные типы MPI следует понимать как описатели расположения в памяти элементов базовых типов. Производный тип MPI представляет собой скрытый (opaque) объект, который специфицирует две вещи: последовательность базовых типов и последовательность смещений. Последовательность таких пар определяется как отображение (карта) типа: Typemap = {(type0, disp0),..., (typen-1, dispn-1)} Значения смещений не обязательно должны быть неотрицательными, различными и упорядоченными по возрастанию. Отображение типа вместе с базовым адресом начала расположения данных buf определяет коммуникационный буфер обмена. Этот буфер будет содержать n элементов, а i-й элемент будет иметь адрес buf+disp и иметь базовый тип type. Стандартные типы MPI имеют предопределенные отображения типов. Например, MPI_INT имеет отображение {(int,0)}. Использование производного типа в функциях обмена сообщениями можно рассматривать как трафарет, наложенный на область памяти, которая содержит передаваемое или принятое сообщение. Стандартный сценарий определения и использования производных типов включает следующие шаги:
Любой тип данных в MPI имеет две характеристики: протяженность и размер, выраженные в байтах:
Для простых типов протяженность и размер совпадают. Функция MPI_Type_extent определяет протяженность элемента некоторого типа. C: int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent) FORTRAN: MPI_TYPE_EXTENT(DATATYPE, EXTENT, IERROR) INTEGER DATATYPE, EXTENT, IERROR
Функция MPI_Type_size определяет "чистый" размер элемента некоторого типа (за вычетом пустых промежутков). C: int MPI_Type_size(MPI_Datatype datatype, int *size) FORTRAN: MPI_TYPE_SIZE(DATATYPE, SIZE, IERROR) INTEGER DATATYPE, SIZE, IERROR
Как отмечалось выше, для создания производных типов в MPI имеется набор специальных функций-конструкторов. Рассмотрим их в последовательности от простого к сложному. Самый простой конструктор типа MPI_Type_contiguous создает новый тип, элементы которого состоят из указанного числа элементов базового типа, занимающих смежные области памяти. C: int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype) FORTRAN: MPI_TYPE_CONTIGUOUS(COUNT, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, OLDTYPE, NEWTYPE, IERROR
Конструктор типа MPI_Type_vector создает тип, элемент которого представляет собой несколько равноудаленных друг от друга блоков из одинакового числа смежных элементов базового типа. C: int MPI_Type_vector(int count, int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype) FORTRAN: MPI_TYPE_VECTOR(COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR
Функция создает тип newtype, элемент которого состоит из count блоков, каждый из которых содержит одинаковое число blocklength элементов типа oldtype. Шаг stride между началом блока и началом следующего блока всюду одинаков и кратен протяженности представления базового типа. Конструктор типа MPI_Type_hvector расширяет возможности конструктора MPI_Type_vector, позволяя задавать произвольный шаг между началами блоков в байтах. C: int MPI_Type_hvector(int count, int blocklength, MPI_Aint stride, MPI_Datatype oldtype, MPI_Datatype *newtype) FORTRAN: MPI_TYPE_HVECTOR(COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR
Графическая интерпретация работы конструктора MPI_Type_hvector приведена на рис. 14. Рис. 14. Графическая интерпретация работы конструктора 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, 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
Эта функция создает тип newtype, каждый элемент которого состоит из count блоков, где i-ый блок содержит array_of_blocklengths[i] элементов базового типа и смещен от начала размещения элемента нового типа на array_of_displacements[i] элементов базового типа. Конструктор типа 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, 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
Элемент нового типа состоит из count блоков, где i-ый блок содержит array_of_blocklengths[i] элементов старого типа и смещен от начала размещения элемента нового типа на array_of_displacements[i] байт.
Конструктор типа MPI_Type_struct - самый универсальный из всех конструкторов типа. Создаваемый им тип является структурой, состоящей из произвольного числа блоков, каждый из которых может содержать произвольное число элементов одного из базовых типов и может быть смещен на произвольное число байтов от начала размещения структуры. C: int MPI_Type_struct(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype *array_of_types, 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
Функция создает тип newtype, элемент которого состоит из count блоков, где i-ый блок содержит array_of_blocklengths[i] элементов типа array_of_types[i]. Смещение i-ого блока от начала размещения элемента нового типа измеряется в байтах и задается в array_of_displacements[i]. Функция 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. Это не повлияет на выполняющиеся в данный момент коммуникационные операции с этим типом данных и на производные типы, которые ранее были определены через уничтоженный тип. Для определения длины сообщения используются две функции: MPI_Get_count и MPI_Get_elements. Для сообщений из простых типов они возвращают одинаковое число. Подпрограмма MPI_Get_count возвращает число элементов типа datatype, указанного в операции получения. Если получено не целое число элементов, то она возвратит константу MPI_UNDEFINED (функция MPI_Get_count рассматривалась в разделе 3.2, посвященном коммуникационным операциям типа точка-точка). Функция 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
|