Using MPI_Type_create_struct() to transfer structs containing dynamic arrays in C

梦想与她 提交于 2019-12-23 05:39:17

问题


Overview: I am testing that the data type I create using MPI_Type_create_struct() is correct and hence sends the correct values. I am having trouble with getting the values stored in the arrays to transfer onto the other processors. I think this is likely a problem with the memory addresses of the arrays in each struct bound and the offsets stored in the array indices[] used to create the data type mpibound.

Problem: I'm working on a program using MPI and my end goal is to use MPI_Gatherv() to gather values from an array of structures called bound which is declared below.

struct bound {
   int      n;
   char*    name;
   double*  lat;
   double*  lon;
};

I have created a test program to ensure that I have used MPI_Type_create_struct() correctly. The function in which I call MPI_Type_create_struct() is written below.

 void CreateBoundType (struct bound a_bound) {
    int blocklens[4];              /*Block Lengths of data in structure*/
    MPI_Datatype old_types[4];     /*Data types of data in structure*/
    MPI_Aint indices[4];           /*Byte displacement of each piece of data*/
    MPI_Aint addr1, addr2, addr3, addr4, baseaddr;

   /*Set block lengths*/
   blocklens[0] = 1;
   blocklens[1] = 10;
   blocklens[2] = NPT_MAX;
   blocklens[3] = NPT_MAX;

   /*Set Data Types*/
   old_types[0] = MPI_INT;
   old_types[1] = MPI_CHAR;  
   old_types[2] = MPI_DOUBLE;  
   old_types[3] = MPI_DOUBLE;  

   /*Set byte displacement for each piece of data in structure*/
   /*!!!!!I expect that the following 8 lines cause my problem!!!!!!*/
   MPI_Get_address ( &a_bound,         &baseaddr);
   MPI_Get_address ( &a_bound.num_pts, &addr1);
   MPI_Get_address ( a_bound.label,    &addr2);
   MPI_Get_address ( a_bound.lat,      &addr3);
   MPI_Get_address ( a_bound.lon,      &addr4);
   indices[0] = addr1 - baseaddr;
   indices[1] = addr2 - baseaddr;
   indices[2] = addr3 - baseaddr;
   indices[3] = addr4 - baseaddr;

   /*Create structure type in MPI so that we can transfer boundaries between nodes*/
   MPI_Type_create_struct(4,blocklens,indices,old_types,&mpibound);
   MPI_Type_commit(&mpibound); 
   return;
}

When I try to use the data type I have created (which is a global variable, mpibound), in a call to MPI_Bcast() the values stored in the arrays which are part of the buffer struct I use are not updated but the integer value n (n is the length of the arrays) does get changed on all processors. Therefore I think that my issue has something to do with the offsets (indices[4]) that are used to define mpibound.

Below I have written a main function that shows how I call this function and set up the structures. (I have left out calls to MPI_Init and other such functions to keep it as short as I can)

int main (int argc, char **argv) {

   /*Initialise MPI etc*/...

   /*Create structure to broadcast*/
   struct bound my_bound;
   my_bound.name  = strdup(string);
   my_bound.lat   = malloc(NPT_MAX*sizeof(double));
   my_bound.lon   = malloc(NPT_MAX*sizeof(double));
   if(rank == 0) {
      my_bound.n      = 5;
      my_bound.lat[0] = 2.6;
      my_bound.lon[0] = 4.2;
   }

   /*Call the function that creates the type mpibound*/
   CreateBoundType(my_bound);

   /*Create buffer to be used in a Broadcast from the root processor (rank 0)*/
   struct bound *buff = malloc(sizeof(struct bound));
   buff->lat = malloc(NPT_MAX*sizeof(double));
   buff->lon = malloc(NPT_MAX*sizeof(double));
   buff = &my_bound;

   /*Cast values in buffer from proc 0 to all others*/
   MPI_Bcast(buff,1,mpibound,0,MPI_COMM_WORLD);

   /*Print values and checks, free memory etc*/...

   return(EXIT_SUCCESS);
}

Putting a few print statements after the call to MPi_Bcast shows that on procs with ranks >0, the value of n is updated to that broadcast from rank 0 but the first element of the lat and lon arrays is still 0.

If you can help me I greatly appreciate it having struggled with this for a few days now! I tried to keep this as brief as I could and this is the best version that I have been able to create.

Thanks for reading!


回答1:


As noted by Zulan, there are some things that make little sense in your code. But the main problem lies

void CreateBoundType (struct bound a_bound) {
//                    HERE HERE HERE HERE

You are passing the structure by value, which means that the MPI datatype mpibound is constructed from the memory addresses of the value copy. The copy contains the same pointer values for label, lat, and lon, but the base will be located somewhere else. Therefore, you cannot use that datatype to send the structure instance in main as the offsets are not valid for it.

What you should do instead is pass the structure by address. The changes are minimal:

void CreateBoundType (struct bound *a_bound) {
   ...
   MPI_Get_address(a_bound,           &baseaddr);
   MPI_Get_address(&a_bound->n, &addr1);
   MPI_Get_address(a_bound->label,    &addr2);
   MPI_Get_address(a_bound->lat,      &addr3);
   MPI_Get_address(a_bound->lon,      &addr4);
   ...
}

...
/*Call the function that creates the type mpibound*/
CreateBoundType(&my_bound);
...

Note that you won't be able to achieve your end goal to gather(v) such structures as the offsets are only valid for a single instance while the gather operation creates an array. Each element of the array will likely have different offsets and will therefore require a separate MPI datatype.

Since you are nevertheless allocating the full amount of memory for each of lat and lon, why not simply use arrays in the structure?

struct bound {
   int     n;
   char    name[10];
   double  lat[NPT_MAX];
   double  lon[NPT_MAX];
};

Don't forget to resize the MPI structure datatype after its creation to sizeof(struct bound) using MPI_Type_create_resized.

Also, note that in C the pointer to the structure is a pointer to its first element, so it is not necessary to compute the offset of n explicitly - it is guaranteed to be 0 by the language.



来源:https://stackoverflow.com/questions/41225554/using-mpi-type-create-struct-to-transfer-structs-containing-dynamic-arrays-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!