Fortran中堆叠的MPI派生数据类型

时间:2012-12-10 12:50:22

标签: matrix fortran mpi derived-types

MPI2允许我们创建派生数据类型并通过编写

发送它们
call mpi_type_create_indexed_block(size,1,dspl_send,rtype,DerType,ierr)
call mpi_send(data,1,DerType,jRank,20,comm,ierr)

通过执行此操作,MPI库会发送数据(N) dspl_send 位置。

现在,对于矩阵数据(M,N),我们可以通过以下代码发送其位置:

call mpi_type_create_indexed_block(size,M,dspl_send,rtype,DerTypeM,ierr)
call mpi_send(data,1,DerTypeM,jRank,20,comm,ierr)

即发送数据(i,dspl_send(j))条目。

我的问题涉及1在随后的mpi_send中的作用。它一直是1吗?另一种尺寸可能吗? MPI派生的数据类型在互联网上的许多文档中得到了很好的解释,但是发送/接收的大小总是 1 ,如果允许另一个大小,则不提及如何使用它。

如果我们想使用矩阵数据(M,N),其大小M在调用之间变化,那么每当我们调用它时,我们是否需要始终创建派生数据类型?是否无法使用 DerType 发送矩阵数据(M,N)数据(N,M)

2 个答案:

答案 0 :(得分:3)

每个MPI数据类型都有两个属性:大小和范围。大小是数据类型表示的实际字节数,而范围是数据类型在内存中覆盖的字节数。某些数据类型不是连续的,这意味着它们的大小可能小于它们的范围,例如(以伪代码显示)

MPI_TYPE_VECTOR(count = 1,
                blocklength = 10,
                stride = 20,
                oldtype = MPI_INTEGER,
                newtype = newtype)

创建一个数据类型,该数据类型包含总共20个(blocklength)中的前10个(stride)个元素。此数据类型的大小为10的大小MPI_INTEGER,在大多数系统上计为40个字节。它的范围是大多数系统的两倍或80字节。如果count为2,那么它将需要10个元素,然后跳过接下来的10个元素,然后再获取10个元素,再次跳过下一个10个元素。因此它的大小和扩展将是两倍大。

在任何MPI例程中指定某个元素计数时,例如MPI_SEND,MPI做了这样的事情:

  1. 使用源缓冲区参数的地址初始化内部数据缓冲区。
  2. 它查询数据类型类型map以确定要从多少字节开始以及从哪里获取并将它们附加到正在构造的消息中。添加的字节数等于数据类型的 size
  3. 它通过数据类型的范围递增内部数据指针。
  4. 减少内部计数,如果仍为非零,则重复前两步。
  5. MPI的一个很好的特性是数据类型的范围不需要与其大小相匹配(如向量示例中所示),并且甚至可以使用{{1赋予数据类型所需的范围值。 }}。这允许创建非常复杂的数据访问模式。例如,使用MPI_TYPE_CREATE_RESIZED通过不跨越整行(C)或列(Fortran)的块来分散矩阵需要使用此类已调整大小的类型。

    回到矢量示例。是使用MPI_SCATTERV创建矢量类型,然后使用count = 1调用MPI_SEND,还是使用count = 2创建矢量类型,然后使用{{1}调用count = 2最终结果是一样的。通常,构造一个完全描述要发送的对象的数据类型。在这种情况下,会在MPI_SEND的调用中给出count = 1。但有些情况下,创建仅描述对象的一部分的数据类型(例如单个部分)可能更有利,然后调用count = 1并将MPI_SEND设置为部分的数量一个人想发送。有时这是个人偏好的问题,有时候这是算法要求的问题。

    关于你的上一个问题,Fortran按列主要顺序存储矩阵,这意味着MPI_SEND在内存中count旁边而不是data(i,j)。因此,data(i±1,j)由每个data(i,j±1)元素的data(M,N)个连续列向量组成。两个元素之间的距离(例如NM)取决于data(1,1)。这就是你在类型构造函数中提供data(1,2)的原因。具有不同行数的矩阵(例如,不同的M)将不会“适合”所创建类型的类型映射,并且将使用错误的元素来构造消息。

答案 1 :(得分:0)

https://stackoverflow.com/a/13802243/7784768中有关范围的描述并不完全正确,因为范围没有考虑数据类型末尾的填充。 MPI数据类型由typemap:

定义
typemap = ((type_0, disp_0 ), ..., (type_n−1, disp_n−1 ))

然后根据

定义范围
lb = min(disp_j)
ub = max(disp_j + sizeof(type_j)) + e)
extent = ub - lb,

其中e可能因对齐要求而为非零。

这意味着在示例中

MPI_TYPE_VECTOR(count = 1,
                blocklength = 10,
                stride = 20,
                oldtype = MPI_INTEGER,
                newtype = newtype)

count = 1,typemap是

((int, 0), (int, 4), ... (int, 36))

和范围在大多数系统40而不是80(即在这种情况下,步幅对类型图没有影响)。对于count = 2,typemap将是

((int, 0), (int, 4), ... (int, 36), (int, 80), (int, 84), ... (int, 116))

和范围120(对于10个整数的第一个块为40个字节,对于步幅为40个字节,对于10个整数的第二个块为40个字节,但在范围内忽略剩余的步幅)。可以使用MPI_Type_get_extent函数轻松找出范围。

Extent是一个非常棘手的概念,在尝试传递派生数据类型的多个元素时很容易出错。