В MPI-1 реализованы объекты, являющиеся типами данных, которые позволяют пользователям указывать способ размещения данных в памяти. Информация о размещении, однажды помещенная в тип данных, не может быть выделена из типа данных с помощью функций MPI-1. В ряде случаев, однако, хотелось бы иметь доступ к информации о размещении для скрытых объектов -типов данных.
Две функции, представленные в этой секции, используются совместно для расшифровки типов данных, чтобы восстановить последовательность вызовов, использованных для их начального определения. Они могут применяться, чтобы позволить пользователю определить карту и тип сигнатуры типа данных.
MPI_TYPE_GET_ENVELOPE(datatype, num_integers, num_addresses,
num_datatypes, combiner)
IN | datatype |
Тип данных для доступа (указатель) | |
OUT | num_integers |
Количество входных чисел , использованных при вызове конструирующего комбинера (неотрицательное целое) | |
OUT | num_addresses |
Количество входных адресов , использованных при вызове конструирующего комбинера (неотрицательное целое) | |
OUT | num_datatypes |
Количество входных типов данных , использованных при вызове конструирующего комбинера (неотрицательное целое) | |
OUT | combiner |
Комбинер (состояние) |
int MPI_Type_get_envelope(MPI_Datatype datatype,
int *num_integers,
int *num_addresses,
int *num_datatypes,
int *combiner)
MPI_TYPE_GET_ENVELOPE(DATATYPE, NUM_INTEGERS, HUM_ADDRESSES,
NUM_DATATYPES, COMBINER, IERROR)
INTEGER DATATYPE, NUM_INTEGERS, NUM_ADDRESSES,
NUM_DATATYPES, COMBINER, IERROR
void MPI::Datatype::Get_envelope(int& num_integers,
int& num_addresses,
int& num_datatypes,
int& combiner) const
Для заданного типа данных MPI_TYPE_GET_ENVELOPE
возвращает информацию о
количестве и типе входных аргументов, использованных в вызове, который
создал datatype
. Возвращенные значения ``количества аргументов''
могут быть использованы для реализации достаточно больших массивов в
расшифровывающей подпрограмме MPI_TYPE_GET_CONTENTS
. Этот вызов и
значение возвращаемых данных описаны ниже. combiner
отображает
конструктор типа данных MPI, который использовался для создания datatype
.
Объяснение:
По требованию, чтобы combiner
отобразил конструктор, использованный при
создании datatype
, получается расшифрованная информация, которая
может использоваться для эффективного восстановления последовательности
вызовов, использованных при первоначальном создании. Способность извлечь
первоначальную последовательность конструкторов считается достаточно
полезной для реализаций с ограниченными ресурсами, в которых
оптимизируется внутреннее представление типов данных для того, чтобы также
помнить первоначальную последовательность конструкторов.
Расшифрованная информация включает данные о дублировании типов данных. Это важно, так как есть потребность отличать предопределенный тип данных от копии этого типа. Первый - зто постоянный объект, который не может быть освобожден, в то время как последний - это производный тип данных, который может быть освобожден.
Совет пользователям: Расшифровка и затем повторная шифровка типов данных не обязательно дадут точную копию. Кэшированная информация не восстанавливается подобным механизмом. Это должно быть скопирована другими методами (принимая во внимание все известные ключи). Функция дублирования типа данных из раздела 1-3.4.1 может использоваться для получения точной копии первоначального типа данных.
Таблица 6.1 содержит значения, которые могут быть возвращены в combiner
,
слева и связанные с ними вызовы справа.
Если combiner
- это MPI_COMBINER_NAMED
, то datatype
- это
имя предопределенного типа данных.
Для вызовов с адресами в качестве аргументов, иногда нужно отличать: вызов
использовал целочисленный или адресный аргумент. Например, есть
два комбинера для hvector
:
MPI_COMBINER_HVECTOR_INTEGER
и MPI_COMBINER_HVECTOR
. Первый используется, если был вызов
MPI-1 из ФОРТРАНa, а второй - если был вызов MPI-1 из Си или
С++. Однако, в системах, где MPI_ADDRESS_KIND
=
MPI_INTEGER_KIND
(то есть, где целочисленные и адресные параметры
совпадают) комбинер MPI_COMBINER_HVECTOR
может быть возвращен для
типа данных, построенного вызовом MPI_TYPE_HVECTOR
из ФОРТРАНa. Точно
так же, MPI_COMBINER_HINDEXED
может быть возвращен для типа, построенного
вызовом MPI_TYPE_HINDEXED
из ФОРТРАНa, а MPI_COMBINER_STRUCT
может быть возвращен для типа данных, сконструированного вызовом
MPI_TYPE_STRUCT
из ФОРТРАНa.
Для подобных систем не требуется отличать конструкторы, которые принимают
адресные аргументы, от конструкторов, принимающих целочисленные аргументы,
так как они совпадают. Все новые MPI-2 вызовы используют адресные
аргументы.
MPI_COMBINER_NAMED |
именованный предопределенный тип | |
MPI_COMBINER_DUP |
MPI_TYPE_DUP |
|
MPI_COMBINER_CONTIGUOUS |
MPI_TYPE_CONTIGUOUS |
|
MPI_COMBINER_VECTOR |
MPI_TYPE_VECTOR |
|
MPI_COMBINER_HVECTOR_INTEGER |
MPI_TYPE_HVECTOR из ФОРТРАНa |
|
MPI_COMBINER_HVECTOR |
MPI_TYPE_HVECTOR из Си или С++
и в некоторых случаях ФОРТРАНa, или же
MPI_TYPE_CREATE_HVECTOR |
|
MPI_COMBINER_INDEXED |
MPI_TYPE_INDEXED |
|
MPI_COMBINER_HINDEXED_INTEGER |
MPI_TYPE_HINDEXED из ФОРТРАНa |
|
MPI_COMBINER_HINDEXED |
MPI_TYPE_HINDEXED из Си или С++
и в некоторых случаях ФОРТРАНa, или же
MPI_TYPE_CREATE_HINDEXED |
|
MPI_COMBINER_INDEXED_BLOCK |
MPI_TYPE_CREATE_INDEXED_BLOCK |
|
MPI_COMBINER_STRUCT_INTEGER |
MPI_TYPE_STRUCT из ФОРТРАНa |
|
MPI_COMBINER_STRUCT |
MPI_TYPE_STRUCT из Си или С++
и в некоторых случаях ФОРТРАНa, или же
MPI_TYPE_CREATE_STRUCT |
|
MPI_COMBINER_SUBARRAY |
MPI_TYPE_CREATE_SUBARRAY |
|
MPI_COMBINER_DARRAY |
MPI_TYPE_CREATE_DARRAY |
|
MPI_COMBINER_F90_REAL |
MPI_TYPE_CREATE_F90_REAL |
|
MPI_COMBINER_F90_COMPLEX |
MPI_TYPE_CREATE_F90_COMPLEX |
|
MPI_COMBINER_F90_INTEGER |
MPI_TYPE_CREATE_F90_INTEGER |
|
MPI_COMBINER_RESIZED |
MPI_TYPE_CREATE_RESIZED |
Объяснение:
Чтобы воссоздать первоначальный вызов, важно знать, была ли адресная
информация усечена. Вызовы MPI-1 из ФОРТРАНa для нескольких
подпрограмм могут являться усекающими субъектами в случае, когда заданная по
умолчанию длина INTEGER
меньше, чем размер адреса.
Фактические аргументы, использованные при вызове для создания datatype
,
можут быть получены с помощью вызова:
MPI_TYPE_GET_CONTENTS(datatype, max_integers,
max_addresses, max_datatypes,
array_of_integers, array_of_addresses,
array_of_datatypes)
IN | datatype |
Тип данных для доступа (указатель) | |
IN | num_integers |
Количество элементов в массиве array_of_integers (неотрицательное целое) |
|
IN | num_addresses |
Количество элементов в массиве array_of_addresses (неотрицательное целое) |
|
IN | num_datatypes |
Количество элементов в массиве array_of_datatypes (неотрицательное целое) |
|
OUT | array_of_integers |
Содержит целочисленные аргументы, использованные при конструировании datatype (массив целых чисел) |
|
OUT | array_of_addresses |
Содержит адресные аргументы, использованные при конструировании datatype (массив целых чисел) |
|
OUT | array_of_datatypes |
Содержит аргументы-типы данных, использованные при конструировании datatype (массив указателей) |
int MPI_Type_get_contents(MPI_Datatype datatype, int max_integers,
int max_addresses, int max_datatypes,
int *array_of_integers,
MPI_Aint *array_of_addresses,
MPIJDatatype *array_of_datatypes)
MPI_TYPE_GET_CONTENTS(DATATYPE, MAX_INTEGERS, MAX_ADDRESSES,
MAX_DATATYPES, ARRAY_OF_INTEGERS, ARRAY_OF_ADDRESSES,
ARRAY_OF_DATATYPES, IERROR)
INTEGER DATATYPE, MAX_INTEGERS, MAX_ADDRESSES,
MAX_DATATYPES, ARRAY_OF_INTEGERS (*), ARRAY_OF_DATATYPES (*),
IERROR
INTEGER(KIND=MPI_ADDRESS_KIND) ARRAY_OF_ADDRESSES (*)
void MPI::Datatype::Get_contents(int max_integers, int max_addresses,
int max_datatypes, int array_of_integers[],
MPI::Aint array_of_addresses[],
MPI::Datatype array_of_datatypes[]) const
datatype
должен быть предопределенным неименованным или производным
типом данных; вызов ошибочен, если datatype
является предопределенным
именованным типом данных.
Значения, присвоенные max_integers
, max_addresses
, и max_datatypes
должны
быть по крайней мере такого же размера, как и значение,
возвращенное в num_integers
, num_addresses
, и num_datatypes
,
соответственно, при вызове MPI_TYPE_GET_ENVELOPE
с тем же самым аргументом
datatype
.
Объяснение:
Аргументы max_integers
, max_addresses
, и max_datatypes
подвержены
проверке на ошибки в вызове. Это происходит аналогично для
аргументов в топологии подпрограмм MPI-1.
Типы данных, возвращенные в array_of_datatypes
- это указатели на
объеткы-типы данных, которые эквивалентны типам данных, использованным в
первоначальном конструирующем запросе. Если они были производными
типами данных, то возвращенные типы данных являются новыми
объектами-типами данных, и пользователь ответственен за их освобождение с
помощью MPI_TYPE_FREE
. Если они были предопределенными типами данных, то
возвращенный тип данных эквивалентен предопределенному и не может быть
освобожден.
Переданное состояние возвращенных производных типов данных неопределено; то есть типы данных могут или не могут быть переданными. Кроме того, и содержимое атрибутов возвращаемых типов данных неопределено.
Обратите внимание на то, что MPI_TYPE_GET_CONTENTS
может быть
вызван с аргументом datatype
, который был сконструирован с
использованием MPI_TYPE_CREATE_F90_REAL
,
MPI_TYPE_CREATE_F90_INTEGER
или MPI_TYPE_CREATE_F90_COMPLEX
(неименованный предопреде-
ленный тип данных). В таком случае,
возвращается пустой array_of_datatypes
.
Объяснение: Определение эквивалентности типов данных подразумевает, что предопределенные типы данных равны. При потребности в одинаковых указателях для именованных предопределенных типов данных возможно использование операторов сравнения = = или .EQ. для определения вызываемого типа данных. []
Совет разработчикам:
Типы данных, возвращенные в array_of_datatypes
, должны представляться
пользователю так, как будто каждый из них - эквивалентная копия типа
данных, использованного в конструирующем тип вызове. Сделано ли это при
создании нового типа данных, или с помощью другого механизма, подобного
механизму подсчета ссылок, это не требует выполнения, пока семантика
сохраняется.[]
Объяснение:
Переданное состояние и атрибуты возвращенного типа данных
преднамеренно
оставлены неопределенными. Тип данных, используемый в первоначальной
конструкции, возможно, был изменен с тех пор, когда он использовался при вызове
конструктора. Атрибуты могут быть добавлены, удалены или модифицированы так же
успешно, как факт передачи типа данных. Семантика позволяет реализации
подсчитывать ссылки без требования отслеживать эти изменения. []
Для MPI-1 вызовов конструкторов типов данных, аргументы-адреса в
ФОРТРАНe имеют тип INTEGER
. В новых вызовах MPI-2
аргументы-адреса имеют тип INTEGER(KIND=MPI_ADDRESS_KIND)
. Вызов
MPI_TYPE_GET_CONTENTS
возвращает все адреса аргументом типа
INTEGER(KIND=MPI_ADDRESS_KIND)
. Это достоверно, даже если были
использованы старые вызовы MPI-1. Таким образом, о расположении
возвращенных значений можно судить по тому, как происходит связывание при
возвратах в Си. Расположение также может быть определено исследованием
новых вызовов MPI-2 в отношении к конструкторам типов данных
обсуждаемых запросов MPI-1, которые включают адреса.
Объяснение:
При наличии всех аргументов-адресов, возвращенных аргументом
array_of_addresses
, результат расшифровки типа данных на Си и
ФОРТРАНe будет получен в этом же аргументе. Полагают, что целое число
типа INTEGER(KIND=MPI_ADDRESS_KIND)
будет по крайней мере также
велико, как и INTEGER
аргумент, использованный при конструировании
типа данных старыми запросами MPI-1, так что никакой потери
информации не произойдет.
Далее приводятся определения значений, которые помещаются в каждое поле
возвращаемых массивов в зависимости от конструктора, используемого для
типа данных. Также указаны необходимые размеры массивов, которые являются
значениями, возвращаемыми MPI_TYPE_GET_ENVELOPE
. На ФОРТРАНe были
сделаны следующие запросы:
INTEGER LARGE
PARAMETER (LARGE = 1000)
INTEGER TYPE, NI, NA, ND, COMBINER, I(LARGE), D(LARGE), IERROR
INTEGER(KIND=MPI_ADDRESS_KIND) A(LARGE)
! КОНСТРУИРОВАНИЕ ТИПА DATATYPE (НЕ ПОКАЗАНО)
CALL MPI_TYPE_GET_ENVELOPE(TYPE, NI, NA, ND, COMBINER, IERROR)
IF ((N1 .GT. LARGE) .OR. (NA .GT. LARGE) .OR. &
(ND .GT. LARGE)) THEN
WRITE (*, *) "NI, NA, OR ND = ", N1, NA, ND, &
" RETURNED BY MPI_TYPE_GET_ENVELOPE IS LARGER THAN LARGE = ", &
LARGE
CALL MPI_ABORT(MPI_COMM_WORLD, 99, IERROR)
ENDIF
CALL MPI_TYPE_GET_CONTENTS(TYPE, NI, NA, ND, I, A, D, IERROR)
Вариант аналогичного вызова на Си:
#define LARGE 1000
int ni, na, nd, combiner, i[LARGE];
MPI_Aint a[LARGE];
MPI_Datatype type, d[LARGE];
/* конструирование типа datatype (не показано) */
MPI_Type_get_envelope(type, ftni, &na, &nd, &combiner);
if ((ni > LARGE) || (na > LARGE) || (nd > LARGE)) {
fprintf (stderr,
"ni, na, or nd = %d %d %d returned by ",
ni, na, nd);
fprintf(stderr,
"MPI_Type_get_envelope is larger than LARGE = %d\n",
LARGE);
MPI_Abort(MPI_COMM_WORLD, 99);
}
MPI_Type_get_contents(type, ni, na, nd, i, a, d);
Код на С++ аналогичен приведенному выше коду на Си, с теми же
возвращаемыми значениями. В описаниях, которые следуют ниже, используются
имя аргументов из символов нижнего регистра. Если комбинер - это
MPI_COMBINER_NAMED
, то ошибочно вызывать
MPI_TYPE_GET_CONTENTS
.
Если комбинер - это MPI_COMBINER_DUP
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
oldtype | d[0] | D[1] |
и ni=0
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_CONTIGUOUS
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
oldtype |
d[0] | D[1] |
и ni=1
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_VECTOR
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
blocklength |
i[1] | I[2] | |
stride |
i[2] | I[3] | |
oldtype |
d[0] | D[1] |
и ni=3
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_HVECTOR_INTEGER
или
MPI_COMBINER_HVECTOR
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
blocklength |
i[1] | I[2] | |
stride |
a[0] | A[1] | |
oldtype |
d[0] | D[1] |
и ni=2
, na=1
, nd=1
.
Если комбинер - это MPI_COMBINER_INDEXED
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
array_of_blocklengths |
от i[1] до i[i[0]] | от I(2) до I(I(1) + 1) | |
array_of_displacements |
от i[i[0]+1] до i[2*i[0]] | от I(I(l) + 2) до I(2*I(1) + 1) | |
oldtype |
d[0] | D[1] |
и ni=2*count+l
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_INDEXED_INTEGER
или
MPI_COMBINER_INDEXED
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
array_of_blocklengths |
от i[1] до i[i[0]] | от I(2) до I(I(1) + 1) | |
array_of_displacements |
от a[0] до a[i[0] - 1] | от A(1) до A(I(1)) | |
oldtype |
d[0] | D[1] |
и ni=count+l
, na=count
, nd=1
.
Если комбинер - это MPI_COMBINER_INDEXED_BLOCK
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
blocklength |
i[1] | I(2) | |
array_of_displacements |
от i[2] до i[i[0] + 1] | от I(3) до I(I(1) + 2) | |
oldtype |
d[0] | D(1) |
и ni=count+2
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_STRUCT_INTEGER
или
MPI_COMBINER_STRUCT
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
count |
i[0] | I[1] | |
array_of_blocklengths |
от i[1] до i[i[0]] | от I(2) до I(I(1) + 1) | |
array_of_displacements |
от a[0] до a[i[0] - 1] | от A(1) до A(I(1)) | |
array_of_types |
от d[0] до d[i[0] - 1] | от D(1) до D(I(1)) |
и ni=count+1
, na=count
, nd=count
.
Если комбинер - это MPI_COMBINER_STRUCT_INTEGER
или
MPI_COMBINER_STRUCT
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
ndims |
i[0] | I[1] | |
array_of_sizes |
от i[1] до i[i[0]] | от I(2) до I(I(1) + 1) | |
array_of_subsizes |
от i[i[0] + l] до i[2*i[0]] | от I(I(l) + 2) до I(2*I(1) + 1) | |
array_of_starts |
от i[2*i[0] + l] до i[3*i[0]] | от I(2*I(l) + 2) до I(3*I(1) + 1) | |
order |
i[3*i[0] | I(3*I(l) + 2) | |
oldtype |
d[0] | D(1) |
и ni=3*ndims+2
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_DARRAY
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
size |
i[0] | I[1] | |
rank |
i[1] | I[2] | |
ndims |
i[2] | I[3] | |
array_of_gsizes |
от i[3] до i[i[2] + 2] | от I(4) до I(I(3) + 3) | |
array_of_distribs |
от i[i[2] + 3] до i[2*i[2]+2] | от I(I(3) + 4) до I(2*I(3) + 3) | |
array_of_dargs |
от i[2*i[2] + 3] до i[3*i[2] + 2] | от I(2*I(3) + 4) до I(3*I(3) + 3) | |
array_of_psizes |
от i[3*i[2] + 3] до i[4*i[2] + 2] | от I(3*I(3) + 4) до I(4*I(3) + 3) | |
order |
i[4*i[2] + 3] | I(4*I(3) + 4) | |
oldtype |
d[0] | D(1) |
и ni=4*ndims+4
, na=0
, nd=1
.
Если комбинер - это MPI_COMBINER_F90_REAL
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
p |
i[0] | I[1] | |
r |
i[1] | I[2] |
и ni=2
, na=0
, nd=0
.
Если комбинер - это MPI_COMBINER_F90_COMPLEX
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
p |
i[0] | I[1] | |
r |
i[1] | I[2] |
и ni=2
, na=0
, nd=0
.
Если комбинер - это MPI_COMBINER_F90_INTEGER
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
r |
i[0] | I[1] |
и ni=1
, na=0
, nd=0
.
Если комбинер - это MPI_COMBINER_RESIZED
, то
Аргумент конструктора | Расположение для Си и С++ | Расположение для ФОРТРАНa | |
lb |
a[0] | A[1] | |
extent |
a[1] | A[2] | |
oldtype |
d[0] | D[1] |
и ni=0
, na=2
, nd=1
.
Пример 6.2.
Этот пример показывает, как можно расшифровать тип данных. Подпрограмма
printdatatype
выводит элементы типа данных. Обратите внимание, что
используется MPI_Type_free
для типов данных, которые не
предопределены.
/*
* Пример расшифровки типа данных. Возвращается 0, если тип данных
* предопределен, и 1, в противном случае.
*/
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
int printdatatype(MPI_Datatype datatype) {
int *array_of_ints;
MPI_Aint *array_of_adds;
MPI_Datatype *array_of_dtypes;
int num_ints, num_adds, num_dtypes, combiner; int i;
MPI_Type_get_envelope(datatype, &num_ints, &num_adds,
&num_dtypes, ftcombiner);
switch(combiner) {
case MPI_COMBINER_NAMED:
printf( "Datatype is named:" );
/* В принципе, вывод здесь может быть организован
по разному. Можно применяться MPI_TYPE_GET_NAME,
если предпочтительно использовать имена, которые
пользовать мог изменить.
*/
if (datatype == MPI_INT) {
printf( "MPI_INT\n" );
} else if (datatype == MPI_DOUBLE) {
printf("MPI_DOUBLE\n" );
} else if (...) {
...
} else {
test for other types ...
}
return 0;
break;
case MPI_COMBINER_STRUCT:
case MPI_COMBINER_STRUCT_INTEGER:
printf("Datatype is struct containing");
array_of_ints = (int *)malloc(num_ints * sizeof(int));
array_of_adds =
(MPI_Aint *)malloc(num_adds * sizeof(MPI_Aint));
array_of_dtypes = (MPI_Datatype *)
malloc(num_dtypes * sizeof(MPI_Datatype));
MPI_Type_get_contents(datatype, num_ints, num_adds,
num_dtypes, array_of_ints,
array_of_adds, array_of_dtypes);
printf ("%d datatypes: \n", array_of _ints [0]);
for (i=0; i<array_of_ints[0]; i++) {
printf("blocklength %d, displacement %ld, type:\n",
array_of_ints[i+1], array_of_adds[i]);
if (printdatatype(array_of_dtypes[i])) {
/* Обратите внимание, что тип тип освобождается */
/* ТОЛЬКО если он не предопределен */
MPI_Type_free(&array_of_dtypes[i]);
}
}
free(array_of_ints);
free(array_of_adds);
free(array_of_dtypes);
break;
. . . другие величины комбинера . . .
default :
printf( "Unrecognized combiner type\n" );
}
return 1;
}