Blame test/mpi/cxx/util/mtest.cxx

Packit 0848f5
/* -*- Mode: C++; c-basic-offset:4 ; -*- */
Packit 0848f5
/*
Packit 0848f5
 *
Packit 0848f5
 *  (C) 2001 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
#include "mpi.h"
Packit 0848f5
#include "mpitestconf.h"
Packit 0848f5
#ifdef HAVE_IOSTREAM
Packit 0848f5
// Not all C++ compilers have iostream instead of iostream.h
Packit 0848f5
#include <iostream>
Packit 0848f5
#ifdef HAVE_NAMESPACE_STD
Packit 0848f5
// Those that do often need the std namespace; otherwise, a bare "cout"
Packit 0848f5
// is likely to fail to compile
Packit 0848f5
using namespace std;
Packit 0848f5
#endif
Packit 0848f5
#else
Packit 0848f5
#include <iostream.h>
Packit 0848f5
#endif
Packit 0848f5
#include "mpitestcxx.h"
Packit 0848f5
#include <stdlib.h>
Packit 0848f5
#include <string.h>
Packit 0848f5
Packit 0848f5
static int dbgflag = 0;         /* Flag used for debugging */
Packit 0848f5
static int wrank = -1;          /* World rank */
Packit 0848f5
static int verbose = 0;         /* Message level (0 is none) */
Packit 0848f5
Packit 0848f5
static void MTestRMACleanup( void );
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Initialize and Finalize MTest
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
   Initialize MTest, initializing MPI if necessary.  
Packit 0848f5
Packit 0848f5
 Environment Variables:
Packit 0848f5
+ MPITEST_DEBUG - If set (to any value), turns on debugging output
Packit 0848f5
- MPITEST_VERBOSE - If set to a numeric value, turns on that level of
Packit 0848f5
  verbose output.
Packit 0848f5
Packit 0848f5
 */
