1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
4 * (C) 2001 by Argonne National Laboratory.
5 * See COPYRIGHT in top-level directory.
8 #include "mpitestconf.h"
10 #if defined(HAVE_STDIO_H) || defined(STDC_HEADERS)
13 #if defined(HAVE_STDLIB_H) || defined(STDC_HEADERS)
16 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
22 /* The following two includes permit the collection of resource usage
25 #ifdef HAVE_SYS_TIME_H
28 #ifdef HAVE_SYS_RESOURCE_H
29 #include <sys/resource.h>
35 * Utility routines for writing MPI tests.
37 * We check the return codes on all MPI routines (other than INIT)
38 * to allow the program that uses these routines to select MPI_ERRORS_RETURN
39 * as the error handler. We do *not* set MPI_ERRORS_RETURN because
40 * the code that makes use of these routines may not check return
45 static void MTestRMACleanup( void );
46 static void MTestResourceSummary( FILE * );
48 /* Here is where we could put the includes and definitions to enable
51 static int dbgflag = 0; /* Flag used for debugging */
52 static int wrank = -1; /* World rank */
53 static int verbose = 0; /* Message level (0 is none) */
54 static int returnWithVal = 0; /* Allow programs to return with a non-zero
55 if there was an error (may cause problems
56 with some runtime systems) */
57 static int usageOutput = 0; /* */
59 /* Provide backward portability to MPI 1 */
64 #define MPI_THREAD_SINGLE 0
68 * Initialize and Finalize MTest
72 Initialize MTest, initializing MPI if necessary.
74 Environment Variables:
75 + MPITEST_DEBUG - If set (to any value), turns on debugging output
76 . MPITEST_THREADLEVEL_DEFAULT - If set, use as the default "provided"
77 level of thread support. Applies to
78 MTest_Init but not MTest_Init_thread.
79 - MPITEST_VERBOSE - If set to a numeric value, turns on that level of
80 verbose output. This is used by the routine 'MTestPrintfMsg'
83 void MTest_Init_thread( int *argc, char ***argv, int required, int *provided )
88 MPI_Initialized( &flag );
90 /* Permit an MPI that claims only MPI 1 but includes the
91 MPI_Init_thread routine (e.g., IBM MPI) */
92 #if MPI_VERSION >= 2 || defined(HAVE_MPI_INIT_THREAD)
93 MPI_Init_thread( argc, argv, required, provided );
95 MPI_Init( argc, argv );
99 /* Check for debugging control */
100 if (getenv( "MPITEST_DEBUG" )) {
102 MPI_Comm_rank( MPI_COMM_WORLD, &wrank );
105 /* Check for verbose control */
106 envval = getenv( "MPITEST_VERBOSE" );
109 long val = strtol( envval, &s, 0 );
111 /* This is the error case for strtol */
112 fprintf( stderr, "Warning: %s not valid for MPITEST_VERBOSE\n",
121 fprintf( stderr, "Warning: %s not valid for MPITEST_VERBOSE\n",
127 /* Check for option to return success/failure in the return value of main */
128 envval = getenv( "MPITEST_RETURN_WITH_CODE" );
130 if (strcmp( envval, "yes" ) == 0 ||
131 strcmp( envval, "YES" ) == 0 ||
132 strcmp( envval, "true" ) == 0 ||
133 strcmp( envval, "TRUE" ) == 0) {
136 else if (strcmp( envval, "no" ) == 0 ||
137 strcmp( envval, "NO" ) == 0 ||
138 strcmp( envval, "false" ) == 0 ||
139 strcmp( envval, "FALSE" ) == 0) {
144 "Warning: %s not valid for MPITEST_RETURN_WITH_CODE\n",
150 /* Print rusage data if set */
151 if (getenv( "MPITEST_RUSAGE" )) {
156 * Initialize the tests, using an MPI-1 style init. Supports
157 * MTEST_THREADLEVEL_DEFAULT to test with user-specified thread level
159 void MTest_Init( int *argc, char ***argv )
162 #if MPI_VERSION >= 2 || defined(HAVE_MPI_INIT_THREAD)
166 threadLevel = MPI_THREAD_SINGLE;
167 str = getenv( "MTEST_THREADLEVEL_DEFAULT" );
168 if (!str) str = getenv( "MPITEST_THREADLEVEL_DEFAULT" );
170 if (strcmp(str,"MULTIPLE") == 0 || strcmp(str,"multiple") == 0) {
171 threadLevel = MPI_THREAD_MULTIPLE;
173 else if (strcmp(str,"SERIALIZED") == 0 ||
174 strcmp(str,"serialized") == 0) {
175 threadLevel = MPI_THREAD_SERIALIZED;
177 else if (strcmp(str,"FUNNELED") == 0 || strcmp(str,"funneled") == 0) {
178 threadLevel = MPI_THREAD_FUNNELED;
180 else if (strcmp(str,"SINGLE") == 0 || strcmp(str,"single") == 0) {
181 threadLevel = MPI_THREAD_SINGLE;
184 fprintf( stderr, "Unrecognized thread level %s\n", str );
185 /* Use exit since MPI_Init/Init_thread has not been called. */
189 MTest_Init_thread( argc, argv, threadLevel, &provided );
191 /* If the MPI_VERSION is 1, there is no MPI_THREAD_xxx defined */
192 MTest_Init_thread( argc, argv, 0, &provided );
197 Finalize MTest. errs is the number of errors on the calling process;
198 this routine will write the total number of errors over all of MPI_COMM_WORLD
199 to the process with rank zero, or " No Errors".
200 It does *not* finalize MPI.
202 void MTest_Finalize( int errs )
204 int rank, toterrs, merr;
206 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
207 if (merr) MTestPrintError( merr );
209 merr = MPI_Reduce( &errs, &toterrs, 1, MPI_INT, MPI_SUM,
211 if (merr) MTestPrintError( merr );
214 printf( " Found %d errors\n", toterrs );
217 printf( " No Errors\n" );
223 MTestResourceSummary( stdout );
226 /* Clean up any persistent objects that we allocated */
229 /* ------------------------------------------------------------------------ */
230 /* This routine may be used instead of "return 0;" at the end of main;
231 it allows the program to use the return value to signal success or failure.
233 int MTestReturnValue( int errors )
235 if (returnWithVal) return errors ? 1 : 0;
238 /* ------------------------------------------------------------------------ */
241 * Miscellaneous utilities, particularly to eliminate OS dependencies
243 * MTestSleep( seconds )
247 void MTestSleep( int sec )
253 void MTestSleep( int sec )
262 * Eventually, this could read a description of a file. For now, we hard
265 * Each kind of datatype has the following functions:
266 * MTestTypeXXXInit - Initialize a send buffer for that type
267 * MTestTypeXXXInitRecv - Initialize a receive buffer for that type
268 * MTestTypeXXXFree - Free any buffers associate with that type
269 * MTestTypeXXXCheckbuf - Check that the buffer contains the expected data
270 * These routines work with (nearly) any datatype that is of type XXX,
271 * allowing the test codes to create a variety of contiguous, vector, and
272 * indexed types, then test them by calling these routines.
274 * Available types (for the XXX) are
275 * Contig - Simple contiguous buffers
276 * Vector - Simple strided "vector" type
277 * Indexed - Indexed datatype. Only for a count of 1 instance of the
280 static int datatype_index = 0;
282 /* ------------------------------------------------------------------------ */
283 /* Datatype routines for contiguous datatypes */
284 /* ------------------------------------------------------------------------ */
286 * Setup contiguous buffers of n copies of a datatype.
288 static void *MTestTypeContigInit( MTestDatatype *mtype )
293 if (mtype->count > 0) {
296 merr = MPI_Type_extent( mtype->datatype, &size );
297 if (merr) MTestPrintError( merr );
298 totsize = size * mtype->count;
300 mtype->buf = (void *) malloc( totsize );
302 p = (signed char *)(mtype->buf);
304 /* Error - out of memory */
305 MTestError( "Out of memory in type buffer init" );
307 for (i=0; i<totsize; i++) {
308 p[i] = 0xff ^ (i & 0xff);
321 * Setup contiguous buffers of n copies of a datatype. Initialize for
322 * reception (e.g., set initial data to detect failure)
324 static void *MTestTypeContigInitRecv( MTestDatatype *mtype )
329 if (mtype->count > 0) {
332 merr = MPI_Type_extent( mtype->datatype, &size );
333 if (merr) MTestPrintError( merr );
334 totsize = size * mtype->count;
336 mtype->buf = (void *) malloc( totsize );
338 p = (signed char *)(mtype->buf);
340 /* Error - out of memory */
341 MTestError( "Out of memory in type buffer init" );
343 for (i=0; i<totsize; i++) {
355 static void *MTestTypeContigFree( MTestDatatype *mtype )
363 static int MTestTypeContigCheckbuf( MTestDatatype *mtype )
366 unsigned char expected;
367 int i, totsize, err = 0, merr;
370 p = (unsigned char *)mtype->buf;
372 merr = MPI_Type_extent( mtype->datatype, &size );
373 if (merr) MTestPrintError( merr );
374 totsize = size * mtype->count;
375 for (i=0; i<totsize; i++) {
376 expected = (0xff ^ (i & 0xff));
377 if (p[i] != expected) {
379 if (mtype->printErrors && err < 10) {
380 printf( "Data expected = %x but got p[%d] = %x\n",
390 /* ------------------------------------------------------------------------ */
391 /* Datatype routines for vector datatypes */
392 /* ------------------------------------------------------------------------ */
394 static void *MTestTypeVectorInit( MTestDatatype *mtype )
399 if (mtype->count > 0) {
401 int i, j, k, nc, totsize;
403 merr = MPI_Type_extent( mtype->datatype, &size );
404 if (merr) MTestPrintError( merr );
405 totsize = mtype->count * size;
407 mtype->buf = (void *) malloc( totsize );
409 p = (unsigned char *)(mtype->buf);
411 /* Error - out of memory */
412 MTestError( "Out of memory in type buffer init" );
415 /* First, set to -1 */
416 for (i=0; i<totsize; i++) p[i] = 0xff;
418 /* Now, set the actual elements to the successive values.
419 To do this, we need to run 3 loops */
421 /* count is usually one for a vector type */
422 for (k=0; k<mtype->count; k++) {
423 /* For each element (block) */
424 for (i=0; i<mtype->nelm; i++) {
426 for (j=0; j<mtype->blksize; j++) {
427 p[j] = (0xff ^ (nc & 0xff));
440 static void *MTestTypeVectorFree( MTestDatatype *mtype )
449 /* ------------------------------------------------------------------------ */
450 /* Datatype routines for indexed block datatypes */
451 /* ------------------------------------------------------------------------ */
454 * Setup a buffer for one copy of an indexed datatype.
456 static void *MTestTypeIndexedInit( MTestDatatype *mtype )
461 if (mtype->count > 1) {
462 MTestError( "This datatype is supported only for a single count" );
464 if (mtype->count == 1) {
468 /* Allocate the send/recv buffer */
469 merr = MPI_Type_extent( mtype->datatype, &totsize );
470 if (merr) MTestPrintError( merr );
472 mtype->buf = (void *) malloc( totsize );
474 p = (signed char *)(mtype->buf);
476 MTestError( "Out of memory in type buffer init\n" );
478 /* Initialize the elements */
479 /* First, set to -1 */
480 for (i=0; i<totsize; i++) p[i] = 0xff;
482 /* Now, set the actual elements to the successive values.
483 We require that the base type is a contiguous type */
485 for (i=0; i<mtype->nelm; i++) {
487 /* Compute the offset: */
488 offset = mtype->displs[i] * mtype->basesize;
489 /* For each element in the block */
490 for (b=0; b<mtype->index[i]; b++) {
491 for (j=0; j<mtype->basesize; j++) {
492 p[offset+j] = 0xff ^ (k++ & 0xff);
494 offset += mtype->basesize;
509 * Setup indexed buffers for 1 copy of a datatype. Initialize for
510 * reception (e.g., set initial data to detect failure)
512 static void *MTestTypeIndexedInitRecv( MTestDatatype *mtype )
517 if (mtype->count > 1) {
518 MTestError( "This datatype is supported only for a single count" );
520 if (mtype->count == 1) {
523 merr = MPI_Type_extent( mtype->datatype, &totsize );
524 if (merr) MTestPrintError( merr );
526 mtype->buf = (void *) malloc( totsize );
528 p = (signed char *)(mtype->buf);
530 /* Error - out of memory */
531 MTestError( "Out of memory in type buffer init\n" );
533 for (i=0; i<totsize; i++) {
547 static void *MTestTypeIndexedFree( MTestDatatype *mtype )
551 free( mtype->displs );
552 free( mtype->index );
559 static int MTestTypeIndexedCheckbuf( MTestDatatype *mtype )
562 unsigned char expected;
563 int i, err = 0, merr;
566 p = (unsigned char *)mtype->buf;
569 merr = MPI_Type_extent( mtype->datatype, &totsize );
570 if (merr) MTestPrintError( merr );
573 for (i=0; i<mtype->nelm; i++) {
575 /* Compute the offset: */
576 offset = mtype->displs[i] * mtype->basesize;
577 for (b=0; b<mtype->index[i]; b++) {
578 for (j=0; j<mtype->basesize; j++) {
579 expected = (0xff ^ (k & 0xff));
580 if (p[offset+j] != expected) {
582 if (mtype->printErrors && err < 10) {
583 printf( "Data expected = %x but got p[%d,%d] = %x\n",
584 expected, i,j, p[offset+j] );
590 offset += mtype->basesize;
598 /* ------------------------------------------------------------------------ */
599 /* Routines to select a datatype and associated buffer create/fill/check */
601 /* ------------------------------------------------------------------------ */
604 Create a range of datatypes with a given count elements.
605 This uses a selection of types, rather than an exhaustive collection.
606 It allocates both send and receive types so that they can have the same
607 type signature (collection of basic types) but different type maps (layouts
610 int MTestGetDatatypes( MTestDatatype *sendtype, MTestDatatype *recvtype,
616 sendtype->InitBuf = 0;
617 sendtype->FreeBuf = 0;
618 sendtype->CheckBuf = 0;
619 sendtype->datatype = 0;
620 sendtype->isBasic = 0;
621 sendtype->printErrors = 0;
622 recvtype->InitBuf = 0;
623 recvtype->FreeBuf = 0;
625 recvtype->CheckBuf = 0;
626 recvtype->datatype = 0;
627 recvtype->isBasic = 0;
628 recvtype->printErrors = 0;
633 /* Set the defaults for the message lengths */
634 sendtype->count = count;
635 recvtype->count = count;
636 /* Use datatype_index to choose a datatype to use. If at the end of the
638 switch (datatype_index) {
640 sendtype->datatype = MPI_INT;
641 sendtype->isBasic = 1;
642 recvtype->datatype = MPI_INT;
643 recvtype->isBasic = 1;
646 sendtype->datatype = MPI_DOUBLE;
647 sendtype->isBasic = 1;
648 recvtype->datatype = MPI_DOUBLE;
649 recvtype->isBasic = 1;
652 sendtype->datatype = MPI_FLOAT_INT;
653 sendtype->isBasic = 1;
654 recvtype->datatype = MPI_FLOAT_INT;
655 recvtype->isBasic = 1;
658 merr = MPI_Type_dup( MPI_INT, &sendtype->datatype );
659 if (merr) MTestPrintError( merr );
660 merr = MPI_Type_set_name( sendtype->datatype,
661 (char*)"dup of MPI_INT" );
662 if (merr) MTestPrintError( merr );
663 merr = MPI_Type_dup( MPI_INT, &recvtype->datatype );
664 if (merr) MTestPrintError( merr );
665 merr = MPI_Type_set_name( recvtype->datatype,
666 (char*)"dup of MPI_INT" );
667 if (merr) MTestPrintError( merr );
668 /* dup'ed types are already committed if the original type
669 was committed (MPI-2, section 8.8) */
672 /* vector send type and contiguous receive type */
673 /* These sizes are in bytes (see the VectorInit code) */
674 sendtype->stride = 3 * sizeof(int);
675 sendtype->blksize = sizeof(int);
676 sendtype->nelm = recvtype->count;
678 merr = MPI_Type_vector( recvtype->count, 1, 3, MPI_INT,
679 &sendtype->datatype );
680 if (merr) MTestPrintError( merr );
681 merr = MPI_Type_commit( &sendtype->datatype );
682 if (merr) MTestPrintError( merr );
683 merr = MPI_Type_set_name( sendtype->datatype,
684 (char*)"int-vector" );
685 if (merr) MTestPrintError( merr );
687 recvtype->datatype = MPI_INT;
688 recvtype->isBasic = 1;
689 sendtype->InitBuf = MTestTypeVectorInit;
690 recvtype->InitBuf = MTestTypeContigInitRecv;
691 sendtype->FreeBuf = MTestTypeVectorFree;
692 recvtype->FreeBuf = MTestTypeContigFree;
693 sendtype->CheckBuf = 0;
694 recvtype->CheckBuf = MTestTypeContigCheckbuf;
698 /* Indexed send using many small blocks and contig receive */
699 sendtype->blksize = sizeof(int);
700 sendtype->nelm = recvtype->count;
701 sendtype->basesize = sizeof(int);
702 sendtype->displs = (int *)malloc( sendtype->nelm * sizeof(int) );
703 sendtype->index = (int *)malloc( sendtype->nelm * sizeof(int) );
704 if (!sendtype->displs || !sendtype->index) {
705 MTestError( "Out of memory in type init\n" );
707 /* Make the sizes larger (4 ints) to help push the total
708 size to over 256k in some cases, as the MPICH code as of
709 10/1/06 used large internal buffers for packing non-contiguous
711 for (i=0; i<sendtype->nelm; i++) {
712 sendtype->index[i] = 4;
713 sendtype->displs[i] = 5*i;
715 merr = MPI_Type_indexed( sendtype->nelm,
716 sendtype->index, sendtype->displs,
717 MPI_INT, &sendtype->datatype );
718 if (merr) MTestPrintError( merr );
719 merr = MPI_Type_commit( &sendtype->datatype );
720 if (merr) MTestPrintError( merr );
721 merr = MPI_Type_set_name( sendtype->datatype,
722 (char*)"int-indexed(4-int)" );
723 if (merr) MTestPrintError( merr );
725 sendtype->InitBuf = MTestTypeIndexedInit;
726 sendtype->FreeBuf = MTestTypeIndexedFree;
727 sendtype->CheckBuf = 0;
729 recvtype->datatype = MPI_INT;
730 recvtype->isBasic = 1;
731 recvtype->count = count * 4;
732 recvtype->InitBuf = MTestTypeContigInitRecv;
733 recvtype->FreeBuf = MTestTypeContigFree;
734 recvtype->CheckBuf = MTestTypeContigCheckbuf;
738 /* Indexed send using 2 large blocks and contig receive */
739 sendtype->blksize = sizeof(int);
741 sendtype->basesize = sizeof(int);
742 sendtype->displs = (int *)malloc( sendtype->nelm * sizeof(int) );
743 sendtype->index = (int *)malloc( sendtype->nelm * sizeof(int) );
744 if (!sendtype->displs || !sendtype->index) {
745 MTestError( "Out of memory in type init\n" );
747 /* index -> block size */
748 sendtype->index[0] = (recvtype->count + 1) / 2;
749 sendtype->displs[0] = 0;
750 sendtype->index[1] = recvtype->count - sendtype->index[0];
751 sendtype->displs[1] = sendtype->index[0] + 1;
752 /* There is a deliberate gap here */
754 merr = MPI_Type_indexed( sendtype->nelm,
755 sendtype->index, sendtype->displs,
756 MPI_INT, &sendtype->datatype );
757 if (merr) MTestPrintError( merr );
758 merr = MPI_Type_commit( &sendtype->datatype );
759 if (merr) MTestPrintError( merr );
760 merr = MPI_Type_set_name( sendtype->datatype,
761 (char*)"int-indexed(2 blocks)" );
762 if (merr) MTestPrintError( merr );
764 sendtype->InitBuf = MTestTypeIndexedInit;
765 sendtype->FreeBuf = MTestTypeIndexedFree;
766 sendtype->CheckBuf = 0;
768 recvtype->datatype = MPI_INT;
769 recvtype->isBasic = 1;
770 recvtype->count = sendtype->index[0] + sendtype->index[1];
771 recvtype->InitBuf = MTestTypeContigInitRecv;
772 recvtype->FreeBuf = MTestTypeContigFree;
773 recvtype->CheckBuf = MTestTypeContigCheckbuf;
777 /* Indexed receive using many small blocks and contig send */
778 recvtype->blksize = sizeof(int);
779 recvtype->nelm = recvtype->count;
780 recvtype->basesize = sizeof(int);
781 recvtype->displs = (int *)malloc( recvtype->nelm * sizeof(int) );
782 recvtype->index = (int *)malloc( recvtype->nelm * sizeof(int) );
783 if (!recvtype->displs || !recvtype->index) {
784 MTestError( "Out of memory in type recv init\n" );
786 /* Make the sizes larger (4 ints) to help push the total
787 size to over 256k in some cases, as the MPICH code as of
788 10/1/06 used large internal buffers for packing non-contiguous
790 /* Note that there are gaps in the indexed type */
791 for (i=0; i<recvtype->nelm; i++) {
792 recvtype->index[i] = 4;
793 recvtype->displs[i] = 5*i;
795 merr = MPI_Type_indexed( recvtype->nelm,
796 recvtype->index, recvtype->displs,
797 MPI_INT, &recvtype->datatype );
798 if (merr) MTestPrintError( merr );
799 merr = MPI_Type_commit( &recvtype->datatype );
800 if (merr) MTestPrintError( merr );
801 merr = MPI_Type_set_name( recvtype->datatype,
802 (char*)"recv-int-indexed(4-int)" );
803 if (merr) MTestPrintError( merr );
805 recvtype->InitBuf = MTestTypeIndexedInitRecv;
806 recvtype->FreeBuf = MTestTypeIndexedFree;
807 recvtype->CheckBuf = MTestTypeIndexedCheckbuf;
809 sendtype->datatype = MPI_INT;
810 sendtype->isBasic = 1;
811 sendtype->count = count * 4;
812 sendtype->InitBuf = MTestTypeContigInit;
813 sendtype->FreeBuf = MTestTypeContigFree;
814 sendtype->CheckBuf = 0;
817 /* Less commonly used but still simple types */
819 sendtype->datatype = MPI_SHORT;
820 sendtype->isBasic = 1;
821 recvtype->datatype = MPI_SHORT;
822 recvtype->isBasic = 1;
825 sendtype->datatype = MPI_LONG;
826 sendtype->isBasic = 1;
827 recvtype->datatype = MPI_LONG;
828 recvtype->isBasic = 1;
831 sendtype->datatype = MPI_CHAR;
832 sendtype->isBasic = 1;
833 recvtype->datatype = MPI_CHAR;
834 recvtype->isBasic = 1;
837 sendtype->datatype = MPI_UINT64_T;
838 sendtype->isBasic = 1;
839 recvtype->datatype = MPI_UINT64_T;
840 recvtype->isBasic = 1;
843 sendtype->datatype = MPI_FLOAT;
844 sendtype->isBasic = 1;
845 recvtype->datatype = MPI_FLOAT;
846 recvtype->isBasic = 1;
849 #ifndef USE_STRICT_MPI
850 /* MPI_BYTE may only be used with MPI_BYTE in strict MPI */
852 sendtype->datatype = MPI_INT;
853 sendtype->isBasic = 1;
854 recvtype->datatype = MPI_BYTE;
855 recvtype->isBasic = 1;
856 recvtype->count *= sizeof(int);
863 if (!sendtype->InitBuf) {
864 sendtype->InitBuf = MTestTypeContigInit;
865 recvtype->InitBuf = MTestTypeContigInitRecv;
866 sendtype->FreeBuf = MTestTypeContigFree;
867 recvtype->FreeBuf = MTestTypeContigFree;
868 sendtype->CheckBuf = MTestTypeContigCheckbuf;
869 recvtype->CheckBuf = MTestTypeContigCheckbuf;
873 if (dbgflag && datatype_index > 0) {
875 fprintf( stderr, "%d: sendtype is %s\n", wrank, MTestGetDatatypeName( sendtype ) );
876 merr = MPI_Type_size( sendtype->datatype, &typesize );
877 if (merr) MTestPrintError( merr );
878 fprintf( stderr, "%d: sendtype size = %d\n", wrank, typesize );
879 fprintf( stderr, "%d: recvtype is %s\n", wrank, MTestGetDatatypeName( recvtype ) );
880 merr = MPI_Type_size( recvtype->datatype, &typesize );
881 if (merr) MTestPrintError( merr );
882 fprintf( stderr, "%d: recvtype size = %d\n", wrank, typesize );
886 else if (verbose && datatype_index > 0) {
887 printf( "Get new datatypes: send = %s, recv = %s\n",
888 MTestGetDatatypeName( sendtype ),
889 MTestGetDatatypeName( recvtype ) );
893 return datatype_index;
896 /* Reset the datatype index (start from the initial data type.
897 Note: This routine is rarely needed; MTestGetDatatypes automatically
898 starts over after the last available datatype is used.
900 void MTestResetDatatypes( void )
904 /* Return the index of the current datatype. This is rarely needed and
905 is provided mostly to enable debugging of the MTest package itself */
906 int MTestGetDatatypeIndex( void )
908 return datatype_index;
911 /* Free the storage associated with a datatype */
912 void MTestFreeDatatype( MTestDatatype *mtype )
915 /* Invoke a datatype-specific free function to handle
916 both the datatype and the send/receive buffers */
917 if (mtype->FreeBuf) {
918 (mtype->FreeBuf)( mtype );
920 /* Free the datatype itself if it was created */
921 if (!mtype->isBasic) {
922 merr = MPI_Type_free( &mtype->datatype );
923 if (merr) MTestPrintError( merr );
927 /* Check that a message was received correctly. Returns the number of
928 errors detected. Status may be NULL or MPI_STATUS_IGNORE */
929 int MTestCheckRecv( MPI_Status *status, MTestDatatype *recvtype )
934 if (status && status != MPI_STATUS_IGNORE) {
935 merr = MPI_Get_count( status, recvtype->datatype, &count );
936 if (merr) MTestPrintError( merr );
938 /* Check count against expected count */
939 if (count != recvtype->count) {
944 /* Check received data */
945 if (!errs && recvtype->CheckBuf( recvtype )) {
951 /* This next routine uses a circular buffer of static name arrays just to
952 simplify the use of the routine */
953 const char *MTestGetDatatypeName( MTestDatatype *dtype )
955 static char name[4][MPI_MAX_OBJECT_NAME];
960 merr = MPI_Type_get_name( dtype->datatype, name[sp], &rlen );
961 if (merr) MTestPrintError( merr );
962 return (const char *)name[sp++];
964 /* ----------------------------------------------------------------------- */
967 * Create communicators. Use separate routines for inter and intra
968 * communicators (there is a routine to give both)
969 * Note that the routines may return MPI_COMM_NULL, so code should test for
970 * that return value as well.
973 static int interCommIdx = 0;
974 static int intraCommIdx = 0;
975 static const char *intraCommName = 0;
976 static const char *interCommName = 0;
979 * Get an intracommunicator with at least min_size members. If "allowSmaller"
980 * is true, allow the communicator to be smaller than MPI_COMM_WORLD and
981 * for this routine to return MPI_COMM_NULL for some values. Returns 0 if
982 * no more communicators are available.
984 int MTestGetIntracommGeneral( MPI_Comm *comm, int min_size, int allowSmaller )
986 int size, rank, merr;
990 /* The while loop allows us to skip communicators that are too small.
991 MPI_COMM_NULL is always considered large enough */
995 switch (intraCommIdx) {
997 *comm = MPI_COMM_WORLD;
999 intraCommName = "MPI_COMM_WORLD";
1003 merr = MPI_Comm_dup(MPI_COMM_WORLD, comm );
1004 if (merr) MTestPrintError( merr );
1005 intraCommName = "Dup of MPI_COMM_WORLD";
1009 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1010 if (merr) MTestPrintError( merr );
1011 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1012 if (merr) MTestPrintError( merr );
1013 merr = MPI_Comm_split( MPI_COMM_WORLD, 0, size-rank, comm );
1014 if (merr) MTestPrintError( merr );
1015 intraCommName = "Rank reverse of MPI_COMM_WORLD";
1018 /* subset of world, with reversed ranks */
1019 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1020 if (merr) MTestPrintError( merr );
1021 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1022 if (merr) MTestPrintError( merr );
1023 merr = MPI_Comm_split( MPI_COMM_WORLD, ((rank < size/2) ? 1 : MPI_UNDEFINED),
1025 if (merr) MTestPrintError( merr );
1026 intraCommName = "Rank reverse of half of MPI_COMM_WORLD";
1029 *comm = MPI_COMM_SELF;
1031 intraCommName = "MPI_COMM_SELF";
1034 /* These next cases are communicators that include some
1035 but not all of the processes */
1042 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1043 if (merr) MTestPrintError( merr );
1044 newsize = size - (intraCommIdx - 4);
1046 if (allowSmaller && newsize >= min_size) {
1047 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1048 if (merr) MTestPrintError( merr );
1049 merr = MPI_Comm_split( MPI_COMM_WORLD, rank < newsize, rank,
1051 if (merr) MTestPrintError( merr );
1052 if (rank >= newsize) {
1053 merr = MPI_Comm_free( comm );
1054 if (merr) MTestPrintError( merr );
1055 *comm = MPI_COMM_NULL;
1058 intraCommName = "Split of WORLD";
1062 /* Act like default */
1063 *comm = MPI_COMM_NULL;
1069 /* Other ideas: dup of self, cart comm, graph comm */
1071 *comm = MPI_COMM_NULL;
1076 if (*comm != MPI_COMM_NULL) {
1077 merr = MPI_Comm_size( *comm, &size );
1078 if (merr) MTestPrintError( merr );
1079 if (size >= min_size)
1083 intraCommName = "MPI_COMM_NULL";
1088 /* we are only done if all processes are done */
1089 MPI_Allreduce(&done2, &done, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD);
1091 /* Advance the comm index whether we are done or not, otherwise we could
1092 * spin forever trying to allocate a too-small communicator over and
1096 if (!done && !isBasic && *comm != MPI_COMM_NULL) {
1097 /* avoid leaking communicators */
1098 merr = MPI_Comm_free(comm);
1099 if (merr) MTestPrintError(merr);
1103 return intraCommIdx;
1107 * Get an intracommunicator with at least min_size members.
1109 int MTestGetIntracomm( MPI_Comm *comm, int min_size )
1111 return MTestGetIntracommGeneral( comm, min_size, 0 );
1114 /* Return the name of an intra communicator */
1115 const char *MTestGetIntracommName( void )
1117 return intraCommName;
1121 * Return an intercomm; set isLeftGroup to 1 if the calling process is
1122 * a member of the "left" group.
1124 int MTestGetIntercomm( MPI_Comm *comm, int *isLeftGroup, int min_size )
1126 int size, rank, remsize, merr;
1128 MPI_Comm mcomm = MPI_COMM_NULL;
1129 MPI_Comm mcomm2 = MPI_COMM_NULL;
1132 /* The while loop allows us to skip communicators that are too small.
1133 MPI_COMM_NULL is always considered large enough. The size is
1134 the sum of the sizes of the local and remote groups */
1136 *comm = MPI_COMM_NULL;
1138 interCommName = "MPI_COMM_NULL";
1140 switch (interCommIdx) {
1142 /* Split comm world in half */
1143 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1144 if (merr) MTestPrintError( merr );
1145 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1146 if (merr) MTestPrintError( merr );
1148 merr = MPI_Comm_split( MPI_COMM_WORLD, (rank < size/2), rank,
1150 if (merr) MTestPrintError( merr );
1154 else if (rank == size/2) {
1158 /* Remote leader is signficant only for the processes
1159 designated local leaders */
1162 *isLeftGroup = rank < size/2;
1163 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD, rleader,
1165 if (merr) MTestPrintError( merr );
1166 interCommName = "Intercomm by splitting MPI_COMM_WORLD";
1169 *comm = MPI_COMM_NULL;
1172 /* Split comm world in to 1 and the rest */
1173 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1174 if (merr) MTestPrintError( merr );
1175 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1176 if (merr) MTestPrintError( merr );
1178 merr = MPI_Comm_split( MPI_COMM_WORLD, rank == 0, rank,
1180 if (merr) MTestPrintError( merr );
1184 else if (rank == 1) {
1188 /* Remote leader is signficant only for the processes
1189 designated local leaders */
1192 *isLeftGroup = rank == 0;
1193 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD,
1194 rleader, 12346, comm );
1195 if (merr) MTestPrintError( merr );
1196 interCommName = "Intercomm by splitting MPI_COMM_WORLD into 1, rest";
1199 *comm = MPI_COMM_NULL;
1203 /* Split comm world in to 2 and the rest */
1204 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1205 if (merr) MTestPrintError( merr );
1206 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1207 if (merr) MTestPrintError( merr );
1209 merr = MPI_Comm_split( MPI_COMM_WORLD, rank < 2, rank,
1211 if (merr) MTestPrintError( merr );
1215 else if (rank == 2) {
1219 /* Remote leader is signficant only for the processes
1220 designated local leaders */
1223 *isLeftGroup = rank < 2;
1224 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD,
1225 rleader, 12347, comm );
1226 if (merr) MTestPrintError( merr );
1227 interCommName = "Intercomm by splitting MPI_COMM_WORLD into 2, rest";
1230 *comm = MPI_COMM_NULL;
1234 /* Split comm world in half, then dup */
1235 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1236 if (merr) MTestPrintError( merr );
1237 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1238 if (merr) MTestPrintError( merr );
1240 merr = MPI_Comm_split( MPI_COMM_WORLD, (rank < size/2), rank,
1242 if (merr) MTestPrintError( merr );
1246 else if (rank == size/2) {
1250 /* Remote leader is signficant only for the processes
1251 designated local leaders */
1254 *isLeftGroup = rank < size/2;
1255 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD, rleader,
1257 if (merr) MTestPrintError( merr );
1258 /* avoid leaking after assignment below */
1259 merr = MPI_Comm_free( &mcomm );
1260 if (merr) MTestPrintError( merr );
1262 /* now dup, some bugs only occur for dup's of intercomms */
1264 merr = MPI_Comm_dup(mcomm, comm);
1265 if (merr) MTestPrintError( merr );
1266 interCommName = "Intercomm by splitting MPI_COMM_WORLD then dup'ing";
1269 *comm = MPI_COMM_NULL;
1273 /* Split comm world in half, form intercomm, then split that intercomm */
1274 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1275 if (merr) MTestPrintError( merr );
1276 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1277 if (merr) MTestPrintError( merr );
1279 merr = MPI_Comm_split( MPI_COMM_WORLD, (rank < size/2), rank,
1281 if (merr) MTestPrintError( merr );
1285 else if (rank == size/2) {
1289 /* Remote leader is signficant only for the processes
1290 designated local leaders */
1293 *isLeftGroup = rank < size/2;
1294 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD, rleader,
1296 if (merr) MTestPrintError( merr );
1297 /* avoid leaking after assignment below */
1298 merr = MPI_Comm_free( &mcomm );
1299 if (merr) MTestPrintError( merr );
1301 /* now split, some bugs only occur for splits of intercomms */
1303 rank = MPI_Comm_rank(mcomm, &rank);
1304 if (merr) MTestPrintError( merr );
1305 /* this split is effectively a dup but tests the split code paths */
1306 merr = MPI_Comm_split(mcomm, 0, rank, comm);
1307 if (merr) MTestPrintError( merr );
1308 interCommName = "Intercomm by splitting MPI_COMM_WORLD then then splitting again";
1311 *comm = MPI_COMM_NULL;
1315 /* split comm world in half discarding rank 0 on the "left"
1316 * communicator, then form them into an intercommunicator */
1317 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1318 if (merr) MTestPrintError( merr );
1319 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1320 if (merr) MTestPrintError( merr );
1322 int color = (rank < size/2 ? 0 : 1);
1324 color = MPI_UNDEFINED;
1326 merr = MPI_Comm_split( MPI_COMM_WORLD, color, rank, &mcomm );
1327 if (merr) MTestPrintError( merr );
1332 else if (rank == (size/2)) {
1336 /* Remote leader is signficant only for the processes
1337 designated local leaders */
1340 *isLeftGroup = rank < size/2;
1341 if (rank != 0) { /* 0's mcomm is MPI_COMM_NULL */
1342 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD, rleader, 12345, comm );
1343 if (merr) MTestPrintError( merr );
1345 interCommName = "Intercomm by splitting MPI_COMM_WORLD (discarding rank 0 in the left group) then MPI_Intercomm_create'ing";
1348 *comm = MPI_COMM_NULL;
1353 /* Split comm world in half then form them into an
1354 * intercommunicator. Then discard rank 0 from each group of the
1355 * intercomm via MPI_Comm_create. */
1356 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1357 if (merr) MTestPrintError( merr );
1358 merr = MPI_Comm_size( MPI_COMM_WORLD, &size );
1359 if (merr) MTestPrintError( merr );
1361 MPI_Group oldgroup, newgroup;
1363 int color = (rank < size/2 ? 0 : 1);
1365 merr = MPI_Comm_split( MPI_COMM_WORLD, color, rank, &mcomm );
1366 if (merr) MTestPrintError( merr );
1371 else if (rank == (size/2)) {
1375 /* Remote leader is signficant only for the processes
1376 designated local leaders */
1379 *isLeftGroup = rank < size/2;
1380 merr = MPI_Intercomm_create( mcomm, 0, MPI_COMM_WORLD, rleader, 12345, &mcomm2 );
1381 if (merr) MTestPrintError( merr );
1383 /* We have an intercomm between the two halves of comm world. Now create
1384 * a new intercomm that removes rank 0 on each side. */
1385 merr = MPI_Comm_group(mcomm2, &oldgroup);
1386 if (merr) MTestPrintError( merr );
1388 merr = MPI_Group_excl(oldgroup, 1, ranks, &newgroup);
1389 if (merr) MTestPrintError( merr );
1390 merr = MPI_Comm_create(mcomm2, newgroup, comm);
1391 if (merr) MTestPrintError( merr );
1393 merr = MPI_Group_free(&oldgroup);
1394 if (merr) MTestPrintError( merr );
1395 merr = MPI_Group_free(&newgroup);
1396 if (merr) MTestPrintError( merr );
1398 interCommName = "Intercomm by splitting MPI_COMM_WORLD then discarding 0 ranks with MPI_Comm_create";
1401 *comm = MPI_COMM_NULL;
1406 *comm = MPI_COMM_NULL;
1411 if (*comm != MPI_COMM_NULL) {
1412 merr = MPI_Comm_size( *comm, &size );
1413 if (merr) MTestPrintError( merr );
1414 merr = MPI_Comm_remote_size( *comm, &remsize );
1415 if (merr) MTestPrintError( merr );
1416 if (size + remsize >= min_size) done = 1;
1419 interCommName = "MPI_COMM_NULL";
1423 /* we are only done if all processes are done */
1424 MPI_Allreduce(MPI_IN_PLACE, &done, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD);
1426 /* Advance the comm index whether we are done or not, otherwise we could
1427 * spin forever trying to allocate a too-small communicator over and
1431 if (!done && *comm != MPI_COMM_NULL) {
1432 /* avoid leaking communicators */
1433 merr = MPI_Comm_free(comm);
1434 if (merr) MTestPrintError(merr);
1437 /* cleanup for common temp objects */
1438 if (mcomm != MPI_COMM_NULL) {
1439 merr = MPI_Comm_free(&mcomm);
1440 if (merr) MTestPrintError( merr );
1442 if (mcomm2 != MPI_COMM_NULL) {
1443 merr = MPI_Comm_free(&mcomm2);
1444 if (merr) MTestPrintError( merr );
1448 return interCommIdx;
1450 /* Return the name of an intercommunicator */
1451 const char *MTestGetIntercommName( void )
1453 return interCommName;
1456 /* Get a communicator of a given minimum size. Both intra and inter
1457 communicators are provided */
1458 int MTestGetComm( MPI_Comm *comm, int min_size )
1461 static int getinter = 0;
1464 idx = MTestGetIntracomm( comm, min_size );
1471 idx = MTestGetIntercomm( comm, &isLeft, min_size );
1480 /* Free a communicator. It may be called with a predefined communicator
1482 void MTestFreeComm( MPI_Comm *comm )
1485 if (*comm != MPI_COMM_WORLD &&
1486 *comm != MPI_COMM_SELF &&
1487 *comm != MPI_COMM_NULL) {
1488 merr = MPI_Comm_free( comm );
1489 if (merr) MTestPrintError( merr );
1493 /* ------------------------------------------------------------------------ */
1494 void MTestPrintError( int errcode )
1497 char string[MPI_MAX_ERROR_STRING];
1499 MPI_Error_class( errcode, &errclass );
1500 MPI_Error_string( errcode, string, &slen );
1501 printf( "Error class %d (%s)\n", errclass, string );
1504 void MTestPrintErrorMsg( const char msg[], int errcode )
1507 char string[MPI_MAX_ERROR_STRING];
1509 MPI_Error_class( errcode, &errclass );
1510 MPI_Error_string( errcode, string, &slen );
1511 printf( "%s: Error class %d (%s)\n", msg, errclass, string );
1514 /* ------------------------------------------------------------------------ */
1516 If verbose output is selected and the level is at least that of the
1517 value of the verbose flag, then perform printf( format, ... );
1519 void MTestPrintfMsg( int level, const char format[], ... )
1523 if (verbose && level >= verbose) {
1524 va_start(list,format);
1525 vprintf( format, list );
1530 /* Fatal error. Report and exit */
1531 void MTestError( const char *msg )
1533 fprintf( stderr, "%s\n", msg );
1535 MPI_Abort( MPI_COMM_WORLD, 1 );
1538 /* ------------------------------------------------------------------------ */
1539 static void MTestResourceSummary( FILE *fp )
1541 #ifdef HAVE_GETRUSAGE
1543 static int pfThreshold = -2;
1545 if (getrusage( RUSAGE_SELF, &ru ) == 0) {
1546 /* There is an option to generate output only when a resource
1547 exceeds a threshold. To date, only page faults supported. */
1548 if (pfThreshold == -2) {
1549 char *p = getenv("MPITEST_RUSAGE_PF");
1552 pfThreshold = strtol( p, 0, 0 );
1555 if (pfThreshold > 0) {
1556 doOutput = ru.ru_minflt > pfThreshold;
1559 /* Cast values to long in case some system has defined them
1560 as another integer type */
1561 fprintf( fp, "RUSAGE: max resident set = %ldKB\n",
1562 (long)ru.ru_maxrss );
1563 fprintf( fp, "RUSAGE: page faults = %ld : %ld\n",
1564 (long)ru.ru_minflt, (long)ru.ru_majflt );
1565 /* Not every Unix provides useful information for the xxrss fields */
1566 fprintf( fp, "RUSAGE: memory in text/data/stack = %ld : %ld : %ld\n",
1567 (long)ru.ru_ixrss, (long)ru.ru_idrss, (long)ru.ru_isrss );
1568 fprintf( fp, "RUSAGE: I/O in and out = %ld : %ld\n",
1569 (long)ru.ru_inblock, (long)ru.ru_oublock );
1570 fprintf( fp, "RUSAGE: context switch = %ld : %ld\n",
1571 (long)ru.ru_nvcsw, (long)ru.ru_nivcsw );
1575 fprintf( fp, "RUSAGE: return error %d\n", errno );
1579 /* ------------------------------------------------------------------------ */
1580 #ifdef HAVE_MPI_WIN_CREATE
1582 * Create MPI Windows
1584 static int win_index = 0;
1585 static const char *winName;
1586 /* Use an attribute to remember the type of memory allocation (static,
1587 malloc, or MPI_Alloc_mem) */
1588 static int mem_keyval = MPI_KEYVAL_INVALID;
1589 int MTestGetWin( MPI_Win *win, int mustBePassive )
1591 static char actbuf[1024];
1592 static char *pasbuf;
1597 if (mem_keyval == MPI_KEYVAL_INVALID) {
1598 /* Create the keyval */
1599 merr = MPI_Win_create_keyval( MPI_WIN_NULL_COPY_FN,
1600 MPI_WIN_NULL_DELETE_FN,
1602 if (merr) MTestPrintError( merr );
1606 switch (win_index) {
1608 /* Active target window */
1609 merr = MPI_Win_create( actbuf, 1024, 1, MPI_INFO_NULL, MPI_COMM_WORLD,
1611 if (merr) MTestPrintError( merr );
1612 winName = "active-window";
1613 merr = MPI_Win_set_attr( *win, mem_keyval, (void *)0 );
1614 if (merr) MTestPrintError( merr );
1617 /* Passive target window */
1618 merr = MPI_Alloc_mem( 1024, MPI_INFO_NULL, &pasbuf );
1619 if (merr) MTestPrintError( merr );
1620 merr = MPI_Win_create( pasbuf, 1024, 1, MPI_INFO_NULL, MPI_COMM_WORLD,
1622 if (merr) MTestPrintError( merr );
1623 winName = "passive-window";
1624 merr = MPI_Win_set_attr( *win, mem_keyval, (void *)2 );
1625 if (merr) MTestPrintError( merr );
1628 /* Active target; all windows different sizes */
1629 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1630 if (merr) MTestPrintError( merr );
1633 buf = (char *)malloc( n );
1636 merr = MPI_Win_create( buf, n, 1, MPI_INFO_NULL, MPI_COMM_WORLD,
1638 if (merr) MTestPrintError( merr );
1639 winName = "active-all-different-win";
1640 merr = MPI_Win_set_attr( *win, mem_keyval, (void *)1 );
1641 if (merr) MTestPrintError( merr );
1644 /* Active target, no locks set */
1645 merr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1646 if (merr) MTestPrintError( merr );
1649 buf = (char *)malloc( n );
1652 merr = MPI_Info_create( &info );
1653 if (merr) MTestPrintError( merr );
1654 merr = MPI_Info_set( info, (char*)"nolocks", (char*)"true" );
1655 if (merr) MTestPrintError( merr );
1656 merr = MPI_Win_create( buf, n, 1, info, MPI_COMM_WORLD, win );
1657 if (merr) MTestPrintError( merr );
1658 merr = MPI_Info_free( &info );
1659 if (merr) MTestPrintError( merr );
1660 winName = "active-nolocks-all-different-win";
1661 merr = MPI_Win_set_attr( *win, mem_keyval, (void *)1 );
1662 if (merr) MTestPrintError( merr );
1670 /* Return a pointer to the name associated with a window object */
1671 const char *MTestGetWinName( void )
1675 /* Free the storage associated with a window object */
1676 void MTestFreeWin( MPI_Win *win )
1681 merr = MPI_Win_get_attr( *win, MPI_WIN_BASE, &addr, &flag );
1682 if (merr) MTestPrintError( merr );
1684 MTestError( "Could not get WIN_BASE from window" );
1688 merr = MPI_Win_get_attr( *win, mem_keyval, &val, &flag );
1689 if (merr) MTestPrintError( merr );
1691 if (val == (void *)1) {
1694 else if (val == (void *)2) {
1695 merr = MPI_Free_mem( addr );
1696 if (merr) MTestPrintError( merr );
1698 /* if val == (void *)0, then static data that must not be freed */
1701 merr = MPI_Win_free(win);
1702 if (merr) MTestPrintError( merr );
1704 static void MTestRMACleanup( void )
1706 if (mem_keyval != MPI_KEYVAL_INVALID) {
1707 MPI_Win_free_keyval( &mem_keyval );
1711 static void MTestRMACleanup( void ) {}