MPI_Isend / Irecv:同时可以在未使用的内存位置访问sendbuffer

时间:2012-07-17 19:08:55

标签: mpi memory-access

我想通过使用异步通信来加速我的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也是进行计算的数组。 MPI是否可能序列化内存访问,尽管通信仅访问Halo(使用派生数据类型)并且计算仅访问数组的核心(仅读取)???

有人知道这是否确定原因?

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

提前致谢。

2 个答案:

答案 0 :(得分:1)

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

但实际上,MPI库并没有像你希望的那样在后台进行那么多的通信,当使用像tcp + ethernet这样的传输和网络时,尤其如此,那里没有有意义的方法可以实现与另一组硬件的通信。

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

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

如果您正在使用infiniband,网络硬件具有很多智能,那么潜在客户会变得更加明亮。如果你愿意留下内存固定(对于openfabrics),和/或你可以使用供应商特定的模块(mxm用于Mellanox,psm用于Qlogic),那么事情可以更快地进展。如果您正在使用共享内存,那么knem kernel module也可以帮助进行内部代码传输。

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

答案 1 :(得分:0)

MPI specification州:

  

非阻塞发送呼叫表示系统可能开始复制   数据超出发送缓冲区。发件人不应该修改任何部分   调用非阻塞发送操作后发送缓冲区,直到   发送完成。

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