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

Packit Service c5cf8c
/* -*- Mode: C++; c-basic-offset:4 ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#include "mpi.h"
Packit Service c5cf8c
#include "mpitestconf.h"
Packit Service c5cf8c
#ifdef HAVE_IOSTREAM
Packit Service c5cf8c
// Not all C++ compilers have iostream instead of iostream.h
Packit Service c5cf8c
#include <iostream>
Packit Service c5cf8c
#ifdef HAVE_NAMESPACE_STD
Packit Service c5cf8c
// Those that do often need the std namespace; otherwise, a bare "cout"
Packit Service c5cf8c
// is likely to fail to compile
Packit Service c5cf8c
using namespace std;
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#else
Packit Service c5cf8c
#include <iostream.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#include "mpitestcxx.h"
Packit Service c5cf8c
#include <stdlib.h>
Packit Service c5cf8c
#include <string.h>
Packit Service c5cf8c
Packit Service c5cf8c
static int dbgflag = 0;         /* Flag used for debugging */
Packit Service c5cf8c
static int wrank = -1;          /* World rank */
Packit Service c5cf8c
static int verbose = 0;         /* Message level (0 is none) */
Packit Service c5cf8c
Packit Service c5cf8c
static void MTestRMACleanup(void);
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Initialize and Finalize MTest
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
   Initialize MTest, initializing MPI if necessary.
Packit Service c5cf8c
Packit Service c5cf8c
 Environment Variables:
Packit Service c5cf8c
+ MPITEST_DEBUG - If set (to any value), turns on debugging output
Packit Service c5cf8c
- MPITEST_VERBOSE - If set to a numeric value, turns on that level of
Packit Service c5cf8c
  verbose output.
Packit Service c5cf8c
Packit Service c5cf8c
 */
