mpich-3.3中的死锁,但其他版本中没有

阿姆卢卡斯

我有以下程序可以使用openmpi和mpich-3.2.1进行编译和运行,但是在MPI_Waitany使用mpich-3.3进行调用时会出现死锁该程序必须以偶数个级别运行,其中一半通过互连器发送数据到后半部分。与较大的自定义仿真程序相比,这是一个较小的版本,我尝试给出一个最小的示例。

一个奇怪的部分是将nwork变量增加到2会使死锁消失。

#include <cstdio>
#include <mpi.h>
#include <vector>

const int endMsg = -1;
const int endTag = 424242;

class Work
{
public:
    Work(const MPI_Comm& comm, const MPI_Comm& interComm, int tag) :
        comm(comm), interComm(interComm), tag(tag)
    {
        MPI_Comm_rank(comm, &rank);
    }

    void waitPrevSend()
    {
        printf("[work %d] waiting for previous message\n", tag);
        MPI_Wait(&sizeReq, MPI_STATUS_IGNORE);
        MPI_Wait(&dataReq, MPI_STATUS_IGNORE);
        sizeReq = MPI_REQUEST_NULL;
        dataReq = MPI_REQUEST_NULL;
    }

    void workAndSend()
    {
        waitPrevSend();
        printf("[work %d] creating data\n", tag);
        data.resize(tag + 42, tag);
        sizeInBytes = data.size();
        MPI_Issend(&sizeInBytes, 1, MPI_INT, rank, 2*tag+0, interComm, &sizeReq);
        MPI_Issend(data.data(), data.size(), MPI_BYTE, rank, 2*tag+1, interComm, &dataReq);
        printf("[work %d] has sent %d bytes of data\n", tag, sizeInBytes);
    }


    MPI_Request wait()
    {
        MPI_Request req;
        printf("[work %d] posted recv of size\n", tag);
        MPI_Irecv(&sizeInBytes, 1, MPI_INT, rank, 2*tag+0, interComm, &req);
        return req;
    }

    void recv()
    {
        data.resize(sizeInBytes);
        MPI_Recv(data.data(), data.size(), MPI_BYTE, rank, 2*tag+1, interComm, MPI_STATUS_IGNORE);
        printf("[work %d] has recved %d bytes of data\n", tag, sizeInBytes);
    }


    MPI_Comm comm, interComm;
    int rank;
    int tag;


    MPI_Request sizeReq {MPI_REQUEST_NULL}, dataReq {MPI_REQUEST_NULL};
    std::vector<char> data;
    int sizeInBytes;
};

class Master
{
public:
    Master(const MPI_Comm& comm, const MPI_Comm& interComm) :
        comm(comm), interComm(interComm)
    {
        MPI_Comm_rank(comm, &rank);
    }

    void run(std::vector<Work>& work, int niter)
    {
        for (int i = 0; i < niter; ++i)
            for (auto& w : work)
                w.workAndSend();
        sendEndMsg();
    }

    void sendEndMsg()
    {
        MPI_Ssend(&endMsg, 1, MPI_INT, rank, endTag, interComm);
    }

    MPI_Comm comm, interComm;
    int rank;
};

class Slave
{
public:
    Slave(const MPI_Comm& comm, const MPI_Comm& interComm) :
        comm(comm), interComm(interComm)
    {
        MPI_Comm_rank(comm, &rank);
    }

    void run(std::vector<Work>& work)
    {
        std::vector<MPI_Request> reqs;
        for (auto& w : work)
            reqs.push_back(w.wait());
        reqs.push_back(recvEndMsg());

        while (true)
        {
            int id;
            MPI_Status status;
            printf("waiting for one of %d requests to complete\n", (int) reqs.size());
            MPI_Waitany(reqs.size(), reqs.data(), &id, &status);

            if (id == (int) reqs.size() - 1)
            {
                for (auto& req : reqs)
                {
                    if (req != MPI_REQUEST_NULL)
                    {
                        MPI_Cancel(&req);
                        MPI_Request_free(&req);
                    }
                }
                return;
            }
            else
            {
                work[id].recv();
                reqs[id] = work[id].wait();
            }
        }
    }

    MPI_Request recvEndMsg()
    {
        MPI_Request req;
        int msg;
        MPI_Irecv(&msg, 1, MPI_INT, rank, endTag, interComm, &req);
        return req;
    }

