很难理解MPI_Type_create_struct
我无法理解MPI_Type_create_struct方法。假设我们有一个结构:
I'm having trouble understanding the MPI_Type_create_struct method. Say we have a struct:
struct foo(){
float value;
char rank;
}
和我们想这个结构体发送到另一个进程。求索低于code样品:
And we want to send this struct to another process. Conside the code sample below:
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在这个例子做的。有人能解释一下上面这两个部分?
I'm not sure what offsets and blocklengths do in this example. Can somebody explain these two parts above?
的目的MPI_Type_create_struct()
是,如你所知,提供一种方法来创建用户的 MPI_Datatype 取值映射了结构化类型。这些新类型也将随之成为MPI通信和其他电话只是作为默认类型使用,让举例转移结构数组,你会转移 INT
的阵列相同的方式小号或浮动
秒。
The purpose of MPI_Type_create_struct()
is, as you know, to provide a way to create user's MPI_Datatype
s mapping his structured types. These new types will subsequently be usable for MPI communications and other calls just as the default types, allowing for example to transfer arrays of structures the same way you would transfer arrays of int
s or float
s.
现在让我们来看看函数本身的更多细节。结果
这里是由人返回其简介
命令:
Now let's see the function itself in more details.
Here is its synopsis as returned by the man
command:
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)
让我们来看看输入参数,如果他们的含义要求进一步的解释:
Let's see for the input parameters if their meaning calls for further explanation:
-
计数
:这是很清楚,你的情况,这将是2
-
array_of_types
:好,那会是{MPI_FLOAT,MPI_CHAR}
为您例如 -
array_of_blocklengths
:再次,不多说了。{1,1}
是什么您这里需要 -
array_of_displacements
:这是你必须要更加小心一点的人。它相当于从结构的开始的存储器地址偏移,以便在array_of_types
中列出的每个元素的地址。在你的情况,这将是类似{&安培; f.value - &安培; F,放大器; f.rank - &安培; F}
与˚F
是类型富
。这里最棘手的部分是,因为潜在的对齐限制,你不能肯定,这将是等于{0,sizeof的(浮动)}
(虽然我在这里pretty相信这将是)。因此,在使用地址偏移,如图使得该方法完全可移植的。而且(THX 赫里斯托·伊利耶夫来这对我指指点点),您可以(也应该)使用offsetof从
宏这不正是你的这个指针运算,简化了code到STDDEF.H
(){offsetof(foo,那么值),offsetof(富,排名)}
这看起来更好。
-
count
: this is quite clear, and in your case, that would be2
-
array_of_types
: well, that'd be{ MPI_FLOAT, MPI_CHAR }
for your example -
array_of_blocklengths
: again, not much to say.{ 1, 1 }
is what you need here -
array_of_displacements
: this is the one for which you have to be a bit more careful. It corresponds to the memory address offsets from the start of the structure, to the address of each element listed inarray_of_types
. In your case, that would be something like{ &f.value - &f, &f.rank - &f }
, withf
being of typefoo
. The tricky part here is that, because of potential alignment constraints, you cannot be sure that this will be equal to{ 0, sizeof( float ) }
(although here I'm pretty sure it will be). Therefore, using addresses offsets as shown makes the method fully portable. Moreover (thx Hristo Iliev to pointing it to me) you can (and should) use theoffsetof()
macro fromstddef.h
which does exactly this pointer arithmetic for your, simplifying the code to{ offsetof( foo, value ), offsetof( foo, rank ) }
which looks nicer.
通过初始化这样的参数,调用 MPI_Type_create_struct()
将返回一个新的 MPI_Datatype
,这将适用于发送或接收的有一个 富
的时间。其原因是,这种新类型不考虑该结构的实际程度,包括其字段对齐约束。而你的例子就是在这方面的完美,因为它会(很可能)是空心的。
With the arguments initialised this way, the call to MPI_Type_create_struct()
will return a new MPI_Datatype
, which will be suitable for sending or receiving one foo
at the time. The reason for that is that this new type doesn't take into account the actual extent of the structure, including the alignment constraints for its fields. And you example is perfect in this regards since it will (very likely) be hollow.
这其中的原因是,浮动
活动的一般的32B的对齐约束,而字符
活动没有。因此,第二结构富
主题阵列的的起始地址是不正确的第一个的端部。它是在下一32B对齐的存储器地址。这将使我们的结构的元件的端部之间3个字节的阵列中的下一个的开始的孔
The reason for that is that float
s have in general an alignment constraint of 32b, while char
s have none. Therefore, the starting address of the second structure foo
of an array of theme is not right at the end of the first one. It is at the next 32b-aligned memory address. This will leave us with a hole of 3 Bytes between the end of an element of the structure to the start of the next in the array.
要解决这个问题,你必须调整你的类型与 MPI_Type_create_resized扩展它()
,这是概要如下:
To handle this issue, you'll have to resize your type for extending it with MPI_Type_create_resized()
, which synopsis is as follow:
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)
使用起来还是比较方便既是磅
和延长
可以通过直接调用函数专门意味着检索为此,即 MPI_Type_get_extent()
(但实际上,你也可以直接使用 0
和的sizeof(富)
)。另外,由于用于调用中介键入 MPI_Type_get_extent()
和 MPI_Type_create_resized()
没有在任何实际的使用MPI通信,它并不需要用 MPI_Type_commit()
,致力于饶恕你一些电话和时间。
Using it is quite easy as both lb
and extend
can be retrieved by directly calling a function specifically meant for this purpose, namely MPI_Type_get_extent()
(but actually, you could also directly use 0
and sizeof( foo )
). In addition, since the intermediary type used for calling MPI_Type_get_extent()
and MPI_Type_create_resized()
isn't used in any actual MPI communication, it doesn't need to be committed with MPI_Type_commit()
, sparing you some calls and time.
现在,与您的code变为:
Now, with that, your code becomes:
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 );