MPI-3标准引入了共享内存,共享该内存的所有进程都可以读取和写入共享内存,而无需调用MPI库。虽然有使用共享或非共享内存的单边通信的例子,但我没有找到太多关于如何通过直接访问正确使用共享内存的信息。
我最终做了这样的事情,它工作得很好,但我想知道MPI标准是否保证它总是有效的?
// initialization:
MPI_Comm comm_shared;
MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, i_mpi, MPI_INFO_NULL, &comm_shared);
// allocation
const int N_WIN=10;
const int mem_size = 1000*1000;
double* mem[10];
MPI_Win win[N_WIN];
for (int i=0; i<N_WIN; i++) { // I need several buffers.
MPI_Win_allocate_shared( mem_size, sizeof(double), MPI_INFO_NULL, comm_shared, &mem[i], &win[i] );
MPI_Win_lock_all(0, win);
}
while(1) {
MPI_Barrier(comm_shared);
... // write anywhere on shared memory
MPI_Barrier(comm_shared);
... // read on shared memory written by other processes
}
// deallocation
for (int i=0; i<N_WIN; i++) {
MPI_Win_unlock_all(win[i]);
MPI_Win_free(&win[i]);
}在这里,我使用MPI_Barrier()来确保同步,并假设硬件使内存视图保持一致。此外,由于我有多个共享窗口,因此对MPI_Barrier的单个调用似乎比在每个共享内存窗口上调用MPI_Win_fence()更有效。
它似乎在我的x86笔记本电脑和服务器上运行得很好。但是这个程序是有效的/正确的MPI程序吗?有没有更有效的方法来实现同样的目标?
发布于 2020-03-07 02:41:20
这里有两个关键问题:
MPI_Barrier绝对不是一个内存屏障,永远不应该那样使用。MPI_Barrier只保证同步进程执行。while(1) {
MPI_Barrier(comm_shared);
... // write anywhere on shared memory
MPI_Barrier(comm_shared);
... // read on shared memory written by other processes
}它可能写得不清楚,但MPI-3标准的相关文本的作者-我是这个小组的一员-可以使用底层/宿主语言的内存模型来推断共享内存。因此,如果您使用C11编写此代码,则可以根据C11内存模型对其进行推理。
如果您想使用MPI来同步共享内存,那么您应该在所有窗口上使用MPI_Win_sync进行加载-存储访问,并在所有窗口上使用MPI_Win_flush进行RMA操作(Put/Get/Accumulate/Get_accumulate/Fetch_and_op/Compare_and_swap).
发布于 2020-02-20 00:00:52
我很想说这个MPI程序是无效的。
解释我的观点所依据的
由用户程序观察到的从/到共享存储器的加载/存储访问的一致性取决于体系结构。通过利用窗口同步功能(参见第11.5节)或显式地完成未完成的存储访问(例如,通过调用MPI_WIN_FLUSH),可以在统一内存模型中创建一致的视图(参见第11.4节)。MPI没有为访问独立内存模型中的共享内存窗口定义语义。
在RMA统一模型中,公共和私有副本是相同的,通过put或累积调用进行的更新最终由加载操作观察,而无需额外的RMA调用。对窗口的存储访问最终对远程get或累积调用可见,而无需额外的RMA调用。RMA统一模型的这些更强大的语义允许用户省略一些同步调用,并有可能提高性能。
如果RMA统一模型中的访问不同步(使用锁或刷新,请参见第11.5.3节),加载和存储操作可能会在进行过程中观察到内存更改。
MPI_BARRIER提供进程同步,但不提供内存synchronization.
所解决的唯一同步总是且仅限于单边同步,即在您的示例中为MPI_Win_flush{,_all}或MPI_Win_unlock{,_all} (除了必须由用户强制执行的主动和被动并发同步之外,或者使用MPI_MODE_NOCHECK assert标志)。
因此,要么使用store直接访问内存,并且需要在调用MPI_Barrier之前在每个窗口上调用MPI_Win_sync() (如示例11.10中所述)以确保同步;要么您正在进行RMA访问,然后必须在第二个屏障之前至少调用MPI_Win_flush_all以确保操作已被传播。如果您尝试使用加载操作进行读取,则在执行此操作之前,可能还必须在第二个屏障之后进行同步。
另一种解决方案是在屏障之间解锁和重新锁定,或者使用编译器和特定于硬件的符号来确保加载发生在数据更新之后。
https://stackoverflow.com/questions/60298288
复制相似问题