MPI 3 共享内存和缓存冲突

MPI 3 shared memory and cache conflicts

当使用 MPI 3 共享内存时,我想到在不同任务上同时写入共享内存的相邻内存位置 window 似乎不起作用。

我猜想 MPI 忽略了可能的缓存冲突,现在我的问题是这是否正确并且 MPI 确实不关心缓存一致性,或者这是实现的一个怪癖,或者是否有完全不同的解释那种行为?

这是一个最小的例子,在 Fortran 中,同时写入共享内存中的不同地址 window 会导致冲突(使用英特尔 MPI 2017、2018、2019 和 GNU OpenMPI 3 进行测试)。

program testAlloc
use mpi
use, intrinsic :: ISO_C_BINDING, only: c_ptr, c_f_pointer
implicit none

integer :: ierr
integer :: window
integer(kind=MPI_Address_kind) :: wsize
type(c_ptr) :: baseptr
integer, pointer :: f_ptr
integer :: comm_rank

call MPI_Init(ierr)

! Each processor allocates one entry
wsize = 1
call MPI_WIN_ALLOCATE_SHARED(wsize,4,MPI_INFO_NULL,MPI_COMM_WORLD,baseptr,window,ierr)

! Convert to a fortran pointer
call c_f_pointer(baseptr, f_ptr)

! Now, assign some value simultaneously
f_ptr = 4

! For output, get the mpi rank
call mpi_comm_rank(MPI_COMM_WORLD, comm_rank, ierr)

! Output the assigned value - only one task reports 4, the others report junk
print *, "On task", comm_rank, "value is", f_ptr

call MPI_Win_free(window, ierr)
call MPI_Finalize(ierr)
end program

奇怪的是,C 中的同一个程序似乎确实按预期工作,这导致了一个问题,如果 Fortran 实现有问题,或者 C 程序只是幸运(使用相同的 MPI 库测试)

#include <mpi.h>
#include <stdio.h>

int main(int argc, char *argv[]){
  MPI_Init(&argc, &argv);
  // Allocate a single resource per task
  MPI_Aint wsize = 1;

  // Do a shared allocation
  int *resource;
  MPI_Win window;
  MPI_Win_allocate_shared(wsize, sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &resource, &window);

  // For output clarification, get the mpi rank
  int comm_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);

  // Assign some value
  *resource = 4;  

  // Tell us the value - this seems to work
  printf("On task %d the value is %d\n",comm_rank,*resource);

  MPI_Win_free(&window);
  MPI_Finalize();
}

来自 MPI 3.1 标准(第 11.2.3 章第 407 页)

MPI_WIN_ALLOCATE_SHARED(size, disp_unit, info, comm, baseptr, win)

IN size size of local window in bytes (non-negative integer)

请注意 window 大小以 字节为单位 而不是单位数。

所以你只需要使用

wsize = 4

在 Fortran 中(假设您的 INTEGER 大小确实是 4)和

wsize = sizeof(int);

C

FWIW

  • 即使 C 版本在大多数时候似乎给出了预期的结果,它也是不正确的,我可以通过 运行 在调试器下的程序下证明这一点。
  • 一般来说,您可能必须在 C 中声明 volatile int * resource; 以防止编译器执行一些可能影响您的应用程序行为的优化(此处不需要这样做)。