структурирование сериализации в C и передача по MPI - PullRequest
30 голосов
/ 26 марта 2012

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

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

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

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

Ответы [ 3 ]

56 голосов
/ 26 марта 2012

Иеремия прав - MPI_Type_create_struct - это то, что нужно.

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

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

#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;
}
11 голосов
/ 30 июня 2015

Хотя ответ Джонатана Дурси правильный, он слишком сложен.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), но только один аргумент старого типадлина каждого блока равна 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);
    

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

6 голосов
/ 26 марта 2012

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

...