1

我想使用异步通信来加速我的 MPI 程序。但使用时间保持不变。工作流程如下。

before:
1.  MPI_send/ MPI_recv Halo           (ca. 10 Seconds) 
2.  process the whole Array           (ca. 12 Seconds)

after:
1. MPI_Isend/ MPI_Irecv Halo         (ca. 0,1 Seconds)
2. process the Array (without Halo)  (ca. 10 Seconds)
3. MPI_Wait                          (ca. 10 Seconds)  (should be ca. 0 Seconds)
4. process the Halo only             (ca. 2 Seconds)

测量结果表明,对于常见的工作负载,Array-core 的通信和处理时间几乎相同。所以异步应该几乎隐藏了通信时间。但事实并非如此。

一个事实——我认为这可能是问题所在——是 sendbuffer 也是进行计算的数组。尽管通信仅访问 Halo(使用派生数据类型)并且计算仅访问数组的核心(仅读取),但 MPI 是否有可能序列化内存访问?

有人知道这是否肯定是原因吗?

是否可能依赖于实现(我正在使用 OpenMPI)?

提前致谢。

4

2 回答 2

1

MPI 不会序列化用户代码中的内存访问(通常,这超出了库的能力),并且确实发生的事情是特定于实现的。

但实际上,MPI 库并没有像您希望的那样在“后台”进行尽可能多的通信,尤其是在使用 tcp + ethernet 等传输和网络时,没有有意义的方式将通信传递给另一套硬件。

只有在运行 MPI 库代码时,例如在 MPI 函数调用中,您才能确定 MPI 库确实在做某事。通常,对多个 MPI 调用中的任何一个的调用都会推动实现“进度引擎”,该引擎会跟踪正在进行的消息并引导它们。因此,例如,您可以快速做的一件事是在计算循环内的请求上调用 MPI_Test(),以确保事情在 MPI_Wait() 之前开始发生。这当然有开销,但这是很容易尝试衡量的。

当然,您可以想象 MPI 库会使用其他一些机制在幕后运行。MPICH2 和 OpenMPI 都使用了单独的“进度线程”,这些线程与用户代码分开执行,并在后台引导;但是要让它运行良好,并且在您尝试运行计算时不占用处理器,这是一个真正困难的问题。OpenMPI 的进度线程实现长期以来一直是实验性的,实际上暂时不在当前 (1.6.x) 版本中,尽管工作仍在继续。我不确定 MPICH2 的支持。

如果您使用的是 infiniband,其中网络硬件具有很多智能,那么前景会明亮一些。如果您愿意保留内存固定(对于 openfabrics),和/或您可以使用特定于供应商的模块(对于 Mellanox 的 mxm,对于 Qlogic 的 psm),那么事情会进展得更快一些。如果您使用共享内存,那么knem 内核模块也可以帮助进行节点内传输。

如果内存不是大问题,您可以采取的另一种特定于实现的方法是尝试使用急切协议直接发送数据,或者为每个块发送更多数据,从而减少对进度引擎的微调。急切协议在这里的意思是数据在发送时自动发送,而不是仅仅启动一组最终将导致消息发送的握手。坏消息是,这通常需要为库提供额外的缓冲内存,但如果这不是问题并且您知道传入消息的数量是有限的(例如,受您拥有的光环邻居的数量),这将有很大帮助. 如何为(例如)openmpi 的共享内存传输执行此操作在 OpenMPI 页面上进行了描述,用于调整共享内存,但其他传输也存在类似的参数,并且通常用于其他实现。IntelMPI拥有的一个不错的工具是“mpitune”工具,它可以自动运行许多此类参数以获得最佳性能。

于 2012-07-17T21:55:56.730 回答
0

MPI 规范规定:

非阻塞发送调用表明系统可能开始从发送缓冲区复制数据。在调用非阻塞发送操作后,发送方不应修改发送缓冲区的任何部分,直到发送完成。

所以是的,您应该首先将数据复制到专用的发送缓冲区。

于 2012-07-17T19:20:37.007 回答