Ali Elgazar
Ali Elgazar

Reputation: 777

in MPI in c how to create a struct of structs and send it to multiple process

so I have this struct

typedef struct{
     float x;
     float y;
     int centroid;
}point;

And I also have this struct

typedef struct{
     int csize;//the current size
     int tsize;//the total size
     point * data;//the data carried
}ArrayList;

These second struct forms a dynamically growing array in C (Functions for dynamic growth is implemented and working fine). how exactly do I create a struct of that and send it using MPI in c? I looked at other posts like struct serialization in C and transfer over MPI and others but I could't find a solution to my problem.

I'd appreciate some help.

Best, Gedo

EDIT- the possible duplicate does NOT solve my question, my question is pertaining a struct containing a pointer to an array of structs which is dynamically growing. the duplicate question pertains having an array of native types in a struct.

Upvotes: 0

Views: 3448

Answers (1)

Jonathan Dursi
Jonathan Dursi

Reputation: 50927

Manually serializing the array of structs to a buffer and sending the buffer is a terrible idea, as it introduces another memory copy on both the send and receive side.

Sending an array of MPI structures is no different than an array of any other object; you just have to create a structure type - there are many examples here and elsewhere - making sure to calculate offsets and sizes as there may be padding inserted in your structs. Then just pass an array of them:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "mpi.h"

typedef struct{
    float x;
    float y;
    int centroid;
} point;

typedef struct{
    int csize;//the current size
    int tsize;//the total size
    point * data;//the data carried
} ArrayList;


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

    int rank, size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    assert( size >= 2 );
    const int npts_avail=20;
    point points[npts_avail];

    ArrayList list;
    list.data = points;

    if (rank == 0) {
        int npts_used=10;
        list.csize = npts_used;
        list.tsize = npts_avail;
        for (int i=0; i<list.csize; i++) {
            points[i].x = 1.*i;
            points[i].y = -2.*i;
            points[i].centroid = i;
        }
    }

    const int nfields=3;
    MPI_Aint disps[nfields];
    int blocklens[] = {1,1,1};
    MPI_Datatype types[] = {MPI_FLOAT, MPI_FLOAT, MPI_INT};

    disps[0] = offsetof( point, x );
    disps[1] = offsetof( point, y );
    disps[2] = offsetof( point, centroid );

    MPI_Datatype istruct, pstruct;
    MPI_Type_create_struct(nfields, blocklens, disps, types, &istruct );
    MPI_Type_create_resized( istruct, 0, (char *)&(points[1]) - (char *)(&points[0]), &pstruct );
    MPI_Type_commit(&pstruct);

    if (rank == 0) {
        MPI_Send( &(list.csize), 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
        MPI_Send( &(list.tsize), 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
        MPI_Send( list.data, list.csize, pstruct, 1, 0, MPI_COMM_WORLD);
    } else if (rank == 1) {
        MPI_Recv( &(list.csize), 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        MPI_Recv( &(list.tsize), 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        MPI_Recv( list.data, list.csize, pstruct, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    }

    if (rank == 1) {
        printf("Received: \n");
        for (int i=0; i<list.csize; i++) {
            printf(" (%f, %f): %d\n", points[i].x, points[i].y, points[i].centroid);
        }
    }

    MPI_Finalize();
}

Running gives the expected output:

$ mpirun -np 2 ./structs
Received:
 (0.000000, -0.000000): 0
 (1.000000, -2.000000): 1
 (2.000000, -4.000000): 2
 (3.000000, -6.000000): 3
 (4.000000, -8.000000): 4
 (5.000000, -10.000000): 5
 (6.000000, -12.000000): 6
 (7.000000, -14.000000): 7
 (8.000000, -16.000000): 8
 (9.000000, -18.000000): 9

Note that you could construct an MPI struct of ArrayList, as well, and use that - except that the displacement of data may have to be changed every time you resend (on the sending side), and on the receiving side it can't even be determined until you know the amount of data you'll need to receive. So best are to send the sizes first (in two messages, as I have here, or better yet, to send it as one message of two ints), and then send the array of structs as shown.

Upvotes: 2

Related Questions