具有滑动访问的 MPI 共享内存通信

MPI shared memory communication with slided access

我有两个关于使用 mpi 共享内存通信的问题

1) 如果我有一个 MPI 等级,它是唯一一个写入 window 的等级,是否有必要使用 mpi_win_lock 和 mpi_win_unlock? 我知道我的应用程序永远不会让其他人尝试写入 window。他们只看了window的内容,我保证他们看了MPI_BARRIER之后,所以window的内容已经更新了

2) 在我的应用程序中,我有一个 MPI rank,它分配了一个共享的 window 需要被 1:N 其他 MPI ranks 读取。

MPI 等级 1 只能读取:rma(1:10)

MPI 等级 2 只能读取 rma(11:20)

MPI 等级 N 只能读作 rma(10*(N-1)+1:10*N)

目前1到N的rank都在查询整个共享window,即大小为“10*N”,MPI_WIN_SHARED_QUERY。

我想问是否可以应用 MPI_WIN_SHARED_QUERY 函数,使得 MPI 级别 1 只能从 1:10 访问 window 和从 11:20 访问级别 2等等

这样,每个级别都有一个来自 1:10 的本地访问,但它们指的是共享 window 的不同块?这可能吗?

非常感谢!

更新

基于下面的答案似乎可以满足我的要求。但是在使用 MPI_WIN_SHARED_QUERY

时不起作用

但是,我不明白本地指针是如何自动指向数组的不同部分的。它怎么知道怎么做。您唯一要做的就是使用大小为 nlocal=5 的 c_f_pointer 调用。它怎么知道,例如等级 3 的 rma 必须访问从 16-20 开始的 5 个位置。我真的不清楚,我担心它是否便携,我可以依靠它吗?

首先,我建议使用 MPI_Win_fence 而不是 MPI_Barrier 进行同步 - 这确保了像屏障一样的时间同步,但也确保了 window 上的所有操作都是可见的(例如写入应刷新到内存中)。

如果你使用 MPI_Win_allocate_shared() 那么你会自动实现你想要的 - 每个等级都有一个指向其本地部分的指针。但是,内存是连续的,因此您可以通过 over/under-indexing 数组元素访问所有内存(您可以使用普通的 Fortran 指针指向纯粹由等级 0 分配的数组的一部分,但我认为 MPI_Win_allocate_shared() 更优雅).

这里有一些代码说明了这一点 - 创建了一个共享数组,由 0 级初始化但由所有级读取。

这似乎在我的笔记本电脑上运行良好:

me@laptop:~$ mpirun -n 4 ./rmatest
 Running on            4  processes with n =           20
 Rank            2  in COMM_WORLD is rank            2  in nodecomm on node laptop
 Rank            3  in COMM_WORLD is rank            3  in nodecomm on node laptop
 Rank            0  in COMM_WORLD is rank            0  in nodecomm on node laptop
 Rank            1  in COMM_WORLD is rank            1  in nodecomm on node laptop
 rank, noderank, arr:            0           0           1           2           3           4           5
 rank, noderank, arr:            3           3          16          17          18          19          20
 rank, noderank, arr:            2           2          11          12          13          14          15
 rank, noderank, arr:            1           1           6           7           8           9          10

虽然一般来说这只适用于同一共享内存节点中的所有列。

program rmatest

  use iso_c_binding, only: c_ptr, c_f_pointer

  use mpi

  implicit none

! Set the size of the road

  integer, parameter :: nlocal = 5
  integer :: i, n
  integer, dimension(MPI_STATUS_SIZE) :: status

  integer, pointer, dimension(:) :: rma

  integer :: comm, nodecomm, nodewin
  integer :: ierr, size, rank, nodesize, noderank, nodestringlen
  integer(MPI_ADDRESS_KIND) :: winsize
  integer :: intsize, disp_unit
  character*(MPI_MAX_PROCESSOR_NAME) :: nodename
  type(c_ptr) :: baseptr

  comm = MPI_COMM_WORLD

  call MPI_Init(ierr)

  call MPI_Comm_size(comm, size, ierr)
  call MPI_Comm_rank(comm, rank, ierr)

  ! Create node-local communicator

  call MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, &
                           MPI_INFO_NULL, nodecomm, ierr)

  ! Check it all went as expected

  call MPI_Get_processor_name(nodename, nodestringlen, ierr)
  call MPI_Comm_size(nodecomm, nodesize, ierr)
  call MPI_Comm_rank(nodecomm, noderank, ierr)

  n = nlocal*nodesize

  if (rank == 0) then

     write(*,*) "Running on ", size, " processes with n = ", n

  end if

  write(*,*) "Rank ", rank," in COMM_WORLD is rank ", noderank, &
             " in nodecomm on node ", nodename(1:nodestringlen)

  call MPI_Type_size(MPI_INTEGER, intsize, ierr)

  winsize = nlocal*intsize

  ! displacements counted in units of integers

  disp_unit = intsize

  call MPI_Win_allocate_shared(winsize, disp_unit, &
       MPI_INFO_NULL, nodecomm, baseptr, nodewin, ierr)

  ! coerce baseptr to a Fortran array: global on rank 0, local on others

  if (noderank == 0) then

     call c_f_pointer(baseptr, rma, [n])

  else

     call c_f_pointer(baseptr, rma, [nlocal])

  end if

  ! Set the local arrays

  rma(1:nlocal) = 0

  ! Set values on noderank 0

  call MPI_Win_fence(0, nodewin, ierr)

  if (rank == 0) then
     do i = 1, n
        rma(i) = i
     end do
  end if

  call MPI_Win_fence(0, nodewin, ierr)

  ! Print the values  

  write(*,*) "rank, noderank, arr: ", rank, noderank, (rma(i), i=1,nlocal)

  call MPI_Finalize(ierr)

end program rmatest