Подтвердить что ты не робот

Структурированная сериализация в C и передача через MPI

У меня довольно простая проблема. Я определил пользовательскую структуру и хочу отправить ее другому MPI с использованием MPI_Bsend (или MPI_Send).

Вот моя структура:

struct car{
  int shifts;
  int topSpeed;
}myCar;

Однако, помимо примитивных типов, MPI, похоже, не поддерживает прямую "передачу" сложных типов данных, подобных описанной выше. Я слышал, что мне, возможно, придется использовать "сериализацию". Как мне это сделать и отправить "myCar" для обработки 5?

Заранее благодарим вас за ваше время.

4b9b3361

Ответ 1

Иеремия прав - MPI_Type_create_struct - это путь сюда.

Важно помнить, что MPI - это библиотека, не встроенная в язык; поэтому он не может "видеть", как выглядит структура, чтобы сериализовать ее самостоятельно. Поэтому для отправки сложных типов данных вы должны явно определить его макет. На языке, который имеет встроенную поддержку для сериализации, набор оберток MPI может с успехом использовать это; mpi4py, например, использует python pickle прозрачно отправлять сложные типы данных; но в C вам нужно засучить рукава и сделать это сами.

Для вашей структуры это выглядит так:

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

typedef struct car_s {
        int shifts;
        int topSpeed;
} car;

int main(int argc, char **argv) {

    const int tag = 13;
    int size, rank;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if (size < 2) {
        fprintf(stderr,"Requires at least two processes.\n");
        exit(-1);
    }

    /* create a type for struct car */
    const int nitems=2;
    int          blocklengths[2] = {1,1};
    MPI_Datatype types[2] = {MPI_INT, MPI_INT};
    MPI_Datatype mpi_car_type;
    MPI_Aint     offsets[2];

    offsets[0] = offsetof(car, shifts);
    offsets[1] = offsetof(car, topSpeed);

    MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_car_type);
    MPI_Type_commit(&mpi_car_type);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        car send;
        send.shifts = 4;
        send.topSpeed = 100;

        const int dest = 1;
        MPI_Send(&send,   1, mpi_car_type, dest, tag, MPI_COMM_WORLD);

        printf("Rank %d: sent structure car\n", rank);
    }
    if (rank == 1) {
        MPI_Status status;
        const int src=0;

        car recv;

        MPI_Recv(&recv,   1, mpi_car_type, src, tag, MPI_COMM_WORLD, &status);
        printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank,
                 recv.shifts, recv.topSpeed);
    }

    MPI_Type_free(&mpi_car_type);
    MPI_Finalize();

    return 0;
}

Ответ 2

Хотя ответ Джонатана Дурси верен, он слишком сложный. MPI предоставляет более простые и менее общие типы конструкторов, более подходящие для вашей проблемы. MPI_Type_create_struct ТОЛЬКО нужен, когда у вас разные типы баз данных (например, int и float).

Для вашего примера существует несколько лучших решений:

  • Предполагая, что два целых числа выровнены в смежной области памяти (т.е. как массив целых чисел), вам вообще не нужен производный тип данных. Просто отправьте/получите два элемента типа MPI_INT с адресом переменной типа car, которая будет использоваться в качестве буфера отправки/получения:

    MPI_Send(&send, 2, MPI_INT, dest, tag, MPI_COMM_WORLD);
    MPI_Recv(&recv, 2, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
    
  • Если вы хотите использовать производный тип данных (например, для удобства чтения или удовольствия от него), вы можете использовать MPI_Type_contiguous, который соответствует массивам:

    MPI_Type_contiguous(2, MPI_INT, &mpi_car_type);
    
  • Если два целых числа выровнены по-разному (скорее всего, это не так, но это зависит от машины и реализации MPI для множества разных платформ), вы можете использовать MPI_Type_indexed_block: он принимает массив смещения (например, MPI_Type_create_struct), но только один аргумент oldtype и длина блока каждого блока по определению: 1:

    MPI_Aint offsets[2];
    offsets[0] = offsetof(car, shifts) ; //most likely going to be 0 
    offsets[1] = offsetof(car, topSpeed);
    MPI_Type_indexed_block(2, offsets, MPI_INT);
    

В то время как другое решение является семантически правильным, его намного труднее прочитать и может повлечь за собой большой штраф за исполнение.

Ответ 3

Посмотрите MPI_Type_create_struct, чтобы создать собственный тип данных MPI для вашего объекта. Пример его использования - http://beige.ucs.indiana.edu/I590/node100.html.