|
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
|