MPI-3 学习笔记(二):单边通信

MPI-3 单边通信(One-sided Communication)特性学习笔记。

基本观点:将数据交换和同步进行解耦,交换数据时不需要远端进程进行同步。

优点:

  • 一些不规则的通信模式(communication pattern)可以更容易实现,不需要额外的步骤来确定要进行多少次 Send/Recv;
  • 如果系统硬件支持远端内存访问(Remote Memory Access, RMA),可以比 Send/Recv 获得更好的性能。

术语:

  • 源进程(Origin process):拥有源数据、发起通信的进程;
  • 目标进程(Target process):拥有目标数据的进程,不需要显式调用通信函数;
  • 阶段(Epoch):一个数据交换时间段;
  • 断言(Assert):指示如何使用单边通信,给出『快速』优化提示。

主要函数一览:

  • MPI_Win_create(*base, total_bytes, unit_bytes, info, comm, *win_handle)
    • 创建一个 Window 并暴露一段连续的内存给 MPI
  • MPI_Win_allocate(total_bytes, unit_bytes, info, comm, *baseptr, *win_handle)
    • MPI_Win_create 类似,但是会申请内存分配;
    • 可能会消耗更少的资源,应该尽可能使用!
  • MPI_Win_create_dynamic(info, comm, *win_handle)
    • 创建一个 Window, 但是不绑定暴露的内存;
    • 只有在使用 MPI_Win_attach 绑定了暴露给 MPI 的内存以后,其他进程才能使用。
  • MPI_Get/Put(*local_buf_addr, local_buf_entry_count, local_entry_datatype, target_rank, target_entry_offset, target_entry_datatype, win_handle)
    • 非阻塞;
    • 冲突访问时系统的行为是未定义的;
    • Rput/Rget:有 Request 句柄的版本,也是非阻塞的,但是开销更大。
  • MPI_Accumulate(*local_buf_addr, local_buf_entry_count, local_entry_datatype, target_rank, target_entry_offset, target_entry_datatype, op, win_handle)
    • 逐个元素的 原子操作,类似于 MPI_Put
    • 仅支持预定义的操作;
    • 允许冲突访问,此时会根据 ordering rules 来进行操作。
  • MPI_Get_accumulate(<local_src_params>, <local_get_result_params>, <target_params>, op, win_handle)
    • *target* 处取数据存到 *result*,然后将 *local_src* 的数据累加操作到 *target* 处。
  • MPI_Fetch_and_op(*local_entry_addr, *result_entry_addr, datatype, target_rank, *target_entry_offset, op, win_handle)
    • 单个元素版本的 MPI_Get_accumulate,
      MPI_Compare_and_swap 参数太复杂了我没看明白……)

RMA 同步模型:解决如下问题:一个进程什么时候可以读写远端进程的数据?X 进程写的数据 Y 进程什么时候可以用?

  1. Fence:主动同步
    • 在同一个 “win” 组中的所有进程都需要调用 MPI_Win_fence 来启动一个数据交换阶段;
    • 数据交换阶段中所有进程都可以发出读写操作请求;
    • 在同一个 “win” 组中的所有进程都需要调用 MPI_Win_fence 来结束一个数据交换阶段;
    • 第二次 fence synchronization 完成时所有的操作请求都已完成;
    • 比较适用于 BSP 模式的程序,比如需要边界交换程序或者稠密线性代数程序(用 MPI_Get, MPI_Put 来代替 MPI_Allgather, MPI_Send/Recv)。
  2. PSCW 同步:主动同步
    • 和 fence 类似,但源进程和目标进程指出他们可以和哪一个组的进程进行通信;
    • 目标进程:启动一个暴露阶段(Exposure Epoch): MPI_Win_post 打开,MPI_Win_wait 关闭;
    • 源进程:启动一个访问阶段(Access epoch):MPI_Win_start 打开,MPI_Win_complete 关闭。
      PSCW
  3. Lock/Unlock:被动同步
    • 单边非同步通信;
    • 目标进程不主动参与通信过程;
    • MPI_Win_lock/MPI_Win_unlock开始/结束被动通信阶段;
    • 独占/共享 模式决定了其他进程能否取得目标进程的锁(使用目标进程的数据),使用独占模式时只有源进程调用 unlock 以后才会释放目标进程的锁;
    • MPI_Win_flush:完成所有还没完成的操作;
    • 类似的函数: MPI_Win_lock_all / MPI_Win_unlock_all, lock/unlock 源进程以外所有其他进程
      Lock

如何选择使用的模式:

  • 主动模式: Bulk synchronization, 如交换 ghost cell;
  • 被动模式:非同步数据交换,或者数据很大时。

内存模型:

  • 统一模式:公共和私有的 window 是同一片内存;
  • 分隔模式:公共和私有的 window 不是同一片内存,但 MPI 提供软件保证的一致性。
    MemMode
  • 这两种模式的语义都非常复杂……