I've been setting up a four-node mpi cluster with raspberry pis. As far as I can tell, I am down to one final major issue, and that is how to send an array of structs from each worker to the manager. I have cropped down the code to the below, but this could take a few tries, as I might have cropped too much. Albeit, I still get the same error (a seg fault, saying an address is not mapped), but sorry if there's a bit of back and fourth.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
struct ticknrank
{
char * ticker;
int errors;
int rank;
};
int main() //Designed for one master, three slaves
{
// i am under the impression the problem lies somewhere in this beginning section, before the commit.
int my_id;
MPI_Init(NULL,NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
MPI_Status status;
MPI_Datatype types[3] = {MPI_CHAR,MPI_INT,MPI_INT};
MPI_Datatype MPI_ticknrank, MPI_tmp;
int blocklengths[3] ={8,1,1};
MPI_Aint offsets[3];
offsets[0] = offsetof(struct ticknrank,ticker);
offsets[1] = offsetof(struct ticknrank,errors);
offsets[2]= offsetof(struct ticknrank,rank);
MPI_Aint lb, extent;
MPI_Type_create_struct(3,blocklengths, offsets, types, &MPI_tmp);
MPI_Type_get_extent(MPI_tmp, &lb, &extent);
MPI_Type_create_resized(MPI_tmp, lb, extent, &MPI_ticknrank);
MPI_Type_commit(&MPI_ticknrank);
// NOTE: sizeof(ticknrank) = 12, while MPI_Type_size(ticknrank) = 16. Not sure what to do about that.
if(my_id == 0) // meaning this process is a host job
{
//NOTE: NodethrRes and fou can be ommitted, I was just lazy and didn't wanna delete them
//on my cluster.
int length = 2;
struct ticknrank * NodeTwoRes = (struct ticknrank *)malloc(length * sizeof(struct ticknrank));
struct ticknrank * NodeThrRes = (struct ticknrank *)malloc(length * sizeof(struct ticknrank));
struct ticknrank * NodeFouRes = (struct ticknrank *)malloc(length * sizeof(struct ticknrank));
MPI_Recv(NodeTwoRes, length, MPI_ticknrank,1,MPI_ANY_TAG, MPI_COMM_WORLD, &status);
MPI_Recv(NodeThrRes, length, MPI_ticknrank,2,MPI_ANY_TAG, MPI_COMM_WORLD, &status);
MPI_Recv(NodeFouRes, length, MPI_ticknrank,3,MPI_ANY_TAG, MPI_COMM_WORLD, &status);
printf("%s\n", NodeTwoRes[0].ticker);
}
else
{
int myLen = 2;
struct ticknrank * results = malloc(myLen * sizeof(struct ticknrank));
results[0].ticker = strdup("FIRST");
results[0].rank = 4;
results[0].errors = 7;
results[1].ticker = strdup("SECON");
results[1].rank = 3;
results[1].errors = 15;
MPI_Send(results,myLen,MPI_ticknrank,0,1,MPI_COMM_WORLD);
}
MPI_Type_free(&MPI_ticknrank);
MPI_Finalize();
return 0;
}
The C
struct is a char * ticker
(which is 4 bytes if you are running 32 bits), but the derived datatype is for a char ticker[8]
which is indeed 8 bytes.
If you want to send multiple struct ticknrank
in one shot, then the data should be in contiguous memory, which means moving from char * ticker
to char ticker[8]
, and replacing strdup()
with strcpy()
(and up to you to make sure there is no buffer overflow).