MPI_Bcast:效率优势?

5
在MPI中,MPI_Bcast是否纯粹是一种方便的功能,还是使用它而不是循环遍历所有排名并向它们发送相同的消息会有效率上的优势?
原因:对于我来说,MPI_Bcast将消息发送给包括根节点在内的所有节点的行为很不方便,所以我不想使用它,除非有充分的理由,或者可以使其不向根节点发送消息。

为什么让MPI_Bcast的根参与会成为一个问题? - Stan Graves
4个回答

9
使用MPI_Bcast肯定比自己编写更有效。所有MPI实现都做了大量工作,以优化基于消息大小和通信架构等因素的集合操作。
例如,在MPICH2中使用MPI_Bcast将根据消息大小使用不同的算法。对于短消息,使用二叉树来最小化处理负载和延迟。对于长消息,它被实现为二叉树散布后跟随全收集。
此外,HPC供应商经常提供MPI实现,可有效利用底层互连,特别是对于集合操作。例如,可以使用硬件支持的多播方案使用定制算法,可以利用现有的互连

4
集体通信比自己编写的速度要快得多。MPI的所有实现都花费了大量时间来优化这些例程以使其更快。
如果您经常想在某个任务的子集上执行集体操作,则可能需要创建自己的子通信器并在这些通信器上使用BCAST等操作。

即使有备用的 comm,该 comm 的根仍然会参与集体操作。OP 特别提到让根节点获得消息是一个问题。 - Stan Graves
1
将根“发送”消息到自身是一个空操作,甚至不是内存复制。 - Jonathan Dursi

3

MPI_Bcast函数将信息从一个进程(即“根”)发送到所有其他进程。相较于循环遍历所有进程,这可能会更快。例如,mpich2实现使用二叉树来分发消息。

如果您不想广播到MPI_COMM_WORLD,但要定义子组,则可以使用以下方法:

#include <stdio.h>
#include "mpi.h"

#define NPROCS 8

int main(int argc, char **argv)
{
    int rank, new_rank, sendbuf, recvbuf,
    ranks1[4]={0,1,2,3}, ranks2[4]={4,5,6,7};

    MPI_Group orig_group, new_group;
    MPI_Comm new_comm;

    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    sendbuf = rank;

    /* Extract the original group handle */
    MPI_Comm_group(MPI_COMM_WORLD, &orig_group);

    /* Divide tasks into two groups based on rank */
    if (rank < NPROCS/2) {
        MPI_Group_incl(orig_group, NPROCS/2, ranks1, &new_group);
    } else {
        MPI_Group_incl(orig_group, NPROCS/2, ranks2, &new_group);
    }

    /* Create new communicator and then perform some comm
     * Here, MPI_Allreduce, but you can MPI_Bcast at will
     */
    MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm);
    MPI_Allreduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_SUM, new_comm);
    MPI_Group_rank (new_group, &new_rank);

    printf("rank= %d newrank= %d recvbuf= %d\n", rank, new_rank, recvbuf); 

    MPI_Finalize();
} 

可能会产生以下输出:
rank= 7 newrank= 3 recvbuf= 22
rank= 0 newrank= 0 recvbuf= 6 
rank= 1 newrank= 1 recvbuf= 6 
rank= 2 newrank= 2 recvbuf= 6 
rank= 6 newrank= 2 recvbuf= 22
rank= 3 newrank= 3 recvbuf= 6
rank= 4 newrank= 0 recvbuf= 22
rank= 5 newrank= 1 recvbuf= 22

3
答案是,在一般情况下,MPI_Bcast比循环快。通常,MPI集合在广泛的消息大小、通信大小和特定排名布局上进行了优化。
尽管如此,在特定的消息大小、通信大小和排名布局下,通过非阻塞点对点调用(例如ISend和Recv/IRecv)循环可能更快...但可能只有在少数特定的消息大小、通信大小和排名布局下才会更快。
如果您编写的特定算法需要Bcast的模式(例如,所有排名都从根节点获取相同的数据负载),则使用Bcast集合。通常情况下,通过自行编写“集合替代品”来增加复杂性是不值得的。
如果算法需要其他消息模式,并且Bcast仅部分适合,则可能值得自行编写...但个人认为这个门槛相当高。

我同意。通过调整集合的参数(手动通过命令行参数/环境变量或自动通过像IntelMPI的mpitune之类的工具),要比重写自己的高效集合容易得多。 - Jonathan Dursi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接