    MPI_Comm comm, interComm;
    int rank;
};


int main(int argc, char **argv)
{
    MPI_Init(&argc, &argv);

    int rank;
    int size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if ((size%2) != 0)
        MPI_Abort(MPI_COMM_WORLD, 1);

    MPI_Comm teamComm, interComm;
    int team = rank % 2;

    MPI_Comm_split(MPI_COMM_WORLD, team, rank, &teamComm);

    const int localLeader  = 0;
    const int remoteLeader = team ? 0 : 1;
    const int tag = 42;
    const int nwork = 1;

    MPI_Intercomm_create(teamComm, localLeader, MPI_COMM_WORLD, remoteLeader, tag, &interComm);

    std::vector<Work> work;
    for (int i = 0; i < nwork; ++i)
        work.emplace_back(Work(teamComm, interComm, i));

    if (team == 0)
    {
        Master master(teamComm, interComm);
        master.run(work, 10);
    }
    else
    {
        Slave slave(teamComm, interComm);
        slave.run(work);
    }

    MPI_Comm_free(&interComm);
    MPI_Comm_free(&teamComm);

    MPI_Finalize();
    return 0;
}

跑步

mpirun -n 2 -l ./test_intercomm

仅在mpich-3.3中导致死锁。有任何想法吗?

编辑:我还试图将停止标记减小到较小的建议,相同的行为。上面命令的输出是:

[0] [work 0] waiting for previous message
[0] [work 0] creating data
[0] [work 0] has sent 42 bytes of data
[1] [work 0] posted recv of size
[1] waiting for one of 2 requests to complete
[0] [work 0] waiting for previous message

因此,在等待发送请求完成时,等级1的死锁在等待中,而等级0的死锁在等待发送请求完成时(第二个,实际数据,其recv仅在通过等待时才由等级1发布)。对我来说,似乎MPI_Waitany阻止了一切。

托贾拉

这是由MPICH v3.3中的错误引起的。它固定在提交0f7be7196cc05bf0c908761e148628e88d635190中将修复程序应用于v3.3可解决死锁。

该修补程序包含在版本3.3.1中,因此您应该升级到该版本。

为了提供更多上下文,提交消息显示:

在传递到设备层之前,testany和waitany函数都会跳过非活动或NULL请求。但是,用于发现第一个非NULL请求的方法可能会错误地跳过数组中的第一个请求。为了解决此问题,我们将第一个非NULL请求初始化为数组(计数)中的无效索引,然后在找到索引后将其设置为有效索引。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

MPICH2 smpd版本不匹配

在MPICH中执行OpenMP / MPI混合作业

Cray mpich是否具有64位整数MPI变量?

试图从html中刮除br,PYTHON 3之外没有任何其他标记的文本

在 mpi mpich 中询问 MPI_Reduce 和 MPI_Bcast

Boostrap 4 间距,为什么按钮没有版本 3 中的垂直间距?

Matlab从3D矩阵中删除所有其他元素

在CakePHP 3中使用其他关联创建具有条件的关联

glCallList上带有OpenMP segfaults的GLFW3(在glfw中的其他位置)

在Unity3D中,碰撞检测还有其他选择吗?

在具有自签名证书的Android 9中未获得SSLPeerUnverifiedException主机名196.1X.3X.X2的错误,但在所有其他版本中均可用

Ubuntu 12.04和MPICH性能

CMake:通过 openmpi 选择 mpich

ehcache 3中没有搜索API?

TYPO3菜单中的其他内容元素

如何停止python3中其他线程的input()?

Python 3中的其他语句始终运行

为其他数组中的每个项目更改Array [3]

如何使用其他类/文件中的函数?AS3

通过单击其他 3 个链接(其他 3 个 div)中的链接替换最初隐藏的 div

Python3中的多处理和死锁问题

18.04版本中的k3b问题“ cdrecord没有打开设备的权限”

发送带有保存在Woocommerce 3中的其他帐户字段值的自定义电子邮件

带有PHP的SQLite3如何将列与其他列中的数据进行交叉引用

如果架构有其他引用,我如何在 OpenAPI 3 中为 GET 和 POST 请求引用相同的架构

可以锁定sqlite3内存数据库以供python中的所有其他进程写入吗

还有其他方法可以验证python3中的命令行参数吗?

d3.js中的3个数组-如何调用其他数组?

python 3中的yield generator中没有next()函数