Memory MPI-MPI类型获取范围和MPI类型获取范围之间的差异
我在理解Memory MPI-MPI类型获取范围和MPI类型获取范围之间的差异,memory,fortran,mpi,sub-array,Memory,Fortran,Mpi,Sub Array,我在理解mpi\u type\u get\u extent和mpi\u type\u get\u true\u extent之间的区别时遇到了一些问题。实际上,我使用的是前者,期望得到的结果是后者,所以我检查了,我发现(在第4.1.8节数据类型的真实范围) 但是,数据类型范围不能用作 需要分配的空间量,如果用户已修改 范围 这让我认为,只要我没有修改数据类型的范围,我就应该在使用这两个子例程时没有任何区别 但我显然错过了什么 声明了以下MPI派生的数据类型 sizes = [10,10,1
mpi\u type\u get\u extent
和mpi\u type\u get\u true\u extent
之间的区别时遇到了一些问题。实际上,我使用的是前者,期望得到的结果是后者,所以我检查了,我发现(在第4.1.8节数据类型的真实范围)
但是,数据类型范围不能用作
需要分配的空间量,如果用户已修改
范围
这让我认为,只要我没有修改数据类型的范围,我就应该在使用这两个子例程时没有任何区别
但我显然错过了什么
声明了以下MPI派生的数据类型
sizes = [10,10,10]
subsizes = [ 3, 3, 3]
starts = [ 2, 2, 2]
CALL MPI_TYPE_CREATE_SUBARRAY(ndims, sizes, subsizes, starts, MPI_ORDER_FORTRAN, MPI_DOUBLE_PRECISION, newtype, ierr)
下面的代码
call mpi_type_size(newtype, k, ierr)
call mpi_type_get_extent(newtype, lb, extent, ierr)
call mpi_type_get_true_extent(newtype, tlb, textent, ierr)
write(*,*) k/DBS, lb/DBS, extent/DBS, tlb/DBS, textent/DBS ! DBS is the size of double precision
生成输出(显然,所有进程都是相同的)
因此mpi_type_size
的行为与我预期的一样,返回产品(补贴)*DBS
ink
;另一方面,我从mpi_-type_-get_-extent
和mpi_-type_-get_-true_-extent
两个方面都期望只有后者才能返回什么(因为我根本没有修改newtype
),特别是222223
,它们基本上是start(1)+start(2)*大小(1)+start(3)*大小(1)*大小(2)
和1+(补贴-1)*[1,尺寸(1),尺寸(1)*尺寸(2)]
为什么mpi\u type\u获取\u区段
在lb
和区段中返回0
和产品(尺寸)
,而不考虑子系统
和启动
我没有发布MWE,因为我根本没有错误(不是在编译时,也不是在运行时),我根本不知道前面提到的两个例程的工作方式。基本上,我希望有人能帮助我理解标准文档中对这些子程序的描述,以及为什么得到我没有预料到的结果是正确的
编辑
根据@GillesGouaillardet的要求,我在这个问题的末尾添加了一个“最小”的工作示例,该示例将与至少4个进程一起运行(请与4个进程一起运行,以便获得相同的输出)。最后几行可以取消注释(有意识地),以表明表示非连续内存位置的类型在与count>1一起使用时可以正常工作,一旦通过mpi\u type\u create\u resized
正确调整大小后即可正常工作。注释这些行后,程序将为创建的所有类型打印size
,lb
,extent
,true\u lb
,true\u extent
(即使是中间类型,未提交):
所有类型都表示4×4矩阵的一行或一列,因此它们的大小总是可以预测的4
;列类型的extent
和true\u extent
也都等于4
单位,因为它表示内存中的四个连续实数;使用mpi_type_vector
创建的类型具有extent
和true_extent
都等于13
reals,如我所料(请参见尼斯草图);如果我想将其与count>1
一起使用,我必须调整其大小,更改其范围
(并且true\u范围
保持不变);现在最困难的部分来了:
使用mpi\u type\u create\u子数组创建的类型的范围是什么?老实说,我本来希望例程返回一个已经调整大小的类型,可以与count>1
一起使用(即size=4
,extent=1
,true\u extent=13
),但它似乎没有:对我来说,extent
是16
,这是全局数组的大小
问题是:为什么?为什么使用mpi\u type\u create\u subarray
创建的类型的extent
是大小array\u参数的元素的乘积
MPI\u Type\u create\u subarray()
创建一个派生数据类型,根据定义,其范围是所有大小的乘积
定义见MPI 3.1标准第96页
MPI\u Type\u create\u subarray()
通常用于MPI-IO,因此扩展数据块的这种定义在这里是有意义的
在这种非常特殊的情况下,它可能不是您所希望的,但请考虑4x4阵列的2x2子阵列。您期望达到什么程度?(对消失的注释的回答)我没有错误,我只是不理解我对应用于用户定义类型的这两个MPI工具的理解有什么错,例如使用MPI\u type\u CREATE\u子数组创建的MPI工具
(对于预定义的数据类型,例如MPI\u DOUBLE\u PRECISION
,没有区别)。您不必回答已删除的注释,毕竟我删除它是有原因的…我的错误意思是不同的结果,但无论如何,我删除了注释。您的代码不可直接编译,但必要的声明是可预测的。关于您的编辑(我重复,我的第一条注释已删除,所以请忘记它),即使是产生要解释的结果的程序通常也需要一个MWE,不仅仅是有错误的程序,还有所有其他程序。无论如何,您的代码可能很好,声明是可预测的,这就是我删除注释的原因。长话短说,MPI_Type_create_subarray()
可能会修改引擎盖下的范围。在Fortran中,描述二维方阵列的数据类型以size==extent
结尾,但描述行的数据类型大小相同,但extent
是一个元素的大小。@GillesGouaillardet,你所说的一个元素的大小是什么意思?就我读过和写过的而言如图所示,Fortran矩阵表示一行m
的类型的范围是1+m*(n-1)
,这正是我所期望的
27 0 1000 222 223
mpi_type_contiguous 4 0 4 0 4
mpi_type_vector 4 0 13 0 13
mpi_type_vector res 4 0 1 0 13
mpi_type_create_subarray 4 0 16 0 13
mpi_type_create_subarray res 4 0 1 0 13
program subarray
use mpi
implicit none
integer :: i, j, k, ierr, myid, npro, rs, mycol, myrowugly, myrow_vec, myrow_sub
integer(kind = mpi_address_kind) :: lb, extent, tlb, textent
real, dimension(:,:), allocatable :: mat
call mpi_init(ierr)
call mpi_comm_rank(mpi_comm_world, myid, ierr)
call mpi_comm_size(mpi_comm_world, npro, ierr)
allocate(mat(npro,npro))
mat = myid*1.0
call mpi_type_size(mpi_real, rs, ierr)
call mpi_type_contiguous(npro, mpi_real, mycol, ierr)
call mpi_type_commit(mycol, ierr)
call mpi_type_size(mycol, k, ierr)
call mpi_type_get_extent(mycol, lb, extent, ierr)
call mpi_type_get_true_extent(mycol, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_contiguous ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_vector(npro, 1, npro, mpi_real, myrowugly, ierr)
call mpi_type_size(myrowugly, k, ierr)
call mpi_type_get_extent(myrowugly, lb, extent, ierr)
call mpi_type_get_true_extent(myrowugly, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_vector ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_create_resized(myrowugly, int(0, mpi_address_kind)*rs, int(1, mpi_address_kind)*rs, myrow_vec, ierr)
call mpi_type_commit(myrow_vec, ierr)
call mpi_type_size(myrow_vec, k, ierr)
call mpi_type_get_extent(myrow_vec, lb, extent, ierr)
call mpi_type_get_true_extent(myrow_vec, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_vector res ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_create_subarray(2, [npro, npro], [1, npro], [0, 0], mpi_order_fortran, mpi_real, myrowugly, ierr)
call mpi_type_size(myrowugly, k, ierr)
call mpi_type_get_extent(myrowugly, lb, extent, ierr)
call mpi_type_get_true_extent(myrowugly, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_create_subarray ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_create_resized(myrowugly, int(0, mpi_address_kind)*rs, int(1, mpi_address_kind)*rs, myrow_sub, ierr)
call mpi_type_commit(myrow_sub, ierr)
call mpi_type_size(myrow_sub, k, ierr)
call mpi_type_get_extent(myrow_sub, lb, extent, ierr)
call mpi_type_get_true_extent(myrow_sub, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_create_subarray res', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
!if (myid == 0) call mpi_send(mat(1,1), 2, mycol, 1, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_recv(mat(1,3), 2, mycol, 1, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_recv(mat(1,1), 2, mycol, 0, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_send(mat(1,3), 2, mycol, 0, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_send(mat(1,1), 2, myrow_vec, 1, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_recv(mat(3,1), 2, myrow_vec, 1, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_recv(mat(1,1), 2, myrow_vec, 0, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_send(mat(3,1), 2, myrow_vec, 0, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_send(mat(1,1), 2, myrow_sub, 1, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_recv(mat(3,1), 2, myrow_sub, 1, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_recv(mat(1,1), 2, myrow_sub, 0, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_send(mat(3,1), 2, myrow_sub, 0, 666, mpi_comm_world, ierr)
!do i = 0, npro
!if (myid == i) then
!print *, ""
!print *, myid
!do j = 1, npro
!print *, mat(j,:)
!end do
!end if
!call mpi_barrier(mpi_comm_world, ierr)
!end do
call mpi_finalize(ierr)
end program subarray