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)?
答案 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做了这样的事情:
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)
个连续列向量组成。两个元素之间的距离(例如N
和M
)取决于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是一个非常棘手的概念,在尝试传递派生数据类型的多个元素时很容易出错。