无法理解MPI_Type_create_struct

VMA*_*A92 12 c struct mpi

我无法理解MPI_Type_create_struct方法.假设我们有一个结构:

   struct foo(){
       float value;
       char rank;
   }
Run Code Online (Sandbox Code Playgroud)

我们希望将此结构发送到另一个进程.考虑下面的代码示例:

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);
Run Code Online (Sandbox Code Playgroud)

我不确定在这个例子中做什么偏移和块长度.有人可以解释上面这两部分吗?

Gil*_*les 14

MPI_Type_create_struct()如您所知,目的是提供一种创建用户MPI_Datatype映射其结构化类型的方法.这些新类型随后可用作MPI通信和其他调用,就像默认类型一样,例如允许以与传输ints或floats 数组相同的方式传输结构数组.

现在让我们更详细地看一下函数本身.
以下是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)
Run Code Online (Sandbox Code Playgroud)

让我们看看输入参数是否需要进一步解释:

  • count:这很清楚,在你的情况下,那就是 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作为类型foo.这里棘手的部分是,由于潜在的对齐约束,你不能确定这是否相等{ 0, sizeof( float ) }(虽然在这里我很确定它会是).因此,如图所示使用地址偏移使得该方法完全可移植.此外(Hristo Iliev指向我)你可以(而且应该)使用offsetof()宏来stddef.h完成这个指针算法,简化{ offsetof( foo, value ), offsetof( foo, rank ) }看起来更好的代码.

通过这种方式初始化参数,调用MPI_Type_create_struct()将返回一个新的MPI_Datatype,这将适合于当时发送或接收一个 foo.原因是这种新类型没有考虑结构的实际范围,包括其字段的对齐约束.你的例子在这方面是完美的,因为它(很可能)是空心的.

原因是floats通常具有32b的对齐约束,而chars没有.因此,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)
Run Code Online (Sandbox Code Playgroud)

使用它,是很容易既lbextend可以通过直接调用专门意味着这个目的,即函数检索MPI_Type_get_extent()(但实际上,你也可以直接使用0sizeof( 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 );
Run Code Online (Sandbox Code Playgroud)

  • 使用“MPI_Type_get_extent”返回的**相同**范围调用“MPI_Type_create_resized”有什么意义?它似乎等同于简单的“extent=extent”。相反,调用“MPI_Type_create_resized(tmp_type, 0, sizeof(foo), &my_mpi_type);”看起来完全合理,因为“MPI_Type_get_extent”返回的“extent”可能与“sizeof(foo)”不同,而实际范围应该不同是“sizeof(foo)”。请澄清。 (2认同)