5.7.2 Attributes Example

Advice to users. This example shows how to write a collective communication operation that uses caching to be more efficient after the first call. The coding style assumes that MPI function results return only error statuses.(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;

   Efficient_Collective_Op (comm, ...)
   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_keyval_create( gop_stuff_copier,
                                gop_stuff_destructor,
                                &gop_key, (void *)0));
       /* get the key while assigning its copy and delete callback
          behavior. */

       MPI_Abort (comm, 99);
     }

     MPI_Attr_get (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_Attr_put ( 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 */

   gop_stuff_destructor (comm, keyval, gop_stuff, extra)
   MPI_Comm comm;
   int keyval;
   gop_stuff_type *gop_stuff;
   void *extra;
   {
     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);
     }
   }

   /* The following routine is called by MPI when a group is copied */
   gop_stuff_copier (comm, keyval, extra, gop_stuff_in, gop_stuff_out, flag)
   MPI_Comm comm;
   int keyval;
   gop_stuff_type *gop_stuff_in, *gop_stuff_out;
   void *extra;
   {
     if (keyval != gop_key) { /* abort -- programming error */ }

     /* The new group adds one reference to this gop_stuff */
     gop_stuff -> ref_count += 1;
     gop_stuff_out = gop_stuff_in;
   }

MPI-Standard for MARMOT