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;
以防止编译器执行一些可能影响您的应用程序行为的优化(此处不需要这样做)。
当使用 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;
以防止编译器执行一些可能影响您的应用程序行为的优化(此处不需要这样做)。