无法理解MPI_Type_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); 

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

正如您所知, MPI_Type_create_struct()的目的是提供一种创建用户MPI_Datatype映射其结构化类型的方法。 这些新类型随后可用作MPI通信和其他调用,就像默认类型一样,例如,允许传输结构数组的方式与传输intfloat 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 :嗯,你的例子就是{ 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 ) }看起来更好的{ offsetof( foo, value ), offsetof( foo, rank ) }

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

原因是float通常具有32b的对齐约束,而char则没有。 因此,主题数组的第二结构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() (但实际上,您也可以直接使用0sizeof( foo ) )。 此外,由于用于调用MPI_Type_get_extent()MPI_Type_create_resized()的中间类型未在任何实际MPI通信中使用,因此不需要使用MPI_Type_commit()提交, 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 );