在理解mpi_type_get_extent和mpi_type_get_true_extent之间的区别时,我遇到了一些问题。在实践中,我使用的是前者,期望使用后者获得的结果,所以我检查了MPI 3.1标准,在这里我找到了(在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生成输出(显然对所有进程都是相同的)
27 0 1000 222 223因此,mpi_type_size的行为与我所期望的一样,在k中返回PRODUCT(subsizes)*DBS;另一方面,我希望从mpi_type_get_extent和mpi_type_get_true_extent中都能得到什么,后者只返回什么(因为我根本没有修改newtype ),特别是222 223,基本上是starts(1) + starts(2)*sizes(1) + starts(3)*sizes(1)*sizes(2)和1 + (subsizes - 1)*[1, sizes(1), sizes(1)*sizes(2)]。
为什么mpi_type_get_extent会在lb和extent中返回0和PRODUCT(sizes),而不管subsizes和starts
我没有发布MWE,因为我根本没有错误(编译时和运行时都没有),我根本就没有前面提到的两个例程的工作方式。基本上,我希望有人能帮助我理解标准文档中对这些子例程的描述,以及为什么得到那些我没有预料到的结果是正确的。
按照@GillesGouaillardet的请求,编辑,我在这个问题的末尾添加了一个“最小”工作示例,以便在中运行至少4个进程(请使用精确的4个进程运行它,以便我们有相同的输出)。最后一行可以取消注释(有意识地),以表明表示非连续内存位置的类型在与count > 1和一起使用时工作正常,一旦它们通过mpi_type_create_resized适当地调整了大小。在对这些行进行注释后,程序为创建的所有类型(即使是中间类型,未提交)打印size、lb、extent、true_lb、true_extent:
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所有类型都表示4×4矩阵的一行或列,因此它们的size总是4;列类型的extent和true_extent都等于4单位,因为它表示内存中的四个连续区域;使用mpi_type_vector创建的类型都有extent和true_extent,这两个值都等于13区域(见很好的草图);如果我想将它与count > 1一起使用,我必须调整它的大小,更改它的extent (和d51保持不变);现在硬部分出现了:
用16创建的extent类型的extent是什么?老实说,我原以为这个例程会返回一个已经调整大小的类型,可以与count > 1一起使用(例如,一个带有size = 4、extent = 1、true_extent = 13的类型),但看起来并不是这样:对我来说,extent就是16,它是全局数组的大小!
问题是:为什么?为什么用extent创建的类型的mpi_type_create_subarray是array_of_sizes参数元素的乘积?

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发布于 2018-05-01 11:16:50
MPI_Type_create_subarray()创建一个派生数据类型,其范围(按定义)是所有大小的乘积。
定义在MPI 3.1标准的第96页。
MPI_Type_create_subarray()通常用于MPI,所以这个范围的定义是有意义的。
在这个非常特殊的情况下,这可能不是您想要的,但是可以考虑4x4数组的2x2子数组。你期望在多大程度上?
https://stackoverflow.com/questions/50098398
复制相似问题