Packit Service c5cf8c
void MTest_Init(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    bool flag;
Packit Service c5cf8c
    const char *envval = 0;
Packit Service c5cf8c
    int threadLevel, provided;
Packit Service c5cf8c
Packit Service c5cf8c
    threadLevel = MPI::THREAD_SINGLE;
Packit Service c5cf8c
    envval = getenv("MTEST_THREADLEVEL_DEFAULT");
Packit Service c5cf8c
    if (envval && *envval) {
Packit Service c5cf8c
        if (strcmp(envval, "MULTIPLE") == 0 || strcmp(envval, "multiple") == 0) {
Packit Service c5cf8c
            threadLevel = MPI::THREAD_MULTIPLE;
Packit Service c5cf8c
        } else if (strcmp(envval, "SERIALIZED") == 0 || strcmp(envval, "serialized") == 0) {
Packit Service c5cf8c
            threadLevel = MPI::THREAD_SERIALIZED;
Packit Service c5cf8c
        } else if (strcmp(envval, "FUNNELED") == 0 || strcmp(envval, "funneled") == 0) {
Packit Service c5cf8c
            threadLevel = MPI::THREAD_FUNNELED;
Packit Service c5cf8c
        } else if (strcmp(envval, "SINGLE") == 0 || strcmp(envval, "single") == 0) {
Packit Service c5cf8c
            threadLevel = MPI::THREAD_SINGLE;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            cerr << "Unrecognized thread level " << envval << "\n";
Packit Service c5cf8c
            cerr.flush();
Packit Service c5cf8c
            /* Use exit since MPI_Init/Init_thread has not been called. */
Packit Service c5cf8c
            exit(1);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    flag = MPI::Is_initialized();
Packit Service c5cf8c
    if (!flag) {
Packit Service c5cf8c
        provided = MPI::Init_thread(threadLevel);
Packit Service c5cf8c
    }
Packit Service c5cf8c
#if defined(HAVE_MPI_IO)
Packit Service c5cf8c
    MPI::FILE_NULL.Set_errhandler(MPI::ERRORS_THROW_EXCEPTIONS);
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
    /* Check for debugging control */
Packit Service c5cf8c
    if (getenv("MPITEST_DEBUG")) {
Packit Service c5cf8c
        dbgflag = 1;
Packit Service c5cf8c
        wrank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* Check for verbose control */
Packit Service c5cf8c
    envval = getenv("MPITEST_VERBOSE");
Packit Service c5cf8c
    if (envval) {
Packit Service c5cf8c
        char *s;
Packit Service c5cf8c
        long val = strtol(envval, &s, 0);
Packit Service c5cf8c
        if (s == envval) {
Packit Service c5cf8c
            /* This is the error case for strtol */
Packit Service c5cf8c
            cerr << "Warning: " << envval << " not valid for MPITEST_VERBOSE\n";
Packit Service c5cf8c
            cerr.flush();
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            if (val >= 0) {
Packit Service c5cf8c
                verbose = val;
Packit Service c5cf8c
            } else {
Packit Service c5cf8c
                cerr << "Warning: " << envval << " not valid for MPITEST_VERBOSE\n";
Packit Service c5cf8c
                cerr.flush();
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
  Finalize MTest.  errs is the number of errors on the calling process;
Packit Service c5cf8c
  this routine will write the total number of errors over all of MPI_COMM_WORLD
Packit Service c5cf8c
  to the process with rank zero, or " No Errors".
Packit Service c5cf8c
 */
Packit Service c5cf8c
void MTest_Finalize(int errs)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int rank, toterrs;
Packit Service c5cf8c
Packit Service c5cf8c
    rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
Packit Service c5cf8c
    MPI::COMM_WORLD.Allreduce(&errs, &toterrs, 1, MPI::INT, MPI::SUM);
Packit Service c5cf8c
    if (rank == 0) {
Packit Service c5cf8c
        if (toterrs) {
Packit Service c5cf8c
            cout << " Found " << toterrs << " errors\n";
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            cout << " No Errors\n";
Packit Service c5cf8c
        }
Packit Service c5cf8c
        cout.flush();
Packit Service c5cf8c
    }
Packit Service c5cf8c
    // Clean up any persistent objects that we allocated
Packit Service c5cf8c
    MTestRMACleanup();
Packit Service c5cf8c
Packit Service c5cf8c
    MPI::Finalize();
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* ----------------------------------------------------------------------- */
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Create communicators.  Use separate routines for inter and intra
Packit Service c5cf8c
 * communicators (there is a routine to give both)
Packit Service c5cf8c
 * Note that the routines may return MPI::COMM_NULL, so code should test for
Packit Service c5cf8c
 * that return value as well.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 */
Packit Service c5cf8c
static int interCommIdx = 0;
Packit Service c5cf8c
static int intraCommIdx = 0;
Packit Service c5cf8c
static const char *intraCommName = 0;
Packit Service c5cf8c
static const char *interCommName = 0;
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Get an intracommunicator with at least min_size members.  If "allowSmaller"
Packit Service c5cf8c
 * is true, allow the communicator to be smaller than MPI::COMM_WORLD and
Packit Service c5cf8c
 * for this routine to return MPI::COMM_NULL for some values.  Returns 0 if
Packit Service c5cf8c
 * no more communicators are available.
Packit Service c5cf8c
 */
Packit Service c5cf8c
int MTestGetIntracommGeneral(MPI::Intracomm & comm, int min_size, bool allowSmaller)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int size, rank;
Packit Service c5cf8c
    bool done = false;
Packit Service c5cf8c
    bool isBasic = false;
Packit Service c5cf8c
Packit Service c5cf8c
    /* The while loop allows us to skip communicators that are too small.
Packit Service c5cf8c
     * MPI::COMM_NULL is always considered large enough */
Packit Service c5cf8c
    while (!done) {
Packit Service c5cf8c
        switch (intraCommIdx) {
Packit Service c5cf8c
            case 0:
Packit Service c5cf8c
                comm = MPI::COMM_WORLD;
Packit Service c5cf8c
                isBasic = true;
Packit Service c5cf8c
                intraCommName = "MPI::COMM_WORLD";
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            case 1:
Packit Service c5cf8c
                /* dup of world */
Packit Service c5cf8c
                comm = MPI::COMM_WORLD.Dup();
Packit Service c5cf8c
                intraCommName = "Dup of MPI::COMM_WORLD";
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            case 2:
Packit Service c5cf8c
                /* reverse ranks */
Packit Service c5cf8c
                size = MPI::COMM_WORLD.Get_size();
Packit Service c5cf8c
                rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
                comm = MPI::COMM_WORLD.Split(0, size - rank);
Packit Service c5cf8c
                intraCommName = "Rank reverse of MPI::COMM_WORLD";
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            case 3:
Packit Service c5cf8c
                /* subset of world, with reversed ranks */
Packit Service c5cf8c
                size = MPI::COMM_WORLD.Get_size();
Packit Service c5cf8c
                rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
                comm = MPI::COMM_WORLD.Split((rank < size / 2), size - rank);
Packit Service c5cf8c
                intraCommName = "Rank reverse of half of MPI::COMM_WORLD";
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            case 4:
Packit Service c5cf8c
                comm = MPI::COMM_SELF;
Packit Service c5cf8c
                isBasic = true;
Packit Service c5cf8c
                intraCommName = "MPI::COMM_SELF";
Packit Service c5cf8c
                break;
Packit Service c5cf8c
Packit Service c5cf8c
                /* These next cases are communicators that include some
Packit Service c5cf8c
                 * but not all of the processes */
Packit Service c5cf8c
            case 5:
Packit Service c5cf8c
            case 6:
Packit Service c5cf8c
            case 7:
Packit Service c5cf8c
            case 8:
Packit Service c5cf8c
                {
Packit Service c5cf8c
                    int newsize;
Packit Service c5cf8c
                    size = MPI::COMM_WORLD.Get_size();
Packit Service c5cf8c
                    newsize = size - (intraCommIdx - 4);
Packit Service c5cf8c
Packit Service c5cf8c
                    if (allowSmaller && newsize >= min_size) {
Packit Service c5cf8c
                        rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
                        comm = MPI::COMM_WORLD.Split(rank < newsize, rank);
Packit Service c5cf8c
                        if (rank >= newsize) {
Packit Service c5cf8c
                            comm.Free();
Packit Service c5cf8c
                            comm = MPI::COMM_NULL;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        /* Act like default */
Packit Service c5cf8c
                        comm = MPI::COMM_NULL;
Packit Service c5cf8c
                        isBasic = true;
Packit Service c5cf8c
                        intraCommName = "MPI::COMM_NULL";
Packit Service c5cf8c
                        intraCommIdx = -1;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                break;
Packit Service c5cf8c
Packit Service c5cf8c
                /* Other ideas: dup of self, cart comm, graph comm */
Packit Service c5cf8c
            default:
Packit Service c5cf8c
                comm = MPI::COMM_NULL;
Packit Service c5cf8c
                isBasic = true;
Packit Service c5cf8c
                intraCommName = "MPI::COMM_NULL";
Packit Service c5cf8c
                intraCommIdx = -1;
Packit Service c5cf8c
                break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        if (comm != MPI::COMM_NULL) {
Packit Service c5cf8c
            size = comm.Get_size();
Packit Service c5cf8c
            if (size >= min_size)
Packit Service c5cf8c
                done = true;
Packit Service c5cf8c
            else {
Packit Service c5cf8c
                /* Try again */
Packit Service c5cf8c
                if (!isBasic)
Packit Service c5cf8c
                    comm.Free();
Packit Service c5cf8c
                intraCommIdx++;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            done = true;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    intraCommIdx++;
Packit Service c5cf8c
    return intraCommIdx;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Get an intracommunicator with at least min_size members.
Packit Service c5cf8c
 */
Packit Service c5cf8c
int MTestGetIntracomm(MPI::Intracomm & comm, int min_size)
Packit Service c5cf8c
{
Packit Service c5cf8c
    return MTestGetIntracommGeneral(comm, min_size, false);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Return the name of an intra communicator */
Packit Service c5cf8c
const char *MTestGetIntracommName(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    return intraCommName;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Return an intercomm; set isLeftGroup to 1 if the calling process is
Packit Service c5cf8c
 * a member of the "left" group.
Packit Service c5cf8c
 */
Packit Service c5cf8c
int MTestGetIntercomm(MPI::Intercomm & comm, int &isLeftGroup, int min_size)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int size, rank, remsize;
Packit Service c5cf8c
    bool done = false;
Packit Service c5cf8c
    MPI::Intracomm mcomm;
Packit Service c5cf8c
    int rleader;
Packit Service c5cf8c
Packit Service c5cf8c
    /* The while loop allows us to skip communicators that are too small.
Packit Service c5cf8c
     * MPI::COMM_NULL is always considered large enough.  The size is
Packit Service c5cf8c
     * the sum of the sizes of the local and remote groups */
Packit Service c5cf8c
    while (!done) {
Packit Service c5cf8c
        comm = MPI::COMM_NULL;
Packit Service c5cf8c
        isLeftGroup = 0;
Packit Service c5cf8c
        interCommName = "MPI_COMM_NULL";
Packit Service c5cf8c
Packit Service c5cf8c
        switch (interCommIdx) {
Packit Service c5cf8c
            case 0:
Packit Service c5cf8c
                /* Split comm world in half */
Packit Service c5cf8c
                rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
                size = MPI::COMM_WORLD.Get_size();
Packit Service c5cf8c
                if (size > 1) {
Packit Service c5cf8c
                    mcomm = MPI::COMM_WORLD.Split((rank < size / 2), rank);
Packit Service c5cf8c
                    if (rank == 0) {
Packit Service c5cf8c
                        rleader = size / 2;
Packit Service c5cf8c
                    } else if (rank == size / 2) {
Packit Service c5cf8c
                        rleader = 0;
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        /* Remote leader is signficant only for the processes
Packit Service c5cf8c
                         * designated local leaders */
Packit Service c5cf8c
                        rleader = -1;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    isLeftGroup = rank < size / 2;
Packit Service c5cf8c
                    comm = mcomm.Create_intercomm(0, MPI::COMM_WORLD, rleader, 12345);
Packit Service c5cf8c
                    mcomm.Free();
Packit Service c5cf8c
                    interCommName = "Intercomm by splitting MPI::COMM_WORLD";
Packit Service c5cf8c
                } else {
Packit Service c5cf8c
                    comm = MPI::COMM_NULL;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            case 1:
Packit Service c5cf8c
                /* Split comm world in to 1 and the rest */
Packit Service c5cf8c
                rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
                size = MPI::COMM_WORLD.Get_size();
Packit Service c5cf8c
                if (size > 1) {
Packit Service c5cf8c
                    mcomm = MPI::COMM_WORLD.Split(rank == 0, rank);
Packit Service c5cf8c
                    if (rank == 0) {
Packit Service c5cf8c
                        rleader = 1;
Packit Service c5cf8c
                    } else if (rank == 1) {
Packit Service c5cf8c
                        rleader = 0;
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        /* Remote leader is signficant only for the processes
Packit Service c5cf8c
                         * designated local leaders */
Packit Service c5cf8c
                        rleader = -1;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    isLeftGroup = rank == 0;
Packit Service c5cf8c
                    comm = mcomm.Create_intercomm(0, MPI::COMM_WORLD, rleader, 12346);
Packit Service c5cf8c
                    mcomm.Free();
Packit Service c5cf8c
                    interCommName = "Intercomm by splitting MPI::COMM_WORLD into 1, rest";
Packit Service c5cf8c
                } else {
Packit Service c5cf8c
                    comm = MPI::COMM_NULL;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                break;
Packit Service c5cf8c
Packit Service c5cf8c
            case 2:
Packit Service c5cf8c
                /* Split comm world in to 2 and the rest */
Packit Service c5cf8c
                rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
                size = MPI::COMM_WORLD.Get_size();
Packit Service c5cf8c
                if (size > 3) {
Packit Service c5cf8c
                    mcomm = MPI::COMM_WORLD.Split(rank < 2, rank);
Packit Service c5cf8c
                    if (rank == 0) {
Packit Service c5cf8c
                        rleader = 2;
Packit Service c5cf8c
                    } else if (rank == 2) {
Packit Service c5cf8c
                        rleader = 0;
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        /* Remote leader is signficant only for the processes
Packit Service c5cf8c
                         * designated local leaders */
Packit Service c5cf8c
                        rleader = -1;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    isLeftGroup = rank < 2;
Packit Service c5cf8c
                    comm = mcomm.Create_intercomm(0, MPI::COMM_WORLD, rleader, 12347);
Packit Service c5cf8c
                    mcomm.Free();
Packit Service c5cf8c
                    interCommName = "Intercomm by splitting MPI::COMM_WORLD into 2, rest";
Packit Service c5cf8c
                } else {
Packit Service c5cf8c
                    comm = MPI::COMM_NULL;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                break;
Packit Service c5cf8c
Packit Service c5cf8c
            default:
Packit Service c5cf8c
                comm = MPI::COMM_NULL;
Packit Service c5cf8c
                interCommName = "MPI::COMM_NULL";
Packit Service c5cf8c
                interCommIdx = -1;
Packit Service c5cf8c
                break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (comm != MPI::COMM_NULL) {
Packit Service c5cf8c
            size = comm.Get_size();
Packit Service c5cf8c
            remsize = comm.Get_remote_size();
Packit Service c5cf8c
            if (size + remsize >= min_size)
Packit Service c5cf8c
                done = true;
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            done = true;
Packit Service c5cf8c
Packit Service c5cf8c
        /* we are only done if all processes are done */
Packit Service c5cf8c
        MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &done, 1, MPI::BOOL, MPI::LAND);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Advance the comm index whether we are done or not, otherwise we could
Packit Service c5cf8c
         * spin forever trying to allocate a too-small communicator over and
Packit Service c5cf8c
         * over again. */
Packit Service c5cf8c
        interCommIdx++;
Packit Service c5cf8c
Packit Service c5cf8c
        if (!done && comm != MPI::COMM_NULL) {
Packit Service c5cf8c
            comm.Free();
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return interCommIdx;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Return the name of an intercommunicator */
Packit Service c5cf8c
const char *MTestGetIntercommName(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    return interCommName;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Get a communicator of a given minimum size.  Both intra and inter
Packit Service c5cf8c
   communicators are provided
Packit Service c5cf8c
   Because Comm is an abstract base class, you can only have references
Packit Service c5cf8c
   to a Comm.*/
Packit Service c5cf8c
int MTestGetComm(MPI::Comm ** comm, int min_size)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int idx;
Packit Service c5cf8c
    static int getinter = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    if (!getinter) {
Packit Service c5cf8c
        MPI::Intracomm rcomm;
Packit Service c5cf8c
        idx = MTestGetIntracomm(rcomm, min_size);
Packit Service c5cf8c
        if (idx == 0) {
Packit Service c5cf8c
            getinter = 1;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            MPI::Intracomm * ncomm = new MPI::Intracomm(rcomm);
Packit Service c5cf8c
            *comm = ncomm;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (getinter) {
Packit Service c5cf8c
        MPI::Intercomm icomm;
Packit Service c5cf8c
        int isLeft;
Packit Service c5cf8c
        idx = MTestGetIntercomm(icomm, isLeft, min_size);
Packit Service c5cf8c
        if (idx == 0) {
Packit Service c5cf8c
            getinter = 0;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            MPI::Intercomm * ncomm = new MPI::Intercomm(icomm);
Packit Service c5cf8c
            *comm = ncomm;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return idx;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Free a communicator.  It may be called with a predefined communicator
Packit Service c5cf8c
 or MPI_COMM_NULL */
Packit Service c5cf8c
void MTestFreeComm(MPI::Comm & comm)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (comm != MPI::COMM_WORLD && comm != MPI::COMM_SELF && comm != MPI::COMM_NULL) {
Packit Service c5cf8c
        comm.Free();
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* ------------------------------------------------------------------------ */
Packit Service c5cf8c
void MTestPrintError(int errcode)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int errclass, slen;
Packit Service c5cf8c
    char string[MPI_MAX_ERROR_STRING];
Packit Service c5cf8c
Packit Service c5cf8c
    errclass = MPI::Get_error_class(errcode);
Packit Service c5cf8c
    MPI::Get_error_string(errcode, string, slen);
Packit Service c5cf8c
    cout << "Error class " << errclass << "(" << string << ")\n";
Packit Service c5cf8c
    cout.flush();
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
void MTestPrintErrorMsg(const char msg[], int errcode)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int errclass, slen;
Packit Service c5cf8c
    char string[MPI_MAX_ERROR_STRING];
Packit Service c5cf8c
Packit Service c5cf8c
    errclass = MPI::Get_error_class(errcode);
Packit Service c5cf8c
    MPI::Get_error_string(errcode, string, slen);
Packit Service c5cf8c
    cout << msg << ": Error class " << errclass << " (" << string << ")\n";
Packit Service c5cf8c
    cout.flush();
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* ------------------------------------------------------------------------ */
Packit Service c5cf8c
/* Fatal error.  Report and exit */
Packit Service c5cf8c
void MTestError(const char *msg)
Packit Service c5cf8c
{
Packit Service c5cf8c
    cerr << msg << "\n";
Packit Service c5cf8c
    cerr.flush();
Packit Service c5cf8c
    MPI::COMM_WORLD.Abort(1);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef HAVE_MPI_WIN_CREATE
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Create MPI Windows
Packit Service c5cf8c
 */
Packit Service c5cf8c
static int win_index = 0;
Packit Service c5cf8c
static const char *winName;
Packit Service c5cf8c
/* Use an attribute to remember the type of memory allocation (static,
Packit Service c5cf8c
   malloc, or MPI_Alloc_mem) */
Packit Service c5cf8c
static int mem_keyval = MPI::KEYVAL_INVALID;
Packit Service c5cf8c
int MTestGetWin(MPI::Win & win, bool mustBePassive)
Packit Service c5cf8c
{
Packit Service c5cf8c
    static char actbuf[1024];
Packit Service c5cf8c
    static char *pasbuf;
Packit Service c5cf8c
    char *buf;
Packit Service c5cf8c
    int n, rank;
Packit Service c5cf8c
    MPI::Info info;
Packit Service c5cf8c
Packit Service c5cf8c
    if (mem_keyval == MPI::KEYVAL_INVALID) {
Packit Service c5cf8c
        /* Create the keyval */
Packit Service c5cf8c
        mem_keyval = MPI::Win::Create_keyval(MPI::Win::NULL_COPY_FN, MPI::Win::NULL_DELETE_FN, 0);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    switch (win_index) {
Packit Service c5cf8c
        case 0:
Packit Service c5cf8c
            /* Active target window */
Packit Service c5cf8c
            win = MPI::Win::Create(actbuf, 1024, 1, MPI::INFO_NULL, MPI::COMM_WORLD);
Packit Service c5cf8c
            winName = "active-window";
Packit Service c5cf8c
            win.Set_attr(mem_keyval, (void *) 0);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        case 1:
Packit Service c5cf8c
            /* Passive target window */
Packit Service c5cf8c
            pasbuf = (char *) MPI::Alloc_mem(1024, MPI::INFO_NULL);
Packit Service c5cf8c
            win = MPI::Win::Create(pasbuf, 1024, 1, MPI::INFO_NULL, MPI::COMM_WORLD);
Packit Service c5cf8c
            winName = "passive-window";
Packit Service c5cf8c
            win.Set_attr(mem_keyval, (void *) 2);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        case 2:
Packit Service c5cf8c
            /* Active target; all windows different sizes */
Packit Service c5cf8c
            rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
            n = rank * 64;
Packit Service c5cf8c
            if (n)
Packit Service c5cf8c
                buf = (char *) malloc(n);
Packit Service c5cf8c
            else
Packit Service c5cf8c
                buf = 0;
Packit Service c5cf8c
            win = MPI::Win::Create(buf, n, 1, MPI::INFO_NULL, MPI::COMM_WORLD);
Packit Service c5cf8c
            winName = "active-all-different-win";
Packit Service c5cf8c
            win.Set_attr(mem_keyval, (void *) 1);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        case 3:
Packit Service c5cf8c
            /* Active target, no locks set */
Packit Service c5cf8c
            rank = MPI::COMM_WORLD.Get_rank();
Packit Service c5cf8c
            n = rank * 64;
Packit Service c5cf8c
            if (n)
Packit Service c5cf8c
                buf = (char *) malloc(n);
Packit Service c5cf8c
            else
Packit Service c5cf8c
                buf = 0;
Packit Service c5cf8c
            info = MPI::Info::Create();
Packit Service c5cf8c
            info.Set("nolocks", "true");
Packit Service c5cf8c
            win = MPI::Win::Create(buf, n, 1, info, MPI::COMM_WORLD);
Packit Service c5cf8c
            info.Free();
Packit Service c5cf8c
            winName = "active-nolocks-all-different-win";
Packit Service c5cf8c
            win.Set_attr(mem_keyval, (void *) 1);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        default:
Packit Service c5cf8c
            win_index = -1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    win_index++;
Packit Service c5cf8c
    return win_index;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Return a pointer to the name associated with a window object */
Packit Service c5cf8c
const char *MTestGetWinName(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
Packit Service c5cf8c
    return winName;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Free the storage associated with a window object */
Packit Service c5cf8c
void MTestFreeWin(MPI::Win & win)
Packit Service c5cf8c
{
Packit Service c5cf8c
    void *addr;
Packit Service c5cf8c
    bool flag;
Packit Service c5cf8c
Packit Service c5cf8c
    flag = win.Get_attr(MPI_WIN_BASE, &addr);
Packit Service c5cf8c
    if (!flag) {
Packit Service c5cf8c
        MTestError("Could not get WIN_BASE from window");
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (addr) {
Packit Service c5cf8c
        void *val;
Packit Service c5cf8c
        flag = win.Get_attr(mem_keyval, &val;;
Packit Service c5cf8c
        if (flag) {
Packit Service c5cf8c
            if (val == (void *) 1) {
Packit Service c5cf8c
                free(addr);
Packit Service c5cf8c
            } else if (val == (void *) 2) {
Packit Service c5cf8c
                MPI::Free_mem(addr);
Packit Service c5cf8c
            }
Packit Service c5cf8c
            /* if val == (void *)0, then static data that must not be freed */
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    win.Free();
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static void MTestRMACleanup(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (mem_keyval != MPI::KEYVAL_INVALID) {
Packit Service c5cf8c
        MPI::Win::Free_keyval(mem_keyval);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
#else
Packit Service c5cf8c
static void MTestRMACleanup(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
}
Packit Service c5cf8c
#endif