0

我将 MPI 等级分开以计算数组的不同部分,然后我想将这些切片放置/发送到不参与计算的不同等级上。该等级是新通信器的主人,该通信器设置为对数组执行其他操作(平均、IO 等)。我让它与 MPI_isend 和 MPI_irecv 一起工作,现在我想尝试 MPI_Put。

use mpi_f08
use iso_c_binding
implicit none

integer, parameter :: n=10, gps = 18, pes=12, dpes = 6 
integer :: main=pes, d=dpes
integer :: diag_master
integer :: global_size, global_rank, diag_size, diag_rank
type(MPI_comm),allocatable :: diag_comm
integer :: pelist_diag
TYPE(MPI_Win) :: win
integer :: ierr, i, j
type(MPI_COMM) :: comm, mycomm
integer :: gsz, grk
integer :: lsz, lrk
integer(KIND=MPI_ADDRESS_KIND) :: local_group
logical :: local_flag
integer :: color,key
!!! THIS IS THE ARRAY
real, dimension(n,pes) :: r
!!! 
logical :: on_dpes = .false.
logical,allocatable,dimension(:) :: dpes_list ! true if on dpes list
integer :: comm_manager
integer :: dmg
integer(KIND=MPI_ADDRESS_KIND) :: buff_size !< the size of a variable type
integer(kind=MPI_ADDRESS_KIND) :: displacement 
integer :: disp_size
integer :: loc_base
integer, pointer :: fptr
!!!!!!!! THIS ALL WORKS BEGIN !!!!!!!!
comm=MPI_COMM_WORLD

   call MPI_INIT(ierr)
 call MPI_COMM_SIZE(COMM, gsz, ierr) 
 call MPI_COMM_RANK(COMM, grk, ierr)

 allocate(dpes_list(gsz))
!     write (6,*) "I am ",grk," of ",gsz
     !> Find the group
 call MPI_COMM_GET_ATTR(COMM,MPI_APPNUM,local_group,local_flag,ierr)
!> Split a new communicator as mycom
 color = int(local_group)
 key = 0
 call MPI_COMM_SPLIT(COMM, color, key, mycomm, ierr)
!> Get information about the split communicators
 call mpi_comm_size(mycomm,lsz,ierr)
 call mpi_comm_rank(mycomm,lrk,ierr)
!> Create data on the main communicator
 if (lsz == pes) then
  comm_manager = main
  on_dpes = .false.
     r = 0.0
     if (mod(lrk,2) == 0) then
          c_loop: do concurrent (i=1:n)
               r(i,lrk+1) = sin(real(i))+real(i)
          enddo c_loop
     else
         r(:,lrk+1) = 10.0-dble(lrk)
     endif
 if (lsz == dpes) then
  diag_size = lsz
  diag_rank = lrk
  comm_manager = d
  on_dpes = .true.
  diag_comm = mycomm
     if (lrk==0) then
          dmg = grk
     endif
 endif
  call MPI_ALLGATHER(on_dpes,1,MPI_LOGICAL, &
               dpes_list,gsz,MPI_LOGICAL, MPI_COMM_WORLD, ierr)
!> Get the master of dpes
 do i=1,gsz
     if (dpes_list(i)) then
          dmg = i-1
          exit
     endif
 enddo
 diag_master = dmg
 diag_global_master = dmg
!!!!!!!! THIS ALL WORKS END !!!!!!!!
!! At this point, the ranks that participate in the calculation 
!! have values in r(i,lrk+1) where lrk is their rank
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!! THIS IS WHERE THINGS GO WRONG? !!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 disp_size = storage_size(r)
 buff_size = disp_size*size(r)
 call c_f_pointer(c_loc(r(1,1)),fptr)
 loc_base = fptr
 nullify(fptr)
 write (6,*) loc_base, grk 
 call MPI_Win_create(loc_base,buff_size,disp_size,MPI_INFO_NULL,&
                     mpi_comm_world,win,ierr)
 call MPI_Win_Fence(0,win,ierr)

displacement = loc_base + disp_size *buff_size

! if (.not.allocated(diag_comm)) then
 if (grk == 11) then
     call MPI_Put(r(:,global_rank+1),size(r,1),MPI_FLOAT,&
          diag_master,displacement,size(r,1), MPI_FLOAT, win ,ierr)
 endif

   call MPI_Win_Fence(0,win,ierr)
   CALL MPI_WIN_FREE(win, ierr)
   call MPI_FINALIZE(ierr)

我已经! if (.not.allocated(diag_comm)) then注释掉了,因为我尝试对所有计算 r 的排名进行此操作,但我得到了相同的结果。我在我的 Makefile 中编译mpiifort -O0 -fpe0 -init=snan,arrays -no-wrap-margin -traceback -stand f18和运行。mpirun -n 12 ./$@.x : -n 6 ./$@.x我正在使用的 mpiifort 版本是

> mpiifort -v
mpiifort for the Intel(R) MPI Library 2019 Update 2 for Linux*
Copyright 2003-2019, Intel Corporation.
ifort version 19.0.2.187

输出 ( write (6,*) loc_base, grk) 很奇怪。

  1072411986           0
           0           1
           0           2
           0           3
           0           4
           0           5
           0           6
           0           7
           0           8
           0           9
           0          10
           0          11
  2142952877          12
  2142952877          13
  2142952877          14
  2142952877          15
  2142952877          16
  2142952877          17

排名 12-17 是不参与“计算 r”的排名,但我不确定为什么c_loc(r(1,1))这些排名不同。此外,等级 0 也不同。

我的实际问题是

1)如何计算displacement变量?我做得对吗?等级之间是否应该有所不同,因为在这种情况下会有所不同?

2) 为什么c_loc(r(1,1))12-17 的排名不同?这与这是一个 SPMD 程序有关吗?为什么等级 0 不同?

3)我可以与所有队伍进行单向沟通而不是只与一个队伍沟通吗?我让每个等级调用 mpi_isend,然后当我以另一种方式执行此操作时,我只是在所有等级发送中循环调用 mpi_irecv。我可以用 MPI_Put 做类似的事情吗?我应该使用 MPI_Get 吗?还有什么?

4)我如何让它工作?这只是我自己的一个教育例子,而我真正需要做的事情要复杂得多。

4

1 回答 1

2

我至少可以回答第 2 项。你有:

call c_f_pointer(c_loc(r(1,1)),fptr) loc_base = fptr

whereloc_base被声明为整数。您似乎假设这loc_base是某种地址,但事实并非如此。在 Fortran 中,来自指针的内在赋值分配的是目标的值,而不是目标的位置。因此,您实际上是在执行loc_baseTRANSFER的 REAL 值r- 可能不是您想要的。

于 2020-01-02T17:55:19.873 回答