Structures in MPI
In MPI we can exchange struct type data. We can do this by first creating a new MPI data type (MPI_Datatype), using MPI_Type_create_struct to which we specify the number of fields of each type and their size in the structure, the placement of the fields in memory (using *offsets * and MPI_Aint).
The signature of the MPI_Type_create_struct function is as follows:
int MPI_Type_create_struct(int count, const int array_of_blocklengths[], const MPI_Aint array_of_displacements[], const MPI_Datatype array_of_types[], MPI_Datatype *newtype)
And it has the following parameters:
- count (↓) - number of blocks (also number of entries in array_of_types, array_of_displacements and array_of_blocklengths vectors)
- array_of_blocklengths[] (↓) - number of elements in each block
- MPI_Aint array_of_displacements[] (↓) - byte displacement for each block
- array_of_types[] (↓) - the type of elements in each block
- *newtype (↑) - the new data type
tip
The byte offset for each block is calculated using the offsetof function. More details on its use can be found here: tutorialspoint.
Example of use:
#include <mpi.h>
#include <stdio.h>
#include <stddef.h>
// the structure at the base of the custom type
typedef struct {
float f1, f2;
char c;
int i[2];
} custom_type;
int main(int argc, char *argv[]) {
int numtasks, rank, source = 0, dest = 1, tag = 1;
custom_type t;
MPI_Datatype customtype, oldtypes[4];
int blockcounts[4];
MPI_Aint offsets[4];
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
// field f1
offsets[0] = offsetof(custom_type, f1);
oldtypes[0] = MPI_FLOAT;
blockcounts[0] = 1;
// field f2
offsets[1] = offsetof(custom_type, f2);
oldtypes[1] = MPI_FLOAT;
blockcounts[1] = 1;
// field c
offsets[2] = offsetof(custom_type, c);
oldtypes[2] = MPI_CHAR;
blockcounts[2] = 1;
// field i
offsets[3] = offsetof(custom_type, i);
oldtypes[3] = MPI_INT;
blockcounts[3] = 2;
// define the new type and commit
MPI_Type_create_struct(4, blockcounts, offsets, oldtypes, &customtype);
MPI_Type_commit(&customtype);
if (rank == 0) {
t.f1 = 0.5;
t.f2 = -1.2;
t.c = 'a';
t.i[0] = 0;
t.i[1] = 1;
MPI_Send(&t, 1, customtype, dest, tag, MPI_COMM_WORLD);
} else if (rank == 1) {
MPI_Recv(&t, 1, customtype, source, tag, MPI_COMM_WORLD, &status);
printf("Received custom type with f1=%.1f, f2=%.1f, c=%c, i[0]=%d, i[1]=%d\n", t.f1, t.f2, t.c, t.i[0], t.i[1]);
}
// the new type is released when it is no longer used
MPI_Type_free(&customtype);
MPI_Finalize();
}