There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
There are no questions on this section at this time.
struct {
double mass ;
int force[FMAX] ;
} packet ;
But when I substitute:
struct {
double mass ;
int *force ;
} packet ;
packet.force = (int *) malloc (FMAX * sizeof(int)) ;
I find the program doesn't work. Specifically, the mass component of the struct
passes successfully from process to process, but not the force.
Why not?
array_of_displacements[1] = (char *) packet.force - (char *) &packet.mass ;which replaces these lines in the original program:
MPI_Type_extent (MPI_DOUBLE, &extent) ; array_of_displacements[1] = extent ;
When the force array is statically allocated by the compiler, the displacement of the second element in the struct is "extent"; however, when the force array is dynamically allocated with malloc, it is necessary to compute the force array's displacement. Afterall, who knows where in memory malloc will allocate the space for the force array? Its relationship to the beginning of the struct is not known as it is for the case the compiler statically allocates the space. So, we compute the displacement by subtracting the beginning of the struct (&packet.mass) from the dynamically allocated address for the force array (packet.force).
Casting the addresses as (char *) is important for two reasons. First, packet.force is a (int *) and &packet.mass is a (double *). C uses the underlying type (int and double in this case) to do its pointer arithmetic, so you want to have the same type when subtracting. The question then remains what underlying type to use. This brings us to the second important point. There is no requirement in C that any of the integral types be large enough to represent a pointer, although people often assume that type long or even int is large enough. It is dangerous to assume (int *) will work. One the other hand, any data pointer can be converted to type (char *) and back safely.
You may note that the array of blocklengths and the array of types remains the same.
Thanks to one of CTC's excellent staff members, John Zollweg, for his impressive insights that lead to the solution of your problem. He suggested running the program through the xldb debugger and see what was really happening. You might find running xldb a good further exercise. If so, check out the VW module titled Parallel Processing Performance Tools.
If you have not already looked at the solution program, malloc.c, here it is:
/* ----------------------------------------------------------------------- * Code: malloc.c * For: MPI Derived Datatypes VW module * This program sends data of mixed type (a C struct) * from one process to another. It shows how to use * the struct derived datatype with a component of the struct * being dynamically allocated. malloc.c is a modified version * of completed.c, a lab exercise code for the MPI Derived * Datatype module. * Usage: malloc * Runs on two nodes. * Author: Mike Hammill with many thanks to John Zollweg for his insights * Last revised: 6/28/96 MWH * ------------------------------------------------------------------------ */ #include "mpi.h" #define PACKET_BLOCKS 2 /* number of elements in struct */ #define FMAX 14 /* length of array of forces */ #define PACKETTAG 99 /* MPI tag for packet to be sent and received */ #define DESTRANK 1 /* rank of destination process */ #define SOURCERANK 0 /* rank of source process */ #define MYMASS 150.0 /* arbitrary constant */ main( argc, argv ) int argc ; char **argv ; { int array_of_blocklengths[PACKET_BLOCKS] = {1, FMAX}, /* for MPI struct */ i, /* loop index */ myrank ; /* rank in communicator of process */ MPI_Aint array_of_displacements[PACKET_BLOCKS] ; /* for MPI struct */ MPI_Datatype array_of_types[PACKET_BLOCKS] = {MPI_DOUBLE, MPI_INT}, /* for MPI struct */ packettype ; MPI_Status status ; /* status of received message */ /* We want to send packet, a contiguous C struct with mixed types. */ /* Declare packet prior to constructing a new derived datatype. */ struct{ double mass ; /* an object's mass */ int *force; /* ptr to array of forces */ } packet ; /* ------------------------------------------------------------------------ */ /* Initialize packet to zero. */ packet.mass = 0.0 ; packet.force = (int *) malloc ( FMAX * sizeof(int)) ; for (i=0; i < FMAX; i++) packet.force[i] = 0.0 ; /* Setup the MPI environment. */ MPI_Init( &argc, &argv ) ; MPI_Comm_rank( MPI_COMM_WORLD, &myrank ) ; printf ( "Task %d initialized\n", myrank ) ; /* Note that all the following variables are constants */ /* and depend only on the format of the C struct. */ array_of_displacements[0] = 0 ; /* This is the new code needed to determine the displacement of your dynamically allocated force array. Care must be taken not to cast addresses as (int *). There is no guarentee in C that an address will fit into an int */ array_of_displacements[1] = (char *) packet.force - (char *) &packet.mass ; /* Use these variables to create a new derived datatype and commit. */ MPI_Type_struct (PACKET_BLOCKS, array_of_blocklengths, array_of_displacements, array_of_types, &packettype) ; MPI_Type_commit (&packettype) ; /* ------------------------------------------------------------------------ */ if ( myrank == SOURCERANK ) { /* Give packet values so we can verify they get sent. */ packet.mass = MYMASS ; for (i=0; i < FMAX; i++) packet.force[i] = (i+1) * 100 ; /* Send packettype with count=1. */ MPI_Send( &packet, 1, packettype, DESTRANK, PACKETTAG, MPI_COMM_WORLD ) ; } /* ------------------------------------------------------------------------ */ else if ( myrank == DESTRANK ) { /* Task with DESTRANK will receive packettype with count=1 */ /* Print packet before the receive. */ printf ("Value of packet before receive:\n") ; printf ("Mass = %.3f \n", packet.mass) ; printf ("Array of forces = " ) ; for ( i=0; i < FMAX; i++ ) printf ("%d ", packet.force[i] ) ; printf ( "\n" ) ; MPI_Recv( &packet, 1, packettype, SOURCERANK, PACKETTAG, MPI_COMM_WORLD, &status ) ; /* Verify that structure got passed. */ /* Print packet before the receive. */ printf ("\nValue of packet after receive:\n") ; printf ("Mass = %.3f \n", packet.mass) ; printf ("Array of forces = " ) ; for ( i=0; i < FMAX; i++ ) printf ("%d ", packet.force[i] ) ; printf ( "\n" ) ; } /* ------------------------------------------------------------------------ */ MPI_Finalize() ; }
There are no questions on this section at this time.
© Copyright 1996 by Cornell University