【问题标题】:MPI - Difference between mpi_type_get_extent and mpi_type_get_true_extentMPI - mpi_type_get_extent 和 mpi_type_get_true_extent 之间的区别
【发布时间】:2018-10-10 10:10:38
【问题描述】:

我在理解mpi_type_get_extent 和mpi_type_get_true_extent 之间的区别时遇到了一些问题。在实践中,我使用的是前者,期待我使用后者获得的结果,所以我检查了MPI 3.1 Standard,在那里我找到了(在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) 和@ 987654337@.

为什么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 x 4 矩阵的一行或一列,因此它们的size 可以预见地总是4;列类型有extent 和true_extent 都等于4 单位,因为它表示内存中的四个连续实数;正如我所料,用mpi_type_vector 创建的类型有extent 和true_extent 都等于13 实数(见漂亮的草图);如果我想将它与count > 1 一起使用,我必须调整它的大小,更改它的extent(并且true_extent 保持不变);现在困难的部分来了:

16 和 extent 是用 mpi_type_create_subarray 创建的类型的什么?老实说,我希望该例程返回一个已经调整大小的类型,准备好与count > 1 一起使用(ie 一个带有size = 4、extent = 1、true_extent = 13 的类型),但似乎不是:令我惊讶的是,extent 是 16,这是全局数组的大小!

问题是:为什么?为什么使用mpi_type_create_subarray 创建的类型的extent 是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

【问题讨论】:

  • (对消失的评论的回答)我没有错误,我只是不明白我对这两个 MPI 工具的理解有什么问题,适用于用户定义的类型,例如创建的一个使用MPI_TYPE_CREATE_SUBARRAY(使用预定义的数据类型,例如MPI_DOUBLE_PRECISION,没有区别)。
  • 您不必回答已删除的 cmets,毕竟我删除它是有原因的……我的意思是错误的结果不同,但无论如何,我删除了评论。您的代码不可直接编译,但必要的声明是可预测的。
  • 关于您的编辑(我再说一遍,我的第一条评论已被删除,所以忘了它),即使是产生一些需要解释的结果的程序通常也需要 MWE,不仅是有错误的程序,而且所有其他程序。无论如何,您的代码可能很好,并且声明是可预测的,这就是我删除评论的原因。
  • 长话短说,MPI_Type_create_subarray() 可能会修改引擎盖下的范围。在 Fortran 中,描述 2D 方阵的列的数据类型以 size==extent 结尾,但描述行的数据类型具有相同的大小,但 extent 是一个元素的大小。
  • @GillesGouaillardet,一个元素的大小是什么意思?据我所读和所见,m by n Fortran 矩阵的一行类型的extent 是1+m*(n-1),这正是我所期望的mpi_type_get_extent 将返回。

标签: memory fortran mpi sub-array


【解决方案1】:

MPI_Type_create_subarray() 创建一个派生数据类型,根据定义,其范围是所有大小的乘积。

定义在 MPI 3.1 标准的第 96 页。

MPI_Type_create_subarray() 通常用于 MPI-IO,所以这个范围的定义在那里是有意义的。

在这种非常特殊的情况下,这可能不是您想要的,但请考虑 4x4 数组的 2x2 子数组。您期望达到什么程度?

【讨论】:

  • 所以它是(ub_marker, size0*ex),eq 的类型映射的最后一个元素。 (4.2),要“负责任”,我理解正确了吗?
  • 是的,这是我的理解
  • 哦,终于!我希望这个问题让你有机会巩固你的知识,因为它帮助我提高了我的知识。顺便说一句,作为数组A的子数组S的数据类型,我希望它的extent等于它的true_extent(这是S的属性,作为A的一部分,它“生活”的地方),或者至少是它的subsize(这将是S的属性),但不是size,它是A的属性。
猜你喜欢
  • 2015-06-04
  • 2013-08-17
  • 2013-10-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 2012-02-04
  • 2021-12-25
  • 2020-05-10
相关资源
最近更新 更多