无法理解 MPI_Type_create_struct

Posted

技术标签:

【中文标题】无法理解 MPI_Type_create_struct【英文标题】:Trouble Understanding MPI_Type_create_struct 【发布时间】:2016-06-07 07:39:19 【问题描述】:

我 方法。假设我们有一个结构:

   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);

我不确定在此示例中偏移量和块长度的作用。有人能解释一下上面的这两部分吗?

【问题讨论】:

您是否阅读过此函数的手册页或其在 MPI 标准中的定义? 【参考方案1】:

如您所知,MPI_Type_create_struct() 的目的是提供一种方法来创建用户的MPI_Datatypes 映射他的结构化类型。这些新类型随后将可用于 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)

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

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 指向我)您可以(并且应该)使用来自stddef.hoffsetof() 宏,它为您执行此指针运算,将代码简化为 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)

使用它非常简单,因为lbextend 都可以通过直接调用专门用于此目的的函数来检索,即MPI_Type_get_extent()(但实际上,您也可以直接使用0 和@987654355 @)。另外,由于调用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 );

【讨论】:

ANSI C 提供了offsetof 宏(在stddef.h 中),它消除了声明结构类型的虚拟变量并为您执行指针运算的需要。 @HristoIliev 我相应地改进了(希望)答案,谢谢 MPI_Type_get_extent 返回的same 范围调用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)。请澄清。 位移以字节表示,在 C 中你确实可以通过地址&mystruct.c 等来获得。对于也适用于 Fortran 的可移植解决方案,请使用 MPI_Get_address

以上是关于无法理解 MPI_Type_create_struct的主要内容,如果未能解决你的问题,请参考以下文章

无法理解仪器数据

卷曲响应无法理解

ngAfterContentChecked() 无法理解 + 角度 2

我似乎无法理解我的代码有啥问题,我无法获得输出

无法理解这些功能的使用

php会话随机丢失,无法理解为啥