Отправить вектор переменной длины с постоянным заголовком в одном сообщении - PullRequest
4 голосов
/ 21 мая 2019

У меня n workers, 1 master (ранг 0), и мне нужно отправлять сообщения через MPI от n workers до master.Формат сообщения - это вектор переменной длины (float *dta) и заголовок постоянного размера struct { int32_t x, int32_t y } dtaHdr.

Мастер просто просматривает входящие результаты и обрабатывает их.Это важно для того, чтобы иметь возможность ассоциировать, что dtaHdr идет с каким dta.

Я знаю, как:

  1. Создать MPI_Datatype для постоянного размера dtaHdr и отправить его через P2P MPI_Send / MPI_Recv.
  2. Отправьте вектор переменной длины любого типа данных (например, MPI_Float) через P2P MPI_Send / MPI_Recv.

. Проблема в том, что я понятия не имею, как объединить эти два подхода.

Я знаю, что мог бы:

  • Сначала отправить заголовок, а затем данные в двух отдельных сообщениях.
    • Это проблема переупорядочения и чередования сообщений.Мне нужен надежный, простой и масштабируемый способ связать заголовок и его данные на master.С двумя сообщениями я не вижу способа, как всегда и просто получать и заголовок, и данные для входящего сообщения на мастер.Т.е. два worker могут отправлять hdr и сообщения с данными на master, и они могут чередоваться.(Я не уверен, что гарантии для заказа являются TBH, даже после прочтения спецификации MPI).
  • Кодировать заголовок и данные в массив MPI_Byte и отправлять его по существукак двоичный блоб.
    • Звучит очень грязно и нарушает некоторые гарантии.

Мой вопрос : как мне MPI-идиоматически отправлять одно идентифицируемое логическое сообщениекоторый содержит как заголовок постоянного размера одного типа, так и вектор переменного размера некоторого второго типа.

1 Ответ

1 голос
/ 24 мая 2019

Эта программа использует MPI_Pack и MPI_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 

Этона самом деле просто проверочный код.Надеемся, что это поможет вам найти решение, которое вы ищете.

Примечание

Этот код не проверяет ошибки и не должен использоваться в производственной среде.

...