Advice to users.
This example shows how to write a collective communication operation
that uses caching to be more efficient after the first call.
( End of advice to users.)
/* key for this module's stuff: */
static int gop_key = MPI_KEYVAL_INVALID;
typedef struct
{
int ref_count; /* reference count */
/* other stuff, whatever else we want */
} gop_stuff_type;
void Efficient_Collective_Op (MPI_Comm comm, ...)
{
gop_stuff_type *gop_stuff;
MPI_Group group;
int foundflag;
MPI_Comm_group(comm, &group);
if (gop_key == MPI_KEYVAL_INVALID) /* get a key on first call ever */
{
if ( ! MPI_Comm_create_keyval( gop_stuff_copier,
gop_stuff_destructor,
&gop_key, (void *)0) ) {
/* get the key while assigning its copy and delete callback
behavior. */
} else
MPI_Abort (comm, 99);
}
MPI_Comm_get_attr (comm, gop_key, &gop_stuff, &foundflag);
if (foundflag)
{ /* This module has executed in this group before.
We will use the cached information */
}
else
{ /* This is a group that we have not yet cached anything in.
We will now do so.
*/
/* First, allocate storage for the stuff we want,
and initialize the reference count */
gop_stuff = (gop_stuff_type *) malloc (sizeof(gop_stuff_type));
if (gop_stuff == NULL) { /* abort on out-of-memory error */ }
gop_stuff -> ref_count = 1;
/* Second, fill in *gop_stuff with whatever we want.
This part isn't shown here */
/* Third, store gop_stuff as the attribute value */
MPI_Comm_set_attr (comm, gop_key, gop_stuff);
}
/* Then, in any case, use contents of *gop_stuff
to do the global op ... */
}
/* The following routine is called by MPI when a group is freed */
int gop_stuff_destructor (MPI_Comm comm, int keyval, void *gop_stuffP,
void *extra)
{
gop_stuff_type *gop_stuff = (gop_stuff_type *)gop_stuffP;
if (keyval != gop_key) { /* abort -- programming error */ }
/* The group's being freed removes one reference to gop_stuff */
gop_stuff -> ref_count -= 1;
/* If no references remain, then free the storage */
if (gop_stuff -> ref_count == 0) {
free((void *)gop_stuff);
}
return MPI_SUCCESS;
}
/* The following routine is called by MPI when a group is copied */
int gop_stuff_copier (MPI_Comm comm, int keyval, void *extra,
void *gop_stuff_inP, void *gop_stuff_outP, int *flag)
{
gop_stuff_type *gop_stuff_in = (gop_stuff_type *)gop_stuff_inP;
gop_stuff_type **gop_stuff_out = (gop_stuff_type **)gop_stuff_outP;
if (keyval != gop_key) { /* abort -- programming error */ }
/* The new group adds one reference to this gop_stuff */
gop_stuff_in -> ref_count += 1;
*gop_stuff_out = gop_stuff_in;
return MPI_SUCCESS;
}