据我了解,接收非阻塞点对点 MPI 消息(Isend 和 Irecv)的顺序与发送它们的顺序一致。是否有任何技术可以使某些消息优先于其他消息?
例如,我们有一个多级算法,其中高分辨率解决方案通过非阻塞调用发送,并且在发送精细消息的同时完成粗略级别的计算。但是,当需要发送低分辨率解决方案时,我们希望那些优先考虑(它们本质上是阻塞的)。
我还可以想象,当我们移动到百亿亿次时,这可能对其他算法有用:一些消息在“关键路径”中,而另一些则不在。
据我了解,接收非阻塞点对点 MPI 消息(Isend 和 Irecv)的顺序与发送它们的顺序一致。是否有任何技术可以使某些消息优先于其他消息?
例如,我们有一个多级算法,其中高分辨率解决方案通过非阻塞调用发送,并且在发送精细消息的同时完成粗略级别的计算。但是,当需要发送低分辨率解决方案时,我们希望那些优先考虑(它们本质上是阻塞的)。
我还可以想象,当我们移动到百亿亿次时,这可能对其他算法有用:一些消息在“关键路径”中,而另一些则不在。
我认为这个问题的答案是否定的。一旦您将它们推送到 MPI 堆栈中,它们就不受您的控制,而 MPI 语义控制着消息的发送方式。
您当然可以通过在发送它们之前在代码中对它们进行排队,然后经常检查哪些是最重要的要发送来确定它们的优先级。但我完全不相信你会得到任何好处。当您准备发送粗略的信息时,是否有证据表明您的精细信息不完整?如果没有,那么您可能首先要调查是否有必要。
目前 MPI 没有消息优先级的规定,即将推出的 MPI 3.0 标准也没有。由 MPI 实现决定如何传输消息。例如,由于通信机制中的某些绕过(高度实现和系统相关),较小的消息可能会更快发送。您可能能够利用大多数 MPI 实现将大消息分成块而较小消息可能能够在大块之间滑动的事实。但是,再一次,这高度依赖于实现,我不会依赖它。
我在 InfiniBand 连接上使用 Open MPI 1.5.3 做了一个简单的实验。程序用 发送一条非常大的消息(1 GiB),MPI_Isend
然后用 发送两条短消息(16 字节)MPI_Send
,然后等待用 完成大发送MPI_Wait
。另一方面,MPI_Irecv
首先为大接收发布一个,然后是两个后续MPI_Recv
操作,然后MPI_Wait
是大接收。在大消息的接收完成之前,我一直能够收到两条短消息。这是我的测试的输出:
[0] Rank 0 running on host1
[0] Starting big send at 0.000019s
[0] Starting small send at 0.215448s
[0] Starting small send 2 at 0.224105s
[0] Starting wait at 0.224114s
[0] Finished wait at 0.935843s
[1] Rank 1 running on host2
[1] Starting big receive at 0.000020s
[1] Starting small recv at 0.000037s
[1] Starting small recv 2 at 0.548396s
[1] Starting wait at 0.548418s
[1] Finished wait at 0.935780s
从大约 700 毫秒的等待时间可以看出,在异步发送完成之前,两个小发送都成功了。我想说,在后台开始大接收后,第一个小接收成功了一段时间(约 300 毫秒)。我尝试仅使用MPI_COMM_WORLD
或使用单独的通信器来处理小消息 - 结果是相同的。每个节点都有一个 QDR IB HCA,并且运行时--mca btl_base_verbose 50
确认没有其他通信通道在使用。
MPI 也不支持我所知道的任何其他通信中间件。这可能是因为我所知道的任何硬件都不支持它,除了 Blue Gene,其中有用于控制消息的高优先级数据包在某些情况下会超过其他消息。然而,这些不是一般用途,因为它们只允许一个通信 64 字节(至少在 Blue Gene/P 上)。
好消息是你不需要这个。实现它的开销是不值得的,你会发现——假设你曾经调查过底层细节——不在网络中实现优先级允许 MPI 在大多数情况下提供最佳性能。
您在消息顺序的上下文中提到这一点有点奇怪。引用你的话:
据我了解,非阻塞点对点 MPI 消息(Isend 和 Irecv)的接收顺序与它们的发送顺序一致。
这里值得指出的是,MPI 只保证进程之间的匹配消息将按照它们发送的顺序被接收。您真的不希望更改这种类型的顺序,因为它使您的代码更易于理解,并减轻了您作为应用程序程序员的巨大负担。
但是,如果您发送带有不同标签的消息,则会更改匹配条件,并且您可以轻松地在第一个之前收到第二个。有关详细信息,请参阅标准相关部分中的第二个示例。我希望,如果您有两段代码同时发送,那么您已经使用标签分离了粗略和精细的消息,而不是尝试在消息排序之上实现您自己的某些协议。这是我认识的大多数 MPI 程序员的第二天性。
无论如何,假设您正在这样做,您可能会担心当您想要发送粗粒度消息时,大量细粒度消息会阻塞您的网络。我对此的一般建议是,如果这不是您现在可以实际测量的性能问题,那么您真的不应该费心解决它。您似乎在上述评论之一中确认这不是问题。
您可能考虑的一种可能的解决方案是使用像 Bcast 或 Barrier 这样的非阻塞集体 (NBC) 来通知每个人粗略阶段已完成并准备发送其解决方案。NBC 流量很可能不会获得优先级,但通知进程至少可以停止发送大量精细解决方案,直到粗发送完成。NBC将在 MPI-3 中,或者如果您不能等待那么久,您可以尝试使用libNBC 。
不过,对于听起来还不是性能问题的东西来说,这似乎需要做很多工作。