Packit 0848f5
void MTest_Init( void )
Packit 0848f5
{
Packit 0848f5
    bool flag;
Packit 0848f5
    const char *envval = 0;
Packit 0848f5
    int        threadLevel, provided;
Packit 0848f5
Packit 0848f5
    threadLevel = MPI::THREAD_SINGLE;
Packit 0848f5
    envval = getenv( "MTEST_THREADLEVEL_DEFAULT" );
Packit 0848f5
    if (envval && *envval) {
Packit 0848f5
	if (strcmp(envval,"MULTIPLE") == 0 || strcmp(envval,"multiple") == 0) {
Packit 0848f5
	    threadLevel = MPI::THREAD_MULTIPLE;
Packit 0848f5
	}
Packit 0848f5
	else if (strcmp(envval,"SERIALIZED") == 0 || 
Packit 0848f5
		 strcmp(envval,"serialized") == 0) {
Packit 0848f5
	    threadLevel = MPI::THREAD_SERIALIZED;
Packit 0848f5
	}
Packit 0848f5
	else if (strcmp(envval,"FUNNELED") == 0 || 
Packit 0848f5
		 strcmp(envval,"funneled") == 0) {
Packit 0848f5
	    threadLevel = MPI::THREAD_FUNNELED;
Packit 0848f5
	}
Packit 0848f5
	else if (strcmp(envval,"SINGLE") == 0 || strcmp(envval,"single") == 0) {
Packit 0848f5
	    threadLevel = MPI::THREAD_SINGLE;
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    cerr << "Unrecognized thread level " << envval << "\n";
Packit 0848f5
	    cerr.flush();
Packit 0848f5
	    /* Use exit since MPI_Init/Init_thread has not been called. */
Packit 0848f5
	    exit(1);
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    flag = MPI::Is_initialized( );
Packit 0848f5
    if (!flag) {
Packit 0848f5
	provided = MPI::Init_thread( threadLevel );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
#if defined(HAVE_MPI_IO)
Packit 0848f5
    MPI::FILE_NULL.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS);
Packit 0848f5
#endif
Packit 0848f5
Packit 0848f5
    /* Check for debugging control */
Packit 0848f5
    if (getenv( "MPITEST_DEBUG" )) {
Packit 0848f5
	dbgflag = 1;
Packit 0848f5
	wrank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    /* Check for verbose control */
Packit 0848f5
    envval = getenv( "MPITEST_VERBOSE" );
Packit 0848f5
    if (envval) {
Packit 0848f5
	char *s;
Packit 0848f5
	long val = strtol( envval, &s, 0 );
Packit 0848f5
	if (s == envval) {
Packit 0848f5
	    /* This is the error case for strtol */
Packit 0848f5
	    cerr << "Warning: "<< envval << " not valid for MPITEST_VERBOSE\n";
Packit 0848f5
	    cerr.flush();
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    if (val >= 0) {
Packit 0848f5
		verbose = val;
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		cerr << "Warning: " << envval << 
Packit 0848f5
		    " not valid for MPITEST_VERBOSE\n";
Packit 0848f5
		cerr.flush();
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/*
Packit 0848f5
  Finalize MTest.  errs is the number of errors on the calling process; 
Packit 0848f5
  this routine will write the total number of errors over all of MPI_COMM_WORLD
Packit 0848f5
  to the process with rank zero, or " No Errors".
Packit 0848f5
  It does *not* finalize MPI.
Packit 0848f5
 */
Packit 0848f5
void MTest_Finalize( int errs )
Packit 0848f5
{
Packit 0848f5
    int rank, toterrs;
Packit 0848f5
Packit 0848f5
    rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
Packit 0848f5
    MPI::COMM_WORLD.Allreduce( &errs, &toterrs, 1, MPI::INT, MPI::SUM );
Packit 0848f5
    if (rank == 0) {
Packit 0848f5
	if (toterrs) {
Packit 0848f5
	    cout << " Found " << toterrs << " errors\n";
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    cout << " No Errors\n";
Packit 0848f5
	}
Packit 0848f5
	cout.flush();
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    // Clean up any persistent objects that we allocated
Packit 0848f5
    MTestRMACleanup();
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/*
Packit 0848f5
 * Datatypes
Packit 0848f5
 *
Packit 0848f5
 * Eventually, this could read a description of a file.  For now, we hard 
Packit 0848f5
 * code the choices
Packit 0848f5
 *
Packit 0848f5
 */
Packit 0848f5
static int datatype_index = 0;
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Setup contiguous buffers of n copies of a datatype.
Packit 0848f5
 */
Packit 0848f5
static void *MTestTypeContigInit( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    MPI::Aint size, lb;
Packit 0848f5
    if (mtype->count > 0) {
Packit 0848f5
	signed char *p;
Packit 0848f5
	int  i;
Packit 0848f5
        MPI::Aint totsize;
Packit 0848f5
	mtype->datatype.Get_extent( lb, size );
Packit 0848f5
	totsize = size * mtype->count;
Packit 0848f5
	if (!mtype->buf) {
Packit 0848f5
	    mtype->buf = (void *) malloc( totsize );
Packit 0848f5
	}
Packit 0848f5
	p = (signed char *)(mtype->buf);
Packit 0848f5
	if (!p) {
Packit 0848f5
	    /* Error - out of memory */
Packit 0848f5
	    MTestError( "Out of memory in type buffer init" );
Packit 0848f5
	}
Packit 0848f5
	for (i=0; i
Packit 0848f5
	    p[i] = 0xff ^ (i & 0xff);
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
	mtype->buf = 0;
Packit 0848f5
    }
Packit 0848f5
    return mtype->buf;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Setup contiguous buffers of n copies of a datatype.  Initialize for
Packit 0848f5
 * reception (e.g., set initial data to detect failure)
Packit 0848f5
 */
Packit 0848f5
static void *MTestTypeContigInitRecv( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    MPI_Aint size;
Packit 0848f5
    if (mtype->count > 0) {
Packit 0848f5
	signed char *p;
Packit 0848f5
	int  i;
Packit 0848f5
        MPI::Aint totsize;
Packit 0848f5
	MPI_Type_extent( mtype->datatype, &size );
Packit 0848f5
	totsize = size * mtype->count;
Packit 0848f5
	if (!mtype->buf) {
Packit 0848f5
	    mtype->buf = (void *) malloc( totsize );
Packit 0848f5
	}
Packit 0848f5
	p = (signed char *)(mtype->buf);
Packit 0848f5
	if (!p) {
Packit 0848f5
	    /* Error - out of memory */
Packit 0848f5
	    MTestError( "Out of memory in type buffer init" );
Packit 0848f5
	}
Packit 0848f5
	for (i=0; i
Packit 0848f5
	    p[i] = 0xff;
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
	if (mtype->buf) {
Packit 0848f5
	    free( mtype->buf );
Packit 0848f5
	}
Packit 0848f5
	mtype->buf = 0;
Packit 0848f5
    }
Packit 0848f5
    return mtype->buf;
Packit 0848f5
}
Packit 0848f5
static void *MTestTypeContigFree( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    if (mtype->buf) {
Packit 0848f5
	free( mtype->buf );
Packit 0848f5
	mtype->buf = 0;
Packit 0848f5
    }
Packit 0848f5
    return 0;
Packit 0848f5
}
Packit 0848f5
static int MTestTypeContigCheckbuf( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    unsigned char *p;
Packit 0848f5
    unsigned char expected;
Packit 0848f5
    int  i, err = 0;
Packit 0848f5
    MPI_Aint size, totsize;
Packit 0848f5
Packit 0848f5
    p = (unsigned char *)mtype->buf;
Packit 0848f5
    if (p) {
Packit 0848f5
	MPI_Type_extent( mtype->datatype, &size );
Packit 0848f5
	totsize = size * mtype->count;
Packit 0848f5
	for (i=0; i
Packit 0848f5
	    expected = (0xff ^ (i & 0xff));
Packit 0848f5
	    if (p[i] != expected) {
Packit 0848f5
		err++;
Packit 0848f5
		if (mtype->printErrors && err < 10) {
Packit 0848f5
		    cout << "Data expected = " << hex << expected << 
Packit 0848f5
			" but got " << p[i] << " for the " <<
Packit 0848f5
			 dec << i << "th entry\n";
Packit 0848f5
		    cout.flush();
Packit 0848f5
		}
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* ------------------------------------------------------------------------ */
Packit 0848f5
/* Datatype routines for vector datatypes                                   */
Packit 0848f5
/* ------------------------------------------------------------------------ */
Packit 0848f5
Packit 0848f5
static void *MTestTypeVectorInit( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    MPI::Aint size, lb;
Packit 0848f5
Packit 0848f5
    if (mtype->count > 0) {
Packit 0848f5
	unsigned char *p;
Packit 0848f5
	int  i, j, k, nc;
Packit 0848f5
        MPI::Aint totsize;
Packit 0848f5
Packit 0848f5
	mtype->datatype.Get_extent( lb, size );
Packit 0848f5
	totsize	   = mtype->count * size;
Packit 0848f5
	if (!mtype->buf) {
Packit 0848f5
	    mtype->buf = (void *) malloc( totsize );
Packit 0848f5
	}
Packit 0848f5
	p	   = (unsigned char *)(mtype->buf);
Packit 0848f5
	if (!p) {
Packit 0848f5
	    /* Error - out of memory */
Packit 0848f5
	    MTestError( "Out of memory in type buffer init" );
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
	/* First, set to -1 */
Packit 0848f5
	for (i=0; i
Packit 0848f5
Packit 0848f5
	/* Now, set the actual elements to the successive values.
Packit 0848f5
	   To do this, we need to run 3 loops */
Packit 0848f5
	nc = 0;
Packit 0848f5
	/* count is usually one for a vector type */
Packit 0848f5
	for (k=0; k<mtype->count; k++) {
Packit 0848f5
	    /* For each element (block) */
Packit 0848f5
	    for (i=0; i<mtype->nelm; i++) {
Packit 0848f5
		/* For each value */
Packit 0848f5
		for (j=0; j<mtype->blksize; j++) {
Packit 0848f5
		    p[j] = (0xff ^ (nc & 0xff));
Packit 0848f5
		    nc++;
Packit 0848f5
		}
Packit 0848f5
		p += mtype->stride;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
	mtype->buf = 0;
Packit 0848f5
    }
Packit 0848f5
    return mtype->buf;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
static void *MTestTypeVectorFree( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    if (mtype->buf) {
Packit 0848f5
	free( mtype->buf );
Packit 0848f5
	mtype->buf = 0;
Packit 0848f5
    }
Packit 0848f5
    return 0;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* ------------------------------------------------------------------------ */
Packit 0848f5
/* Routines to select a datatype and associated buffer create/fill/check    */
Packit 0848f5
/* routines                                                                 */
Packit 0848f5
/* ------------------------------------------------------------------------ */
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
   Create a range of datatypes with a given count elements.
Packit 0848f5
   This uses a selection of types, rather than an exhaustive collection.
Packit 0848f5
   It allocates both send and receive types so that they can have the same
Packit 0848f5
   type signature (collection of basic types) but different type maps (layouts
Packit 0848f5
   in memory) 
Packit 0848f5
 */
Packit 0848f5
int MTestGetDatatypes( MTestDatatype *sendtype, MTestDatatype *recvtype,
Packit 0848f5
		       int count )
Packit 0848f5
{
Packit 0848f5
    sendtype->InitBuf	  = 0;
Packit 0848f5
    sendtype->FreeBuf	  = 0;
Packit 0848f5
    sendtype->CheckBuf	  = 0;
Packit 0848f5
    sendtype->datatype	  = 0;
Packit 0848f5
    sendtype->isBasic	  = 0;
Packit 0848f5
    sendtype->printErrors = 0;
Packit 0848f5
    recvtype->InitBuf	  = 0;
Packit 0848f5
    recvtype->FreeBuf	  = 0;
Packit 0848f5
    recvtype->CheckBuf	  = 0;
Packit 0848f5
    recvtype->datatype	  = 0;
Packit 0848f5
    recvtype->isBasic	  = 0;
Packit 0848f5
    recvtype->printErrors = 0;
Packit 0848f5
Packit 0848f5
    sendtype->buf	  = 0;
Packit 0848f5
    recvtype->buf	  = 0;
Packit 0848f5
Packit 0848f5
    /* Set the defaults for the message lengths */
Packit 0848f5
    sendtype->count       = count;
Packit 0848f5
    recvtype->count       = count;
Packit 0848f5
    /* Use datatype_index to choose a datatype to use.  If at the end of the
Packit 0848f5
       list, return 0 */
Packit 0848f5
    switch (datatype_index) {
Packit 0848f5
    case 0:
Packit 0848f5
	sendtype->datatype = MPI::INT;
Packit 0848f5
	sendtype->isBasic  = 1;
Packit 0848f5
	recvtype->datatype = MPI::INT;
Packit 0848f5
	recvtype->isBasic  = 1;
Packit 0848f5
	break;
Packit 0848f5
    case 1:
Packit 0848f5
	sendtype->datatype = MPI::DOUBLE;
Packit 0848f5
	sendtype->isBasic  = 1;
Packit 0848f5
	recvtype->datatype = MPI::DOUBLE;
Packit 0848f5
	recvtype->isBasic  = 1;
Packit 0848f5
	break;
Packit 0848f5
    case 2:
Packit 0848f5
	sendtype->datatype = MPI::INT;
Packit 0848f5
	sendtype->isBasic  = 1;
Packit 0848f5
	recvtype->datatype = MPI::BYTE;
Packit 0848f5
	recvtype->isBasic  = 1;
Packit 0848f5
	recvtype->count    *= sizeof(int);
Packit 0848f5
	break;
Packit 0848f5
    case 3:
Packit 0848f5
	sendtype->datatype = MPI::FLOAT_INT;
Packit 0848f5
	sendtype->isBasic  = 1;
Packit 0848f5
	recvtype->datatype = MPI::FLOAT_INT;
Packit 0848f5
	recvtype->isBasic  = 1;
Packit 0848f5
	break;
Packit 0848f5
    case 4:
Packit 0848f5
	sendtype->datatype = MPI::INT.Dup();
Packit 0848f5
	sendtype->datatype.Set_name( "dup of MPI::INT" );
Packit 0848f5
	recvtype->datatype = MPI::INT.Dup();
Packit 0848f5
	recvtype->datatype.Set_name( "dup of MPI::INT" );
Packit 0848f5
	/* dup'ed types are already committed if the original type 
Packit 0848f5
	   was committed (MPI-2, section 8.8) */
Packit 0848f5
	break;
Packit 0848f5
    case 5:
Packit 0848f5
	/* vector send type and contiguous receive type */
Packit 0848f5
	/* These sizes are in bytes (see the VectorInit code) */
Packit 0848f5
	sendtype->stride   = 3 * sizeof(int);
Packit 0848f5
	sendtype->blksize  = sizeof(int);
Packit 0848f5
	sendtype->nelm     = recvtype->count;
Packit 0848f5
	sendtype->datatype = MPI::INT.Create_vector( recvtype->count, 1, sendtype->stride );
Packit 0848f5
        sendtype->datatype.Commit();
Packit 0848f5
	sendtype->datatype.Set_name( "int-vector" );
Packit 0848f5
	sendtype->count    = 1;
Packit 0848f5
	recvtype->datatype = MPI::INT;
Packit 0848f5
	recvtype->isBasic  = 1;
Packit 0848f5
	sendtype->InitBuf  = MTestTypeVectorInit;
Packit 0848f5
	recvtype->InitBuf  = MTestTypeContigInitRecv;
Packit 0848f5
	sendtype->FreeBuf  = MTestTypeVectorFree;
Packit 0848f5
	recvtype->FreeBuf  = MTestTypeContigFree;
Packit 0848f5
	sendtype->CheckBuf = 0;
Packit 0848f5
	recvtype->CheckBuf = MTestTypeContigCheckbuf;
Packit 0848f5
	break;
Packit 0848f5
    default:
Packit 0848f5
	datatype_index = -1;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    if (!sendtype->InitBuf) {
Packit 0848f5
	sendtype->InitBuf  = MTestTypeContigInit;
Packit 0848f5
	recvtype->InitBuf  = MTestTypeContigInitRecv;
Packit 0848f5
	sendtype->FreeBuf  = MTestTypeContigFree;
Packit 0848f5
	recvtype->FreeBuf  = MTestTypeContigFree;
Packit 0848f5
	sendtype->CheckBuf = MTestTypeContigCheckbuf;
Packit 0848f5
	recvtype->CheckBuf = MTestTypeContigCheckbuf;
Packit 0848f5
    }
Packit 0848f5
    datatype_index++;
Packit 0848f5
Packit 0848f5
    if (dbgflag && datatype_index > 0) {
Packit 0848f5
	int typesize;
Packit 0848f5
	cout << wrank << ": sendtype is " << MTestGetDatatypeName( sendtype ) 
Packit 0848f5
	     << "\n";
Packit 0848f5
	typesize = sendtype->datatype.Get_size();
Packit 0848f5
	cout << wrank << ": sendtype size = " << typesize << "\n";
Packit 0848f5
	cout << wrank << ": recvtype is " << MTestGetDatatypeName( recvtype ) 
Packit 0848f5
	     << "\n";
Packit 0848f5
	typesize = recvtype->datatype.Get_size();
Packit 0848f5
	cout << wrank << ": recvtype size = " << typesize << "\n";
Packit 0848f5
	cout.flush();
Packit 0848f5
    }
Packit 0848f5
    return datatype_index;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Reset the datatype index (start from the initial data type.
Packit 0848f5
   Note: This routine is rarely needed; MTestGetDatatypes automatically
Packit 0848f5
   starts over after the last available datatype is used.
Packit 0848f5
*/
Packit 0848f5
void MTestResetDatatypes( void )
Packit 0848f5
{
Packit 0848f5
    datatype_index = 0;
Packit 0848f5
}
Packit 0848f5
/* Return the index of the current datatype.  This is rarely needed and
Packit 0848f5
   is provided mostly to enable debugging of the MTest package itself */
Packit 0848f5
int MTestGetDatatypeIndex( void )
Packit 0848f5
{
Packit 0848f5
    return datatype_index;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
void MTestFreeDatatype( MTestDatatype *mtype )
Packit 0848f5
{
Packit 0848f5
    /* Invoke a datatype-specific free function to handle
Packit 0848f5
       both the datatype and the send/receive buffers */
Packit 0848f5
    if (mtype->FreeBuf) {
Packit 0848f5
	(mtype->FreeBuf)( mtype );
Packit 0848f5
    }
Packit 0848f5
    // Free the datatype itself if it was created
Packit 0848f5
    if (!mtype->isBasic) {
Packit 0848f5
	mtype->datatype.Free();
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Check that a message was received correctly.  Returns the number of
Packit 0848f5
   errors detected.  Status may be NULL or MPI_STATUS_IGNORE */
Packit 0848f5
int MTestCheckRecv( MPI::Status &status, MTestDatatype *recvtype )
Packit 0848f5
{
Packit 0848f5
    int count;
Packit 0848f5
    int errs = 0;
Packit 0848f5
Packit 0848f5
    /* Note that status may not be MPI_STATUS_IGNORE; C++ doesn't include 
Packit 0848f5
       MPI_STATUS_IGNORE, instead using different function prototypes that
Packit 0848f5
       do not include the status argument */
Packit 0848f5
    count = status.Get_count( recvtype->datatype );
Packit 0848f5
    
Packit 0848f5
    /* Check count against expected count */
Packit 0848f5
    if (count != recvtype->count) {
Packit 0848f5
	errs ++;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    /* Check received data */
Packit 0848f5
    if (!errs && recvtype->CheckBuf( recvtype )) {
Packit 0848f5
	errs++;
Packit 0848f5
    }
Packit 0848f5
    return errs;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* This next routine uses a circular buffer of static name arrays just to
Packit 0848f5
   simplify the use of the routine */
Packit 0848f5
const char *MTestGetDatatypeName( MTestDatatype *dtype )
Packit 0848f5
{
Packit 0848f5
    static char name[4][MPI_MAX_OBJECT_NAME];
Packit 0848f5
    static int sp=0;
Packit 0848f5
    int rlen;
Packit 0848f5
Packit 0848f5
    if (sp >= 4) sp = 0;
Packit 0848f5
    dtype->datatype.Get_name( name[sp], rlen );
Packit 0848f5
    return (const char *)name[sp++];
Packit 0848f5
}
Packit 0848f5
/* ----------------------------------------------------------------------- */
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Create communicators.  Use separate routines for inter and intra
Packit 0848f5
 * communicators (there is a routine to give both)
Packit 0848f5
 * Note that the routines may return MPI::COMM_NULL, so code should test for
Packit 0848f5
 * that return value as well.
Packit 0848f5
 * 
Packit 0848f5
 */
Packit 0848f5
static int interCommIdx = 0;
Packit 0848f5
static int intraCommIdx = 0;
Packit 0848f5
static const char *intraCommName = 0;
Packit 0848f5
static const char *interCommName = 0;
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Get an intracommunicator with at least min_size members.  If "allowSmaller"
Packit 0848f5
 * is true, allow the communicator to be smaller than MPI::COMM_WORLD and
Packit 0848f5
 * for this routine to return MPI::COMM_NULL for some values.  Returns 0 if
Packit 0848f5
 * no more communicators are available.
Packit 0848f5
 */
Packit 0848f5
int MTestGetIntracommGeneral( MPI::Intracomm &comm, int min_size, 
Packit 0848f5
			      bool allowSmaller )
Packit 0848f5
{
Packit 0848f5
    int size, rank;
Packit 0848f5
    bool done=false;
Packit 0848f5
    bool isBasic = false;
Packit 0848f5
Packit 0848f5
    /* The while loop allows us to skip communicators that are too small.
Packit 0848f5
       MPI::COMM_NULL is always considered large enough */
Packit 0848f5
    while (!done) {
Packit 0848f5
	switch (intraCommIdx) {
Packit 0848f5
	case 0:
Packit 0848f5
	    comm = MPI::COMM_WORLD;
Packit 0848f5
	    isBasic = true;
Packit 0848f5
	    intraCommName = "MPI::COMM_WORLD";
Packit 0848f5
	    break;
Packit 0848f5
	case 1:
Packit 0848f5
	    /* dup of world */
Packit 0848f5
	    comm = MPI::COMM_WORLD.Dup();
Packit 0848f5
	    intraCommName = "Dup of MPI::COMM_WORLD";
Packit 0848f5
	    break;
Packit 0848f5
	case 2:
Packit 0848f5
	    /* reverse ranks */
Packit 0848f5
	    size = MPI::COMM_WORLD.Get_size();
Packit 0848f5
	    rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	    comm = MPI::COMM_WORLD.Split( 0, size-rank );
Packit 0848f5
	    intraCommName = "Rank reverse of MPI::COMM_WORLD";
Packit 0848f5
	    break;
Packit 0848f5
	case 3:
Packit 0848f5
	    /* subset of world, with reversed ranks */
Packit 0848f5
	    size = MPI::COMM_WORLD.Get_size();
Packit 0848f5
	    rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	    comm = MPI::COMM_WORLD.Split( (rank < size/2), size-rank );
Packit 0848f5
	    intraCommName = "Rank reverse of half of MPI::COMM_WORLD";
Packit 0848f5
	    break;
Packit 0848f5
	case 4:
Packit 0848f5
	    comm = MPI::COMM_SELF;
Packit 0848f5
	    isBasic = true;
Packit 0848f5
	    intraCommName = "MPI::COMM_SELF";
Packit 0848f5
	    break;
Packit 0848f5
Packit 0848f5
	    /* These next cases are communicators that include some
Packit 0848f5
	       but not all of the processes */
Packit 0848f5
	case 5:
Packit 0848f5
	case 6:
Packit 0848f5
	case 7:
Packit 0848f5
	case 8:
Packit 0848f5
	{
Packit 0848f5
	    int newsize;
Packit 0848f5
	    size = MPI::COMM_WORLD.Get_size();
Packit 0848f5
	    newsize = size - (intraCommIdx - 4);
Packit 0848f5
	    
Packit 0848f5
	    if (allowSmaller && newsize >= min_size) {
Packit 0848f5
		rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
		comm = MPI::COMM_WORLD.Split( rank < newsize, rank );
Packit 0848f5
		if (rank >= newsize) {
Packit 0848f5
		    comm.Free();
Packit 0848f5
		    comm = MPI::COMM_NULL;
Packit 0848f5
		}
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		/* Act like default */
Packit 0848f5
		comm = MPI::COMM_NULL;
Packit 0848f5
		isBasic = true;
Packit 0848f5
		intraCommName = "MPI::COMM_NULL";
Packit 0848f5
		intraCommIdx = -1;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	break;
Packit 0848f5
	    
Packit 0848f5
	    /* Other ideas: dup of self, cart comm, graph comm */
Packit 0848f5
	default:
Packit 0848f5
	    comm = MPI::COMM_NULL;
Packit 0848f5
	    isBasic = true;
Packit 0848f5
	    intraCommName = "MPI::COMM_NULL";
Packit 0848f5
	    intraCommIdx = -1;
Packit 0848f5
	    break;
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
	if (comm != MPI::COMM_NULL) {
Packit 0848f5
	    size = comm.Get_size();
Packit 0848f5
	    if (size >= min_size) 
Packit 0848f5
		done = true;
Packit 0848f5
	    else {
Packit 0848f5
		/* Try again */
Packit 0848f5
		if (!isBasic) comm.Free();
Packit 0848f5
		intraCommIdx++;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	else
Packit 0848f5
	    done = true;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    intraCommIdx++;
Packit 0848f5
    return intraCommIdx;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Get an intracommunicator with at least min_size members.
Packit 0848f5
 */
Packit 0848f5
int MTestGetIntracomm( MPI::Intracomm &comm, int min_size ) 
Packit 0848f5
{
Packit 0848f5
    return MTestGetIntracommGeneral( comm, min_size, false );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Return the name of an intra communicator */
Packit 0848f5
const char *MTestGetIntracommName( void )
Packit 0848f5
{
Packit 0848f5
    return intraCommName;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Return an intercomm; set isLeftGroup to 1 if the calling process is 
Packit 0848f5
 * a member of the "left" group.
Packit 0848f5
 */
Packit 0848f5
int MTestGetIntercomm( MPI::Intercomm &comm, int &isLeftGroup, int min_size )
Packit 0848f5
{
Packit 0848f5
    int size, rank, remsize;
Packit 0848f5
    bool done=false;
Packit 0848f5
    MPI::Intracomm mcomm;
Packit 0848f5
    int rleader;
Packit 0848f5
Packit 0848f5
    /* The while loop allows us to skip communicators that are too small.
Packit 0848f5
       MPI::COMM_NULL is always considered large enough.  The size is
Packit 0848f5
       the sum of the sizes of the local and remote groups */
Packit 0848f5
    while (!done) {
Packit 0848f5
        comm          = MPI::COMM_NULL;
Packit 0848f5
	isLeftGroup   = 0;
Packit 0848f5
	interCommName = "MPI_COMM_NULL";
Packit 0848f5
Packit 0848f5
	switch (interCommIdx) {
Packit 0848f5
	case 0:
Packit 0848f5
	    /* Split comm world in half */
Packit 0848f5
	    rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	    size = MPI::COMM_WORLD.Get_size();
Packit 0848f5
	    if (size > 1) {
Packit 0848f5
		mcomm = MPI::COMM_WORLD.Split( (rank < size/2), rank );
Packit 0848f5
		if (rank == 0) {
Packit 0848f5
		    rleader = size/2;
Packit 0848f5
		}
Packit 0848f5
		else if (rank == size/2) {
Packit 0848f5
		    rleader = 0;
Packit 0848f5
		}
Packit 0848f5
		else {
Packit 0848f5
		    /* Remote leader is signficant only for the processes
Packit 0848f5
		       designated local leaders */
Packit 0848f5
		    rleader = -1;
Packit 0848f5
		}
Packit 0848f5
		isLeftGroup = rank < size/2;
Packit 0848f5
		comm = mcomm.Create_intercomm( 0, MPI::COMM_WORLD, rleader, 12345 );
Packit 0848f5
		mcomm.Free();
Packit 0848f5
		interCommName = "Intercomm by splitting MPI::COMM_WORLD";
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		comm = MPI::COMM_NULL;
Packit 0848f5
            }
Packit 0848f5
	    break;
Packit 0848f5
	case 1:
Packit 0848f5
	    /* Split comm world in to 1 and the rest */
Packit 0848f5
	    rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	    size = MPI::COMM_WORLD.Get_size();
Packit 0848f5
	    if (size > 1) {
Packit 0848f5
		mcomm = MPI::COMM_WORLD.Split( rank == 0, rank );
Packit 0848f5
		if (rank == 0) {
Packit 0848f5
		    rleader = 1;
Packit 0848f5
		}
Packit 0848f5
		else if (rank == 1) {
Packit 0848f5
		    rleader = 0;
Packit 0848f5
		}
Packit 0848f5
		else {
Packit 0848f5
		    /* Remote leader is signficant only for the processes
Packit 0848f5
		       designated local leaders */
Packit 0848f5
		    rleader = -1;
Packit 0848f5
		}
Packit 0848f5
		isLeftGroup = rank == 0;
Packit 0848f5
		comm = mcomm.Create_intercomm( 0, MPI::COMM_WORLD, rleader, 12346 );
Packit 0848f5
		mcomm.Free();
Packit 0848f5
		interCommName = "Intercomm by splitting MPI::COMM_WORLD into 1, rest";
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		comm = MPI::COMM_NULL;
Packit 0848f5
            }
Packit 0848f5
	    break;
Packit 0848f5
Packit 0848f5
	case 2:
Packit 0848f5
	    /* Split comm world in to 2 and the rest */
Packit 0848f5
	    rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	    size = MPI::COMM_WORLD.Get_size();
Packit 0848f5
	    if (size > 3) {
Packit 0848f5
		mcomm = MPI::COMM_WORLD.Split( rank < 2, rank );
Packit 0848f5
		if (rank == 0) {
Packit 0848f5
		    rleader = 2;
Packit 0848f5
		}
Packit 0848f5
		else if (rank == 2) {
Packit 0848f5
		    rleader = 0;
Packit 0848f5
		}
Packit 0848f5
		else {
Packit 0848f5
		    /* Remote leader is signficant only for the processes
Packit 0848f5
		       designated local leaders */
Packit 0848f5
		    rleader = -1;
Packit 0848f5
		}
Packit 0848f5
		isLeftGroup = rank < 2;
Packit 0848f5
		comm = mcomm.Create_intercomm( 0, MPI::COMM_WORLD, rleader, 12347 );
Packit 0848f5
		mcomm.Free();
Packit 0848f5
		interCommName = "Intercomm by splitting MPI::COMM_WORLD into 2, rest";
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		comm = MPI::COMM_NULL;
Packit 0848f5
            }
Packit 0848f5
	    break;
Packit 0848f5
Packit 0848f5
	default:
Packit 0848f5
	    comm = MPI::COMM_NULL;
Packit 0848f5
	    interCommName = "MPI::COMM_NULL";
Packit 0848f5
	    interCommIdx = -1;
Packit 0848f5
	    break;
Packit 0848f5
	}
Packit 0848f5
	if (comm != MPI::COMM_NULL) {
Packit 0848f5
	    size = comm.Get_size();
Packit 0848f5
	    remsize = comm.Get_remote_size();
Packit 0848f5
	    if (size + remsize >= min_size) done = true;
Packit 0848f5
	}
Packit 0848f5
	else
Packit 0848f5
	    done = true;
Packit 0848f5
Packit 0848f5
        /* we are only done if all processes are done */
Packit 0848f5
        MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &done, 1, MPI::BOOL, MPI::LAND);
Packit 0848f5
Packit 0848f5
        /* Advance the comm index whether we are done or not, otherwise we could
Packit 0848f5
         * spin forever trying to allocate a too-small communicator over and
Packit 0848f5
         * over again. */
Packit 0848f5
        interCommIdx++;
Packit 0848f5
Packit 0848f5
        if (!done && comm != MPI::COMM_NULL) {
Packit 0848f5
            comm.Free();
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return interCommIdx;
Packit 0848f5
}
Packit 0848f5
/* Return the name of an intercommunicator */
Packit 0848f5
const char *MTestGetIntercommName( void )
Packit 0848f5
{
Packit 0848f5
    return interCommName;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Get a communicator of a given minimum size.  Both intra and inter 
Packit 0848f5
   communicators are provided
Packit 0848f5
   Because Comm is an abstract base class, you can only have references 
Packit 0848f5
   to a Comm.*/
Packit 0848f5
int MTestGetComm( MPI::Comm **comm, int min_size )
Packit 0848f5
{
Packit 0848f5
    int idx;
Packit 0848f5
    static int getinter = 0;
Packit 0848f5
Packit 0848f5
    if (!getinter) {
Packit 0848f5
	MPI::Intracomm rcomm;
Packit 0848f5
	idx = MTestGetIntracomm( rcomm, min_size );
Packit 0848f5
	if (idx == 0) {
Packit 0848f5
	    getinter = 1;
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    MPI::Intracomm *ncomm = new MPI::Intracomm(rcomm);
Packit 0848f5
	    *comm = ncomm;
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    if (getinter) {
Packit 0848f5
	MPI::Intercomm icomm;
Packit 0848f5
	int isLeft;
Packit 0848f5
	idx = MTestGetIntercomm( icomm, isLeft, min_size );
Packit 0848f5
	if (idx == 0) {
Packit 0848f5
	    getinter = 0;
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    MPI::Intercomm *ncomm = new MPI::Intercomm(icomm);
Packit 0848f5
	    *comm = ncomm;
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return idx;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Free a communicator.  It may be called with a predefined communicator
Packit 0848f5
 or MPI_COMM_NULL */
Packit 0848f5
void MTestFreeComm( MPI::Comm &comm )
Packit 0848f5
{
Packit 0848f5
    if (comm != MPI::COMM_WORLD &&
Packit 0848f5
	comm != MPI::COMM_SELF &&
Packit 0848f5
	comm != MPI::COMM_NULL) {
Packit 0848f5
	comm.Free();
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* ------------------------------------------------------------------------ */
Packit 0848f5
void MTestPrintError( int errcode )
Packit 0848f5
{
Packit 0848f5
    int errclass, slen;
Packit 0848f5
    char string[MPI_MAX_ERROR_STRING];
Packit 0848f5
    
Packit 0848f5
    errclass = MPI::Get_error_class( errcode );
Packit 0848f5
    MPI::Get_error_string( errcode, string, slen );
Packit 0848f5
    cout << "Error class " << errclass << "(" << string << ")\n";
Packit 0848f5
    cout.flush();
Packit 0848f5
}
Packit 0848f5
void MTestPrintErrorMsg( const char msg[], int errcode )
Packit 0848f5
{
Packit 0848f5
    int errclass, slen;
Packit 0848f5
    char string[MPI_MAX_ERROR_STRING];
Packit 0848f5
    
Packit 0848f5
    errclass = MPI::Get_error_class( errcode );
Packit 0848f5
    MPI::Get_error_string( errcode, string, slen );
Packit 0848f5
    cout << msg << ": Error class " << errclass << " (" << string << ")\n";
Packit 0848f5
    cout.flush();
Packit 0848f5
}
Packit 0848f5
/* ------------------------------------------------------------------------ */
Packit 0848f5
/* Fatal error.  Report and exit */
Packit 0848f5
void MTestError( const char *msg )
Packit 0848f5
{
Packit 0848f5
    cerr << msg << "\n";
Packit 0848f5
    cerr.flush();
Packit 0848f5
    MPI::COMM_WORLD.Abort(1);
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
#ifdef HAVE_MPI_WIN_CREATE
Packit 0848f5
/*
Packit 0848f5
 * Create MPI Windows
Packit 0848f5
 */
Packit 0848f5
static int win_index = 0;
Packit 0848f5
static const char *winName;
Packit 0848f5
/* Use an attribute to remember the type of memory allocation (static,
Packit 0848f5
   malloc, or MPI_Alloc_mem) */
Packit 0848f5
static int mem_keyval = MPI::KEYVAL_INVALID;
Packit 0848f5
int MTestGetWin( MPI::Win &win, bool mustBePassive )
Packit 0848f5
{
Packit 0848f5
    static char actbuf[1024];
Packit 0848f5
    static char *pasbuf;
Packit 0848f5
    char        *buf;
Packit 0848f5
    int         n, rank;
Packit 0848f5
    MPI::Info   info;
Packit 0848f5
Packit 0848f5
    if (mem_keyval == MPI::KEYVAL_INVALID) {
Packit 0848f5
	/* Create the keyval */
Packit 0848f5
	mem_keyval = MPI::Win::Create_keyval( MPI::Win::NULL_COPY_FN, 
Packit 0848f5
					      MPI::Win::NULL_DELETE_FN, 0 );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    switch (win_index) {
Packit 0848f5
    case 0:
Packit 0848f5
	/* Active target window */
Packit 0848f5
	win = MPI::Win::Create( actbuf, 1024, 1, MPI::INFO_NULL, MPI::COMM_WORLD );
Packit 0848f5
	winName = "active-window";
Packit 0848f5
	win.Set_attr( mem_keyval, (void *)0 );
Packit 0848f5
	break;
Packit 0848f5
    case 1:
Packit 0848f5
	/* Passive target window */
Packit 0848f5
	pasbuf = (char *)MPI::Alloc_mem( 1024, MPI::INFO_NULL );
Packit 0848f5
	win = MPI::Win::Create( pasbuf, 1024, 1, MPI::INFO_NULL, MPI::COMM_WORLD );
Packit 0848f5
	winName = "passive-window";
Packit 0848f5
	win.Set_attr( mem_keyval, (void *)2 );
Packit 0848f5
	break;
Packit 0848f5
    case 2:
Packit 0848f5
	/* Active target; all windows different sizes */
Packit 0848f5
	rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	n = rank * 64;
Packit 0848f5
	if (n) 
Packit 0848f5
	    buf = (char *)malloc( n );
Packit 0848f5
	else
Packit 0848f5
	    buf = 0;
Packit 0848f5
	win = MPI::Win::Create( buf, n, 1, MPI::INFO_NULL, MPI::COMM_WORLD );
Packit 0848f5
	winName = "active-all-different-win";
Packit 0848f5
	win.Set_attr( mem_keyval, (void *)1 );
Packit 0848f5
	break;
Packit 0848f5
    case 3:
Packit 0848f5
	/* Active target, no locks set */
Packit 0848f5
	rank = MPI::COMM_WORLD.Get_rank();
Packit 0848f5
	n = rank * 64;
Packit 0848f5
	if (n) 
Packit 0848f5
	    buf = (char *)malloc( n );
Packit 0848f5
	else
Packit 0848f5
	    buf = 0;
Packit 0848f5
	info = MPI::Info::Create( );
Packit 0848f5
	info.Set( "nolocks", "true" );
Packit 0848f5
	win = MPI::Win::Create( buf, n, 1, info, MPI::COMM_WORLD );
Packit 0848f5
	info.Free();
Packit 0848f5
	winName = "active-nolocks-all-different-win";
Packit 0848f5
	win.Set_attr( mem_keyval, (void *)1 );
Packit 0848f5
	break;
Packit 0848f5
    default:
Packit 0848f5
	win_index = -1;
Packit 0848f5
    }
Packit 0848f5
    win_index++;
Packit 0848f5
    return win_index;
Packit 0848f5
}
Packit 0848f5
/* Return a pointer to the name associated with a window object */
Packit 0848f5
const char *MTestGetWinName( void )
Packit 0848f5
{
Packit 0848f5
    
Packit 0848f5
    return winName;
Packit 0848f5
}
Packit 0848f5
/* Free the storage associated with a window object */
Packit 0848f5
void MTestFreeWin( MPI::Win &win )
Packit 0848f5
{
Packit 0848f5
    void *addr;
Packit 0848f5
    bool flag;
Packit 0848f5
Packit 0848f5
    flag = win.Get_attr( MPI_WIN_BASE, &addr );
Packit 0848f5
    if (!flag) {
Packit 0848f5
	MTestError( "Could not get WIN_BASE from window" );
Packit 0848f5
    }
Packit 0848f5
    if (addr) {
Packit 0848f5
	void *val;
Packit 0848f5
	flag = win.Get_attr( mem_keyval, &val );
Packit 0848f5
	if (flag) {
Packit 0848f5
	    if (val == (void *)1) {
Packit 0848f5
		free( addr );
Packit 0848f5
	    }
Packit 0848f5
	    else if (val == (void *)2) {
Packit 0848f5
		MPI::Free_mem( addr );
Packit 0848f5
	    }
Packit 0848f5
	    /* if val == (void *)0, then static data that must not be freed */
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    win.Free();
Packit 0848f5
}
Packit 0848f5
static void MTestRMACleanup( void )
Packit 0848f5
{
Packit 0848f5
    if (mem_keyval != MPI::KEYVAL_INVALID) {
Packit 0848f5
	MPI::Win::Free_keyval( mem_keyval );
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
#else 
Packit 0848f5
static void MTestRMACleanup( void ) {}
Packit 0848f5
#endif