在一封邮件中发送带有恒定头的可变长度向量

时间:2019-05-21 14:50:24

标签: c mpi

我有n个workers,1个master(等级0),并且需要通过MPI从n个workersmaster发送消息。消息格式是可变长度向量(float *dta)和恒定大小的标头struct { int32_t x, int32_t y } dtaHdr

主控器仅遍历传入的结果并对其进行处理。能够将哪个dtaHdr与哪个dta关联起来很重要。

我知道该怎么做

  1. 为大小不变的MPI_Datatype创建dtaHdr,然后通过P2P MPI_Send / MPI_Recv发送。
  2. 通过P2P MPI_Float / MPI_Send发送任何数据类型(例如MPI_Recv)的可变长度向量。

问题是我不知道如何结合这两种方法。

我知道我可以做到:

  • 在两个单独的消息中先发送标头,然后发送数据。
    • 这有消息重新排序和交织的问题。我需要一种可靠,简单且可扩展的方式来关联标头及其在master上的数据。对于两条消息,我看不到如何始终简单地获取主服务器上传入消息的标头和数据的方法。即两个worker可以向master发送hdr和数据消息,并且它们可能变得交错。 (即使阅读了MPI规范,我也不确定TBH的订购保证是什么。)
  • 将标头和数据都编码到MPI_Byte数组中,并将其作为二进制Blob实质发送。
    • 声音真的很脏,破坏了某些保证。

我的问题:我如何MPI惯用地发送一条可识别的逻辑消息,该消息既包含一种类型的恒定大小的标头,又包含某种第二类型的可变大小的矢量。

1 个答案:

答案 0 :(得分:1)

该程序使用MPI_PackMPI_Unpack在同一封邮件中发送两种不同的类型:

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

#define ARRAY_SIZE(array) \
    (sizeof(array) / sizeof(array[0]))

struct data_header {
    int32_t x;
    int32_t y;
};

MPI_Datatype dt_header;
MPI_Datatype dt_vector;

void sendmsg(void) {
    struct data_header header = { 1, 2 };
    float example[] = { 1.0, 2.0, 3.0, 4.0 };
    char buffer[4096];
    int position;

    MPI_Pack(&header, 1, dt_header, buffer, sizeof(buffer), &position, MPI_COMM_WORLD);
    MPI_Pack(example, 1, dt_vector, buffer, sizeof(buffer), &position, MPI_COMM_WORLD);
    MPI_Send(buffer, position, MPI_PACKED, 0, 0, MPI_COMM_WORLD);
}

void recvmsg(void) {
    struct data_header header;
    float example[4];
    char buffer[4096];
    int position = 0;

    MPI_Recv(buffer, sizeof(buffer), MPI_PACKED, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    MPI_Unpack(buffer, sizeof(buffer), &position, &header, 1, dt_header, MPI_COMM_WORLD);
    MPI_Unpack(buffer, sizeof(buffer), &position, example, 1, dt_vector, MPI_COMM_WORLD);

    printf("x = %d, y = %d\n", header.x, header.y);
    for (int index = 0; index < ARRAY_SIZE(example); index++) {
        printf("%f ", example[index]);
    }
    printf("\n");
}

int main(void) {
    int world_size;
    int world_rank;

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    MPI_Type_contiguous(2, MPI_INT, &dt_header);
    MPI_Type_commit(&dt_header);
    MPI_Type_contiguous(4, MPI_FLOAT, &dt_vector);
    MPI_Type_commit(&dt_vector);

    if (0 == world_rank) {
        recvmsg();
    }
    else {
        sendmsg();
    }

    MPI_Finalize();

    return 0;
}

输出

x = 1, y = 2
1.000000 2.000000 3.000000 4.000000 

这实际上只是概念验证代码。希望它将帮助您找到所需的解决方案。

注意

此代码不进行错误检查,因此不应在生产环境中使用。