Проблема с пониманием типа MPI create struct
у меня возникли проблемы с пониманием метода MPI_Type_create_struct. Скажем, у нас есть структура:
struct foo(){
float value;
char rank;
}
и мы хотим отправить эту структуру в другой процесс. Рассмотрим пример кода ниже:
int count = 2; //number of elements in struct
MPI_Aint offsets[count] = {0, 8};
int blocklengths[count] = {1, 1};
MPI_Datatype types[count] = {MPI_FLOAT, MPI_CHAR};
MPI_Datatype my_mpi_type;
MPI_Type_create_struct(count, blocklengths, offsets, types, &my_mpi_type);
Я не уверен, что зачеты и blocklengths сделать в этом примере. Может кто-нибудь объяснить эти две части выше?
1 ответов
цель MPI_Type_create_struct()
- это, как вы знаете, чтобы обеспечить способ создания отображение его структурированных типов. Эти новые типы впоследствии будут использоваться для связи MPI и других вызовов так же, как типы по умолчанию, позволяя, например, передавать массивы структур так же, как вы бы передать массивы int
или float
s.
теперь давайте посмотрим на саму функцию более подробно.
Вот его синопсис, возвращенный man
команда:
NAME
MPI_Type_create_struct - Create an MPI datatype from a general set of
datatypes, displacements, and block sizes
SYNOPSIS
int MPI_Type_create_struct(int count,
const int array_of_blocklengths[],
const MPI_Aint array_of_displacements[],
const MPI_Datatype array_of_types[],
MPI_Datatype *newtype)
INPUT PARAMETERS
count - number of blocks (integer) --- also number of entries
in arrays array_of_types, array_of_displacements and
array_of_blocklengths
array_of_blocklengths
- number of elements in each block (array of integer)
array_of_displacements
- byte displacement of each block (array of address integer)
array_of_types
- type of elements in each block (array of handles to datatype
objects)
OUTPUT PARAMETERS
newtype - new datatype (handle)
давайте посмотрим для входных параметров, если их значение требует дальнейшего объяснения:
-
count
: это совершенно ясно, и в вашем случае это было бы2
-
array_of_types
: ну, это было бы -
array_of_blocklengths
: опять же, не так много сказать.{ 1, 1 }
это то, что вам нужно здесь -
array_of_displacements
: это тот, для которого вы должны быть немного более осторожны. Это соответствует смещение адреса памяти от начала структуры до адреса каждого элемента, указанного вarray_of_types
. В вашем случае это было бы что-то вроде{ &f.value - &f, &f.rank - &f }
Сf
типfoo
. Сложная часть здесь заключается в том, что из-за потенциальных ограничений выравнивания вы не можете быть уверены, что это будет равно{ 0, sizeof( float ) }
(хотя здесь я уверен, что это будет). Поэтому использование смещений адресов, как показано, делает метод полностью переносимым. Более того (thx Христо Илиев чтобы указать на меня), вы можете (и должны) использоватьoffsetof()
макросstddef.h
который делает именно эту арифметику указателя для вашего, упрощая код до{ offsetof( foo, value ), offsetof( foo, rank ) }
что выглядит лучше.
с аргументами, инициализированными таким образом, вызов MPI_Type_create_struct()
возвращает новый MPI_Datatype
, который будет подходить для отправки или получения один foo
в то время. Причина этого заключается в том, что этот новый тип не учитывает фактический размер структура, включая ограничения выравнивания для ее полей. И ваш пример идеален в этом отношении, так как он (очень вероятно) будет пустым.
причина в том, что float
s имеют в целом ограничение выравнивания 32b, в то время как char
у s нет. Следовательно, начальный адрес второй структуры foo
массива темы не является правильным в конце первого. Он находится на следующем 32B-выровненном адресе памяти. Это оставит нас с отверстием 3 байта между концом элемента структуры и началом следующего в массиве.
чтобы справиться с этой проблемой, вам придется изменить размер вашего типа для его расширения с помощью MPI_Type_create_resized()
, синопсис которого выглядит следующим образом:
NAME
MPI_Type_create_resized - Create a datatype with a new lower bound
and extent from an existing datatype
SYNOPSIS
int MPI_Type_create_resized(MPI_Datatype oldtype,
MPI_Aint lb,
MPI_Aint extent,
MPI_Datatype *newtype)
INPUT PARAMETERS
oldtype - input datatype (handle)
lb - new lower bound of datatype (address integer)
extent - new extent of datatype (address integer)
OUTPUT PARAMETERS
newtype - output datatype (handle)
используя его довольно легко, как оба lb
и extend
может быть получен путем прямого вызова функции, специально предназначенной для этой цели, а именно MPI_Type_get_extent()
(но на самом деле, вы могли бы также использовать 0
и sizeof( foo )
). Кроме того, поскольку тип посредника, используемый для вызова MPI_Type_get_extent()
и MPI_Type_create_resized()
не используется в какой-либо фактической связи MPI, это не должно быть совершено с MPI_Type_commit()
, избавляя вас от некоторых звонков и времени.
теперь, с этим, ваш код становится:
int count = 2;
int array_of_blocklengths[] = { 1, 1 };
MPI_Aint array_of_displacements[] = { offsetof( foo, value ),
offsetof( foo, rank ) };
MPI_Datatype array_of_types[] = { MPI_FLOAT, MPI_CHAR };
MPI_Datatype tmp_type, my_mpi_type;
MPI_Aint lb, extent;
MPI_Type_create_struct( count, array_of_blocklengths, array_of_displacements,
array_of_types, &tmp_type );
MPI_Type_get_extent( tmp_type, &lb, &extent );
MPI_Type_create_resized( tmp_type, lb, extent, &my_mpi_type );
MPI_Type_commit( &my_mpi_type );