and*_*epd 5 c++ parallel-processing mpi
我有一个算法,在每次迭代中,每个节点都必须计算一个数组的一个部分,其中每个元素都x_依赖于所有元素x.
x_[i] = some_func(x) // each x_[i] depends on the entire x
也就是说,每次迭代都会x进行计算x_,这将是x下一次迭代的新迭代.
对此进行并列化的方法是MPI将x_在节点之间进行分割并Allgather在计算之后进行调用,x_以便每个处理器将其发送x_到x所有其他处理器中的适当位置,然后重复.这是非常低效的,因为它Allgather每次迭代都需要昂贵的调用,更不用说它需要与x节点一样多的副本.
我想到了一种不需要复制的替代方法.如果程序在一台机器上运行,使用共享RAM,是否可以只x_在节点之间共享(不复制)?也就是说,在计算x_每个处理器之后会使其对其他节点可见,然后可以将其x用作下一次迭代的节点,而无需进行多次复制.我可以设计算法,以便没有处理器同时访问它x_,这就是为每个节点制作一个私有副本是过度的.
我想我要问的是:我可以简单地通过将数组标记为节点之间的共享来共享MPI中的内存,而不是手动为每个节点制作副本吗?(为简单起见假设我在一个CPU上运行)
您可以使用MPI_Win_allocate_sharedMPI-3在节点内共享内存。它提供了一种可移植的方式来使用 Sys5 和 POSIX 共享内存(以及任何类似的东西)。
以下内容摘自MPI 3.1 标准。
MPI_WIN_ALLOCATE_SHARED(size, disp_unit, info, comm, baseptr, win)
IN 本地窗口的大小大小,以字节为单位(非负整数)
IN disp_unit 位移的本地单位大小,以字节为单位(正整数)
IN info info 参数(句柄) IN comm intra-communicator (handle)
OUT 本地分配的窗口段的 baseptr 地址 (choice)
OUT 调用返回的 win 窗口对象 (handle)
int MPI_Win_allocate_shared(MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, void *baseptr, MPI_Win *win)
(如果您需要 Fortran 声明,请单击链接)
您使用MPI_Win_free. 分配和释放都是集体的。这与 Sys5 或 POSIX 不同,但使用户界面更加简单。
为了知道如何对另一个进程的内存执行加载存储,您需要在本地地址空间中查询该内存的地址。在另一个进程的地址空间中共享地址是不正确的(在某些情况下它可能会起作用,但不能假设它会起作用)。
MPI_WIN_SHARED_QUERY(win, rank, size, disp_unit, baseptr)
IN win 共享内存窗口对象(句柄)
IN rank 组中的窗口win(非负整数)或MPI_PROC_NULL
OUT size 窗口段的大小大小(非负整数) )
OUT disp_unit 位移的本地单位大小,以字节为单位(正整数)
OUT baseptr 地址,用于加载/存储访问窗口段(选择)
int MPI_Win_shared_query(MPI_Win win, int rank, MPI_Aint *size, int *disp_unit, void *baseptr)
(如果您需要 Fortran 声明,请单击上面的链接)
MPI_WIN_SYNC(win)
IN win 窗口对象(句柄)
int MPI_Win_sync(MPI_Win win)
此函数用作加载存储访问与共享内存窗口关联的数据的内存屏障。
您还可以使用 ISO 语言功能(即由 C11 和 C++11 原子提供的功能)或编译器扩展(例如GCC 内在函数,例如__sync_synchronize)来获得一致的数据视图。
如果您已经了解进程间共享内存语义,那么 MPI-3 实现将很容易理解。如果没有,请记住您需要正确同步内存和控制流。前者有 MPI_Win_sync,而现有的 MPI 同步函数,如MPI_Barrier和MPI_Send+MPI_Recv将适用于后者。或者您可以使用 MPI-3 原子来构建计数器和锁。
以下代码来自https://github.com/jeffhammond/HPCInfo/tree/master/mpi/rma/shared-memory-windows,其中包含共享内存使用的示例程序,已被 MPI 论坛用于辩论这些特征的语义。
该程序通过共享内存演示了单向成对同步。如果您只想创建一个 WORM(一次写入,多次读取)slab,那应该简单得多。
#include <stdio.h>
#include <mpi.h>
/* This function synchronizes process rank i with process rank j
* in such a way that this function returns on process rank j
* only after it has been called on process rank i.
*
* No additional semantic guarantees are provided.
*
* The process ranks are with respect to the input communicator (comm). */
int p2p_xsync(int i, int j, MPI_Comm comm)
{
/* Avoid deadlock. */
if (i==j) {
return MPI_SUCCESS;
}
int rank;
MPI_Comm_rank(comm, &rank);
int tag = 666; /* The number of the beast. */
if (rank==i) {
MPI_Send(NULL, 0, MPI_INT, j, tag, comm);
} else if (rank==j) {
MPI_Recv(NULL, 0, MPI_INT, i, tag, comm, MPI_STATUS_IGNORE);
}
return MPI_SUCCESS;
}
/* If val is the same at all MPI processes in comm,
* this function returns 1, else 0. */
int coll_check_equal(int val, MPI_Comm comm)
{
int minmax[2] = {-val,val};
MPI_Allreduce(MPI_IN_PLACE, minmax, 2, MPI_INT, MPI_MAX, comm);
return ((-minmax[0])==minmax[1] ? 1 : 0);
}
int main(int argc, char * argv[])
{
MPI_Init(&argc, &argv);
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int * shptr = NULL;
MPI_Win shwin;
MPI_Win_allocate_shared(rank==0 ? sizeof(int) : 0,sizeof(int),
MPI_INFO_NULL, MPI_COMM_WORLD,
&shptr, &shwin);
/* l=local r=remote */
MPI_Aint rsize = 0;
int rdisp;
int * rptr = NULL;
int lint = -999;
MPI_Win_shared_query(shwin, 0, &rsize, &rdisp, &rptr);
if (rptr==NULL || rsize!=sizeof(int)) {
printf("rptr=%p rsize=%zu \n", rptr, (size_t)rsize);
MPI_Abort(MPI_COMM_WORLD, 1);
}
/*******************************************************/
MPI_Win_lock_all(0 /* assertion */, shwin);
if (rank==0) {
*shptr = 42; /* Answer to the Ultimate Question of Life, The Universe, and Everything. */
MPI_Win_sync(shwin);
}
for (int j=1; j<size; j++) {
p2p_xsync(0, j, MPI_COMM_WORLD);
}
if (rank!=0) {
MPI_Win_sync(shwin);
}
lint = *rptr;
MPI_Win_unlock_all(shwin);
/*******************************************************/
if (1==coll_check_equal(lint,MPI_COMM_WORLD)) {
if (rank==0) {
printf("SUCCESS!\n");
}
} else {
printf("rank %d: lint = %d \n", rank, lint);
}
MPI_Win_free(&shwin);
MPI_Finalize();
return 0;
}
Run Code Online (Sandbox Code Playgroud)