【问题标题】:Is it wrong to call MPI_Bcast several times?多次调用 MPI_Bcast 有错吗?
【发布时间】:2019-05-23 23:13:05
【问题描述】:

我正在尝试使用 MPI 实现矩阵向量乘法(即 nxn 矩阵乘以 nx1 向量)。

最初,我决定使用多个MPI_Bcast 调用(在我注意到MPI_AllGather...之前),我偶然发现了一些奇怪的行为。显然,无论传递给MPI_Bcast调用什么等级,都可以接收数据。

使用的部分代码(函数在彼此之后调用,因此发送广播在接收广播之前)。打印仅用于调试目的,我知道测试数据的长度为 2:

class Processor
{
public:
    Processor(int rank, int communicatorSize);

private:
    void broadcastOwnVectorToOtherRanks();
    void receiveBroadcastsFromOtherRanks();
    //...

    int ownRank;
    int communicatorSize;
    std::vector<int> ownVectorPart;
    std::vector<int> totalVector;
    //...
};

void Processor::broadcastOwnVectorToOtherRanks()
{
    //ownVectorPart is correctly filled before this function call
    std::printf("Own data in vector %d %d\n", ownVectorPart[0], ownVectorPart[1]);
    MPI_Bcast(ownVectorPart.data(), ownVectorPart.size(), MPI_INT, ownRank, MPI_COMM_WORLD);
}

void Processor::receiveBroadcastsFromOtherCommunicators()
{
    for (int rank = 0; rank < communicatorSize; ++rank)
    {
        if (rank == ownRank)
        {
            totalVector.insert(totalVector.end(), ownVectorPart.begin(), ownVectorPart.end());
        }
        else
        {
            std::vector<int> buffer(ownVectorPart.size());
            MPI_Bcast(buffer.data(), ownVectorPart.size(), MPI_INT, rank, MPI_COMM_WORLD);
            std::printf("Received from process with rank %d: %d %d\n", rank, buffer[0], buffer[1]);
            totalVector.insert(totalVector.end(), buffer.begin(), buffer.end());
        }
    }
}

结果(按等级排序):

[0] Own data in vector 0 1
[0] Received from communicator 1: 6 7
[0] Received from communicator 2: 4 5
[0] Received from communicator 3: 2 3
[1] Own data in vector 2 3
[1] Received from communicator 0: 0 1
[1] Received from communicator 2: 4 5
[1] Received from communicator 3: 6 7
[2] Own data in vector 4 5
[2] Received from communicator 0: 0 1
[2] Received from communicator 1: 2 3
[2] Received from communicator 3: 6 7
[3] Own data in vector 6 7
[3] Received from communicator 0: 4 5
[3] Received from communicator 1: 2 3
[3] Received from communicator 2: 0 1

如您所见,在进程中接收到的 rank 0 和 3 数据与发送的数据不同。例如,等级为0 的进程从等级3 接收数据,即使它期待来自进程1 的数据。

在我看来,在接收广播数据时会忽略排名,而 MPI 会在数据到来时分配数据,无论它是否来自预期的排名。

为什么MPI_Bcast 接收来自秩为3 的进程的数据,而作为参数传递的秩是1?同时多次调用MPI_Bcast 是一种未定义的行为吗?还是我的代码有错误?

【问题讨论】:

  • 您将传播者与根等级混合在一起。在您的 sn-p 中,只有一个通信器,它是 MPI_COMM_WORLD。通信器的所有等级都必须以 same 根等级调用MPI_Bcast(),我怀疑您的程序中不是这种情况,因此是未定义的行为。如果您需要更多帮助,请上传minimal reproducible example
  • @GillesGouaillardet 是的,很抱歉对沟通者和等级造成混淆。我的问题是,所有队伍都在尝试广播数据。首先,每个 rank 发送单个广播(broadcastOwnVectorToOtherCommunicators()),其次每个 rank 尝试接收来自所有其他 rank 的广播(receiveBroadcastsFromOtherCommunicators())。多个广播正在同时交换。我将编辑问题以尝试清除它。
  • 是的,所有广播都已接收。例如等级为3 的进程将发送一个广播并从012 接收总共3 个广播。但是接收到的数据是混杂的,好像MPI_Bcast中的rank参数被忽略了一样。
  • 再一次,您可能误用了MPI_Bcast()。通信器的所有等级必须调用具有相同root 参数的集体子例程。如果您使用minimal reproducible example编辑您的问题,我只能确认它
  • @GillesGouaillardet 完整示例中缺少什么? main()? qsub 的 PBS 文件?我可以重构它以避免类来尝试简化它?我试图解释所有进程都会用给定的root最终调用MPI_Bcast。所有进程都会在某个时候使用root == 0root == 1 等调用它。如果不允许这样做,这就是我要问的全部内容。

标签: c++ mpi


【解决方案1】:

引用 MPI 3.1 标准(第 5.12 节):

所有进程都必须调用集体操作(阻塞和非阻塞) 每个通信器的顺序相同。特别是,一旦一个进程调用 集体操作,通信器中的所有其他进程必须 最终调用相同的集体操作,并没有 其他集体操作,其间使用相同的通信器。

将此与第 5.4 节结合起来:

如果 comm 是一个内部通信器,MPI_BCAST 广播一条来自 对组的所有进程本身具有等级根的进程 包括。组的所有成员都使用相同的方法调用它 comm 和 root 的参数。

我将这两个部分解释为您必须以相同的顺序调用MPI_Bcast 和类似的集体通信函数,并在所有进程上使用相同的参数。使用不同的根值调用是无效的。

我相信MPI_Allgather 更适合您似乎想要的交流方式。它从所有进程收集等量的数据并将其复制到每个进程。

【讨论】:

    猜你喜欢
    • 2012-11-20
    • 2014-07-06
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    相关资源
    最近更新 更多