【问题标题】:I found myself cannot understood the parameter "recvcounts" of MPI_Gatherv我发现自己无法理解 MPI_Gatherv 的参数“recvcounts”
【发布时间】:2011-09-21 06:56:30
【问题描述】:

MPI_Gatherv 是这样一个 MPI 接口:

int MPI_Gatherv(
    void* sendbuf,
    int sendcount,
    MPI_Datatype sendtype,
    void* recvbuf,
    int *recvcounts,
    int *displs,
    MPI_Datatype recvtype,
    int root,
    MPI_Comm comm)

“recvcounts”的类型是“int *”,这样我们可以分别设置每个进程要接收的项目数;但是我发现这是不可能的:

当recvcounts[i]

当recvcounts[i] > sendcount时,程序会crash,错误信息是这样的:

Fatal error in PMPI_Gatherv: Message truncated, error stack:
PMPI_Gatherv(386).....: MPI_Gatherv failed(sbuf=0012FD34, scount=2, MPI_CHAR, rbuf=0012FCC8, rcnts=0012FB30, displs=0012F998, MPI_CHAR, root=0, MPI_COMM_WORLD) failed
MPIR_Gatherv_impl(199):
MPIR_Gatherv(103).....:
MPIR_Localcopy(332)...: Message truncated; 2 bytes received but buffer size is 1

所以这意味着根必须从每个进程接收固定数量的项目并且参数recvcount没有意义?还是我理解错了?

这是我的代码:

#include <mpi.h>
#include <iostream>

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

    int n, id;
    MPI_Comm_size(MPI_COMM_WORLD, &n);
    MPI_Comm_rank(MPI_COMM_WORLD, &id);

    char x[100], y[100];
    memset(x, '0' + id, sizeof(x));
    memset(y, '%', sizeof(y));
    int cnts[100], offs[100] = {0};
    for (int i = 0; i < n; i++)
    {
        cnts[i] = i + 1;
        if (i > 0)
        {
            offs[i] = offs[i - 1] + cnts[i - 1];
        }
    }
    MPI_Gatherv(x, 1, MPI_CHAR, y, cnts, offs, MPI_CHAR, 0, MPI_COMM_WORLD);    // receive only 1 item from each process
    //MPI_Gatherv(x, 2, MPI_CHAR, y, cnts, offs, MPI_CHAR, 0, MPI_COMM_WORLD);    // crash
    if (id == 0)
    {
        printf("Gatherv:\n");
        for (int i = 0; i < 100; i++)
        {
            printf("%c ", y[i]);
        }
        printf("\n");
    }

    MPI_Finalize();

    return 0;
}

【问题讨论】:

    标签: c++ mpi


    【解决方案1】:

    正如@Alexander Molodih 指出的那样,sendcount=recvcount, sendtype=recvtype 将始终有效;但是当您开始创建自己的 MPI 类型时,您通常有不同的发送和接收类型,这就是 recvcount 可能与 sendcount 不同的原因。

    举个例子,看看最近问的MPI partition matrix into blocks;有一个二维数组被分解成块并分散。发送类型(必须从全局数组中只挑选出必要的数据)和接收类型(只是一个连续的数据块)不同,计数也不同。

    这就是发送和接收类型和计数不同的一般原因,例如 sendrecv、gather/scatter 或任何其他同时发生发送和接收的操作。

    在您的gatherv 情况下,每个进程可能有自己不同的发送计数,但recvcount[] 数组必须是所有这些计数的列表,以便接收器可以正确放置接收到的数据。如果您事先不知道这些值,(每个等级只知道自己的计数,cnts[id])您可以先收集:

    MPI_Gather(&(cnts[id]), 1, MPI_INT, cnts, 1, MPI_INT, 0, MPI_COMM_WORLD):
    for (int i = 1; i < n; i++) { 
        offs[i] = offs[i - 1] + cnts[i - 1];
    }
    MPI_Gatherv(x, cnts[id], MPI_CHAR, y, cnts, offs, MPI_CHAR, 0, MPI_COMM_WORLD);   
    

    【讨论】:

    • 我似乎发现了我的错误:语句“sendcount=recvcount”的意思是,“sendcount=recvcounts[id]”对于每个进程都是正确的,不仅适用于收集进程,对吗? ?
    猜你喜欢
    • 2013-05-08
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 2016-02-09
    • 2014-01-02
    相关资源
    最近更新 更多