借助 MPI-3 非阻塞集合改进性能

全新 MPI-3 非阻塞集合能够提高应用性能。该改进效果在适当的应用上将会非常显著。但是对于一些应用,如果添加非阻塞集合,将会降低性能。接下来,我将介绍什么是非阻塞集合,并展示一个能够通过使用 MPI_Iallreduce 获益的内核。

什么是 MPI-3 非阻塞集合?

非阻塞集合是能够立即返回到应用代码的新版本集合功能。这些版本可以在您的应用执行其他任务时在后台执行集合操作(只要您的 MPI 实现支持)。如果您的应用结构支持您开始集合操作、执行本地工作并随后从集合操作中获取结果,那么您的应用可以通过使用非阻塞集合获益。

何时使用非阻塞集合?

为了从非阻塞集合获得优势,您的应用在集合开始到必须完成时必须能够执行大量任务,以抵消检查集合完成所额外付出的开销。一般而言,尺寸较大的消息需要更多计算能力来抵消将数据迁移至通信缓冲。如果您与重叠计算相关的消息尺寸较小,则可以获益。

此外,您的可用系统资源必须充足。如果您已经使用了所有可用系统资源,那么 MPI 实现无法与计算并行运行通信,从而将无法提供优势,可能还会降低性能。

如何确认潜在改进?

您可以通过几个步骤来确认如何使用非阻塞集合改进应用的性能。第一步,确认应用在集合上耗费的总体时间是多少。如果在集合上消耗的时间较少,则总体可用应用能够改进的可能性较小,切换到非阻塞集合的投资价值较低。您可以查看英特尔® 跟踪分析器中的摘要页,了解是否有任何热点功能是集合。

确定集合有足够的时间后,需要查看应用的工作流程是否允许非阻塞集合。例如,如果您计算数据集,在集合中立刻使用它,然后在集合之后立刻使用集合结果,您将需要重新处理应用流程才可从获得非阻塞集合的优势。但是如果您能够提前计算数据集,并在其计算后尽快将其传递至集合,然后过一段时间再使用,则有可能获得非阻塞集合的优势。

MPI_Iallreduce 使用示例

我们假定一个包含 3 个阵列的代码内核,每个阵列跨多个等级分布。内核获得第一个阵列的优势,并用它来修改第二个阵列。找到第二个阵列的最小值和最大值,用它连同第一个阵列的总数来修改第三个阵列。然后第三个阵列在所有等级减少为一个总数。伪代码:

MPI_Allreduce(A1,sumA1temp,MPI_SUM)
avgA1=sum(sumA1temp(:))/(elements*ranks)
A2(:)=A2(:)*avgA1
MPI_Allreduce(A2,minA2temp,MPI_MIN)
MPI_Allreduce(A2,maxA2temp,MPI_MAX)
A3(:)=A3(:)+avgA1
minA2=minval(minA2temp(:))
maxA2=maxval(maxA2temp(:))
A3(:)=A3(:)*(minA2+maxA2)*0.5
MPI_Allreduce(A3,sumA3temp,MPI_SUM)
finalsum=sum(sumA3temp(:))

该内核可以通过从 MPI_Allreduce 切换到 MPI_Iallreduce(以便降低第二个阵列的最小值和最大值)来提升性能。伪代码:

MPI_Allreduce(A1,sumA1temp,MPI_SUM)
avgA1=sum(sumA1temp(:))/(elements*size)
A2(:)=A2(:)*avgA1
MPI_Iallreduce(A2,minA2temp,MPI_MIN,req2min)
MPI_Iallreduce(A2,maxA2temp,MPI_MAX,req2max)
A3(:)=A3(:)+avgA1
MPI_Wait(req2min)
minA2=minval(minA2temp(:))
MPI_Wait(req2max)
maxA2=maxval(maxA2temp(:))
A3(:)=A3(:)*(minA2+maxA2)*0.5
MPI_Allreduce(A3,sumA3temp,MPI_SUM)
finalsum=sum(sumA3temp(:))

性能改进具体取决于多种因素,但是内核运行时的降低超过 50%。在对采用英特尔® 至强™ E5-2697 v2 处理器,英特尔® MPI 库版本 5.0 并运行 12 个等级(全部使用共享内存进行通信)的双插槽系统的测试中,非阻塞版本完成内核(带有一个包含 10000 个随机生成副本的阵列)的时间减少 54%。这是因为集合能够重叠通信,从而整体提高应用的并行性。

有关编译器优化的更完整信息,请参阅优化通知