我想通过使用异步通信来加速我的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)吗?
提前致谢。
答案 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)
非阻塞发送呼叫表示系统可能开始复制 数据超出发送缓冲区。发件人不应该修改任何部分 调用非阻塞发送操作后发送缓冲区,直到 发送完成。
所以,是的,您应该先将数据复制到专用的发送缓冲区。