Reputation: 777
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
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