Blame src/mpi/comm/comm_split.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
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
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
#include "mpicomm.h"
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
=== BEGIN_MPI_T_CVAR_INFO_BLOCK ===
Packit Service c5cf8c
Packit Service c5cf8c
categories:
Packit Service c5cf8c
    - name        : COMMUNICATOR
Packit Service c5cf8c
      description : cvars that control communicator construction and operation
Packit Service c5cf8c
Packit Service c5cf8c
cvars:
Packit Service c5cf8c
    - name        : MPIR_CVAR_COMM_SPLIT_USE_QSORT
Packit Service c5cf8c
      category    : COMMUNICATOR
Packit Service c5cf8c
      type        : boolean
Packit Service c5cf8c
      default     : true
Packit Service c5cf8c
      class       : device
Packit Service c5cf8c
      verbosity   : MPI_T_VERBOSITY_USER_BASIC
Packit Service c5cf8c
      scope       : MPI_T_SCOPE_ALL_EQ
Packit Service c5cf8c
      description : >-
Packit Service c5cf8c
        Use qsort(3) in the implementation of MPI_Comm_split instead of bubble sort.
Packit Service c5cf8c
Packit Service c5cf8c
=== END_MPI_T_CVAR_INFO_BLOCK ===
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
/* -- Begin Profiling Symbol Block for routine MPI_Comm_split */
Packit Service c5cf8c
#if defined(HAVE_PRAGMA_WEAK)
Packit Service c5cf8c
#pragma weak MPI_Comm_split = PMPI_Comm_split
Packit Service c5cf8c
#elif defined(HAVE_PRAGMA_HP_SEC_DEF)
Packit Service c5cf8c
#pragma _HP_SECONDARY_DEF PMPI_Comm_split  MPI_Comm_split
Packit Service c5cf8c
#elif defined(HAVE_PRAGMA_CRI_DUP)
Packit Service c5cf8c
#pragma _CRI duplicate MPI_Comm_split as PMPI_Comm_split
Packit Service c5cf8c
#elif defined(HAVE_WEAK_ATTRIBUTE)
Packit Service c5cf8c
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm * newcomm)
Packit Service c5cf8c
    __attribute__ ((weak, alias("PMPI_Comm_split")));
Packit Service c5cf8c
#endif
Packit Service c5cf8c
/* -- End Profiling Symbol Block */
Packit Service c5cf8c
Packit Service c5cf8c
/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
Packit Service c5cf8c
   the MPI routines */
Packit Service c5cf8c
#ifndef MPICH_MPI_FROM_PMPI
Packit Service c5cf8c
#undef MPI_Comm_split
Packit Service c5cf8c
#define MPI_Comm_split PMPI_Comm_split
Packit Service c5cf8c
Packit Service c5cf8c
typedef struct splittype {
Packit Service c5cf8c
    int color, key;
Packit Service c5cf8c
} splittype;
Packit Service c5cf8c
Packit Service c5cf8c
/* Same as splittype but with an additional field to stabilize the qsort.  We
Packit Service c5cf8c
 * could just use one combined type, but using separate types simplifies the
Packit Service c5cf8c
 * allgather step. */
Packit Service c5cf8c
typedef struct sorttype {
Packit Service c5cf8c
    int color, key;
Packit Service c5cf8c
    int orig_idx;
Packit Service c5cf8c
} sorttype;
Packit Service c5cf8c
Packit Service c5cf8c
#if defined(HAVE_QSORT)
Packit Service c5cf8c
static int sorttype_compare(const void *v1, const void *v2)
Packit Service c5cf8c
{
Packit Service c5cf8c
    const sorttype *s1 = v1;
Packit Service c5cf8c
    const sorttype *s2 = v2;
Packit Service c5cf8c
Packit Service c5cf8c
    if (s1->key > s2->key)
Packit Service c5cf8c
        return 1;
Packit Service c5cf8c
    if (s1->key < s2->key)
Packit Service c5cf8c
        return -1;
Packit Service c5cf8c
Packit Service c5cf8c
    /* (s1->key == s2->key), maintain original order */
Packit Service c5cf8c
    if (s1->orig_idx > s2->orig_idx)
Packit Service c5cf8c
        return 1;
Packit Service c5cf8c
    else if (s1->orig_idx < s2->orig_idx)
Packit Service c5cf8c
        return -1;
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    return 0;   /* should never happen */
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
}
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* Sort the entries in keytable into increasing order by key.  A stable
Packit Service c5cf8c
   sort should be used incase the key values are not unique. */
Packit Service c5cf8c
static void MPIU_Sort_inttable(sorttype * keytable, int size)
Packit Service c5cf8c
{
Packit Service c5cf8c
    sorttype tmp;
Packit Service c5cf8c
    int i, j;
Packit Service c5cf8c
Packit Service c5cf8c
#if defined(HAVE_QSORT)
Packit Service c5cf8c
    /* temporary switch for profiling performance differences */
Packit Service c5cf8c
    if (MPIR_CVAR_COMM_SPLIT_USE_QSORT) {
Packit Service c5cf8c
        /* qsort isn't a stable sort, so we have to enforce stability by keeping
Packit Service c5cf8c
         * track of the original indices */
Packit Service c5cf8c
        for (i = 0; i < size; ++i)
Packit Service c5cf8c
            keytable[i].orig_idx = i;
Packit Service c5cf8c
        qsort(keytable, size, sizeof(sorttype), &sorttype_compare);
Packit Service c5cf8c
    } else
Packit Service c5cf8c
#endif
Packit Service c5cf8c
    {
Packit Service c5cf8c
        /* --BEGIN USEREXTENSION-- */
Packit Service c5cf8c
        /* fall through to insertion sort if qsort is unavailable/disabled */
Packit Service c5cf8c
        for (i = 1; i < size; ++i) {
Packit Service c5cf8c
            tmp = keytable[i];
Packit Service c5cf8c
            j = i - 1;
Packit Service c5cf8c
            while (1) {
Packit Service c5cf8c
                if (keytable[j].key > tmp.key) {
Packit Service c5cf8c
                    keytable[j + 1] = keytable[j];
Packit Service c5cf8c
                    j = j - 1;
Packit Service c5cf8c
                    if (j < 0)
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                } else {
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            keytable[j + 1] = tmp;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* --END USEREXTENSION-- */
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_split_impl
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_split_impl(MPIR_Comm * comm_ptr, int color, int key, MPIR_Comm ** newcomm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm *local_comm_ptr;
Packit Service c5cf8c
    splittype *table, *remotetable = 0;
Packit Service c5cf8c
    sorttype *keytable, *remotekeytable = 0;
Packit Service c5cf8c
    int rank, size, remote_size, i, new_size, new_remote_size,
Packit Service c5cf8c
        first_entry = 0, first_remote_entry = 0, *last_ptr;
Packit Service c5cf8c
    int in_newcomm;             /* TRUE iff *newcomm should be populated */
Packit Service c5cf8c
    MPIR_Context_id_t new_context_id, remote_context_id;
Packit Service c5cf8c
    MPIR_Errflag_t errflag = MPIR_ERR_NONE;
Packit Service c5cf8c
    MPIR_Comm_map_t *mapper;
Packit Service c5cf8c
    MPIR_CHKLMEM_DECL(4);
Packit Service c5cf8c
Packit Service c5cf8c
    rank = comm_ptr->rank;
Packit Service c5cf8c
    size = comm_ptr->local_size;
Packit Service c5cf8c
    remote_size = comm_ptr->remote_size;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Step 1: Find out what color and keys all of the processes have */
Packit Service c5cf8c
    MPIR_CHKLMEM_MALLOC(table, splittype *, size * sizeof(splittype), mpi_errno,
Packit Service c5cf8c
                        "table", MPL_MEM_COMM);
Packit Service c5cf8c
    table[rank].color = color;
Packit Service c5cf8c
    table[rank].key = key;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get the communicator to use in collectives on the local group of
Packit Service c5cf8c
     * processes */
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        if (!comm_ptr->local_comm) {
Packit Service c5cf8c
            MPII_Setup_intercomm_localcomm(comm_ptr);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        local_comm_ptr = comm_ptr->local_comm;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        local_comm_ptr = comm_ptr;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* Gather information on the local group of processes */
Packit Service c5cf8c
    mpi_errno =
Packit Service c5cf8c
        MPIR_Allgather(MPI_IN_PLACE, 2, MPI_INT, table, 2, MPI_INT, local_comm_ptr, &errflag);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail");
Packit Service c5cf8c
Packit Service c5cf8c
    /* Step 2: How many processes have our same color? */
Packit Service c5cf8c
    new_size = 0;
Packit Service c5cf8c
    if (color != MPI_UNDEFINED) {
Packit Service c5cf8c
        /* Also replace the color value with the index of the *next* value
Packit Service c5cf8c
         * in this set.  The integer first_entry is the index of the
Packit Service c5cf8c
         * first element */
Packit Service c5cf8c
        last_ptr = &first_entry;
Packit Service c5cf8c
        for (i = 0; i < size; i++) {
Packit Service c5cf8c
            /* Replace color with the index in table of the next item
Packit Service c5cf8c
             * of the same color.  We use this to efficiently populate
Packit Service c5cf8c
             * the keyval table */
Packit Service c5cf8c
            if (table[i].color == color) {
Packit Service c5cf8c
                new_size++;
Packit Service c5cf8c
                *last_ptr = i;
Packit Service c5cf8c
                last_ptr = &table[i].color;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* We don't need to set the last value to -1 because we loop through
Packit Service c5cf8c
     * the list for only the known size of the group */
Packit Service c5cf8c
Packit Service c5cf8c
    /* If we're an intercomm, we need to do the same thing for the remote
Packit Service c5cf8c
     * table, as we need to know the size of the remote group of the
Packit Service c5cf8c
     * same color before deciding to create the communicator */
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        splittype mypair;
Packit Service c5cf8c
        /* For the remote group, the situation is more complicated.
Packit Service c5cf8c
         * We need to find the size of our "partner" group in the
Packit Service c5cf8c
         * remote comm.  The easiest way (in terms of code) is for
Packit Service c5cf8c
         * every process to essentially repeat the operation for the
Packit Service c5cf8c
         * local group - perform an (intercommunicator) all gather
Packit Service c5cf8c
         * of the color and rank information for the remote group.
Packit Service c5cf8c
         */
Packit Service c5cf8c
        MPIR_CHKLMEM_MALLOC(remotetable, splittype *,
Packit Service c5cf8c
                            remote_size * sizeof(splittype), mpi_errno,
Packit Service c5cf8c
                            "remotetable", MPL_MEM_COMM);
Packit Service c5cf8c
        /* This is an intercommunicator allgather */
Packit Service c5cf8c
Packit Service c5cf8c
        /* We must use a local splittype because we've already modified the
Packit Service c5cf8c
         * entries in table to indicate the location of the next rank of the
Packit Service c5cf8c
         * same color */
Packit Service c5cf8c
        mypair.color = color;
Packit Service c5cf8c
        mypair.key = key;
Packit Service c5cf8c
        mpi_errno = MPIR_Allgather(&mypair, 2, MPI_INT, remotetable, 2, MPI_INT,
Packit Service c5cf8c
                                   comm_ptr, &errflag);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail");
Packit Service c5cf8c
Packit Service c5cf8c
        /* Each process can now match its color with the entries in the table */
Packit Service c5cf8c
        new_remote_size = 0;
Packit Service c5cf8c
        last_ptr = &first_remote_entry;
Packit Service c5cf8c
        for (i = 0; i < remote_size; i++) {
Packit Service c5cf8c
            /* Replace color with the index in table of the next item
Packit Service c5cf8c
             * of the same color.  We use this to efficiently populate
Packit Service c5cf8c
             * the keyval table */
Packit Service c5cf8c
            if (remotetable[i].color == color) {
Packit Service c5cf8c
                new_remote_size++;
Packit Service c5cf8c
                *last_ptr = i;
Packit Service c5cf8c
                last_ptr = &remotetable[i].color;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* Note that it might find that there a now processes in the remote
Packit Service c5cf8c
         * group with the same color.  In that case, COMM_SPLIT will
Packit Service c5cf8c
         * return a null communicator */
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        /* Set the size of the remote group to the size of our group.
Packit Service c5cf8c
         * This simplifies the test below for intercomms with an empty remote
Packit Service c5cf8c
         * group (must create comm_null) */
Packit Service c5cf8c
        new_remote_size = new_size;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    in_newcomm = (color != MPI_UNDEFINED && new_remote_size > 0);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Step 3: Create the communicator */
Packit Service c5cf8c
    /* Collectively create a new context id.  The same context id will
Packit Service c5cf8c
     * be used by each (disjoint) collections of processes.  The
Packit Service c5cf8c
     * processes whose color is MPI_UNDEFINED will not influence the
Packit Service c5cf8c
     * resulting context id (by passing ignore_id==TRUE). */
Packit Service c5cf8c
    /* In the multi-threaded case, MPIR_Get_contextid_sparse assumes that the
Packit Service c5cf8c
     * calling routine already holds the single criticial section */
Packit Service c5cf8c
    mpi_errno = MPIR_Get_contextid_sparse(local_comm_ptr, &new_context_id, !in_newcomm);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    MPIR_Assert(new_context_id != 0);
Packit Service c5cf8c
Packit Service c5cf8c
    /* In the intercomm case, we need to exchange the context ids */
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        if (comm_ptr->rank == 0) {
Packit Service c5cf8c
            mpi_errno = MPIC_Sendrecv(&new_context_id, 1, MPIR_CONTEXT_ID_T_DATATYPE, 0, 0,
Packit Service c5cf8c
                                      &remote_context_id, 1, MPIR_CONTEXT_ID_T_DATATYPE,
Packit Service c5cf8c
                                      0, 0, comm_ptr, MPI_STATUS_IGNORE, &errflag);
Packit Service c5cf8c
            if (mpi_errno) {
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
            }
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Bcast(&remote_context_id, 1, MPIR_CONTEXT_ID_T_DATATYPE, 0, local_comm_ptr,
Packit Service c5cf8c
                           &errflag);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
            MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail");
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            /* Broadcast to the other members of the local group */
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Bcast(&remote_context_id, 1, MPIR_CONTEXT_ID_T_DATATYPE, 0, local_comm_ptr,
Packit Service c5cf8c
                           &errflag);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
            MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail");
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    *newcomm_ptr = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Now, create the new communicator structure if necessary */
Packit Service c5cf8c
    if (in_newcomm) {
Packit Service c5cf8c
Packit Service c5cf8c
        mpi_errno = MPIR_Comm_create(newcomm_ptr);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            goto fn_fail;
Packit Service c5cf8c
Packit Service c5cf8c
        (*newcomm_ptr)->recvcontext_id = new_context_id;
Packit Service c5cf8c
        (*newcomm_ptr)->local_size = new_size;
Packit Service c5cf8c
        (*newcomm_ptr)->pof2 = MPL_pof2(new_size);
Packit Service c5cf8c
        (*newcomm_ptr)->comm_kind = comm_ptr->comm_kind;
Packit Service c5cf8c
        /* Other fields depend on whether this is an intercomm or intracomm */
Packit Service c5cf8c
Packit Service c5cf8c
        /* Step 4: Order the processes by their key values.  Sort the
Packit Service c5cf8c
         * list that is stored in table.  To simplify the sort, we
Packit Service c5cf8c
         * extract the table into a smaller array and sort that.
Packit Service c5cf8c
         * Also, store in the "color" entry the rank in the input communicator
Packit Service c5cf8c
         * of the entry. */
Packit Service c5cf8c
        MPIR_CHKLMEM_MALLOC(keytable, sorttype *, new_size * sizeof(sorttype),
Packit Service c5cf8c
                            mpi_errno, "keytable", MPL_MEM_COMM);
Packit Service c5cf8c
        for (i = 0; i < new_size; i++) {
Packit Service c5cf8c
            keytable[i].key = table[first_entry].key;
Packit Service c5cf8c
            keytable[i].color = first_entry;
Packit Service c5cf8c
            first_entry = table[first_entry].color;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* sort key table.  The "color" entry is the rank of the corresponding
Packit Service c5cf8c
         * process in the input communicator */
Packit Service c5cf8c
        MPIU_Sort_inttable(keytable, new_size);
Packit Service c5cf8c
Packit Service c5cf8c
        if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
            MPIR_CHKLMEM_MALLOC(remotekeytable, sorttype *,
Packit Service c5cf8c
                                new_remote_size * sizeof(sorttype),
Packit Service c5cf8c
                                mpi_errno, "remote keytable", MPL_MEM_COMM);
Packit Service c5cf8c
            for (i = 0; i < new_remote_size; i++) {
Packit Service c5cf8c
                remotekeytable[i].key = remotetable[first_remote_entry].key;
Packit Service c5cf8c
                remotekeytable[i].color = first_remote_entry;
Packit Service c5cf8c
                first_remote_entry = remotetable[first_remote_entry].color;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* sort key table.  The "color" entry is the rank of the
Packit Service c5cf8c
             * corresponding process in the input communicator */
Packit Service c5cf8c
            MPIU_Sort_inttable(remotekeytable, new_remote_size);
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_irregular(*newcomm_ptr, comm_ptr, NULL,
Packit Service c5cf8c
                                    new_size, MPIR_COMM_MAP_DIR__L2L, &mapper);
Packit Service c5cf8c
Packit Service c5cf8c
            for (i = 0; i < new_size; i++) {
Packit Service c5cf8c
                mapper->src_mapping[i] = keytable[i].color;
Packit Service c5cf8c
                if (keytable[i].color == comm_ptr->rank)
Packit Service c5cf8c
                    (*newcomm_ptr)->rank = i;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* For the remote group, the situation is more complicated.
Packit Service c5cf8c
             * We need to find the size of our "partner" group in the
Packit Service c5cf8c
             * remote comm.  The easiest way (in terms of code) is for
Packit Service c5cf8c
             * every process to essentially repeat the operation for the
Packit Service c5cf8c
             * local group - perform an (intercommunicator) all gather
Packit Service c5cf8c
             * of the color and rank information for the remote group.
Packit Service c5cf8c
             */
Packit Service c5cf8c
            /* We apply the same sorting algorithm to the entries that we've
Packit Service c5cf8c
             * found to get the correct order of the entries.
Packit Service c5cf8c
             *
Packit Service c5cf8c
             * Note that if new_remote_size is 0 (no matching processes with
Packit Service c5cf8c
             * the same color in the remote group), then MPI_COMM_SPLIT
Packit Service c5cf8c
             * is required to return MPI_COMM_NULL instead of an intercomm
Packit Service c5cf8c
             * with an empty remote group. */
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_irregular(*newcomm_ptr, comm_ptr, NULL,
Packit Service c5cf8c
                                    new_remote_size, MPIR_COMM_MAP_DIR__R2R, &mapper);
Packit Service c5cf8c
Packit Service c5cf8c
            for (i = 0; i < new_remote_size; i++)
Packit Service c5cf8c
                mapper->src_mapping[i] = remotekeytable[i].color;
Packit Service c5cf8c
Packit Service c5cf8c
            (*newcomm_ptr)->context_id = remote_context_id;
Packit Service c5cf8c
            (*newcomm_ptr)->remote_size = new_remote_size;
Packit Service c5cf8c
            (*newcomm_ptr)->local_comm = 0;
Packit Service c5cf8c
            (*newcomm_ptr)->is_low_group = comm_ptr->is_low_group;
Packit Service c5cf8c
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            /* INTRA Communicator */
Packit Service c5cf8c
            (*newcomm_ptr)->context_id = (*newcomm_ptr)->recvcontext_id;
Packit Service c5cf8c
            (*newcomm_ptr)->remote_size = new_size;
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_irregular(*newcomm_ptr, comm_ptr, NULL,
Packit Service c5cf8c
                                    new_size, MPIR_COMM_MAP_DIR__L2L, &mapper);
Packit Service c5cf8c
Packit Service c5cf8c
            for (i = 0; i < new_size; i++) {
Packit Service c5cf8c
                mapper->src_mapping[i] = keytable[i].color;
Packit Service c5cf8c
                if (keytable[i].color == comm_ptr->rank)
Packit Service c5cf8c
                    (*newcomm_ptr)->rank = i;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* Inherit the error handler (if any) */
Packit Service c5cf8c
        MPID_THREAD_CS_ENTER(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr));
Packit Service c5cf8c
        (*newcomm_ptr)->errhandler = comm_ptr->errhandler;
Packit Service c5cf8c
        if (comm_ptr->errhandler) {
Packit Service c5cf8c
            MPIR_Errhandler_add_ref(comm_ptr->errhandler);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        MPID_THREAD_CS_EXIT(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr));
Packit Service c5cf8c
Packit Service c5cf8c
        mpi_errno = MPIR_Comm_commit(*newcomm_ptr);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_CHKLMEM_FREEALL();
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPI_Comm_split
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
/*@
Packit Service c5cf8c
Packit Service c5cf8c
MPI_Comm_split - Creates new communicators based on colors and keys
Packit Service c5cf8c
Packit Service c5cf8c
Input Parameters:
Packit Service c5cf8c
+ comm - communicator (handle)
Packit Service c5cf8c
. color - control of subset assignment (nonnegative integer).  Processes
Packit Service c5cf8c
  with the same color are in the same new communicator
Packit Service c5cf8c
- key - control of rank assignment (integer)
Packit Service c5cf8c
Packit Service c5cf8c
Output Parameters:
Packit Service c5cf8c
. newcomm - new communicator (handle)
Packit Service c5cf8c
Packit Service c5cf8c
Notes:
Packit Service c5cf8c
  The 'color' must be non-negative or 'MPI_UNDEFINED'.
Packit Service c5cf8c
Packit Service c5cf8c
.N ThreadSafe
Packit Service c5cf8c
Packit Service c5cf8c
.N Fortran
Packit Service c5cf8c
Packit Service c5cf8c
Algorithm:
Packit Service c5cf8c
.vb
Packit Service c5cf8c
  1. Use MPI_Allgather to get the color and key from each process
Packit Service c5cf8c
  2. Count the number of processes with the same color; create a
Packit Service c5cf8c
     communicator with that many processes.  If this process has
Packit Service c5cf8c
     'MPI_UNDEFINED' as the color, create a process with a single member.
Packit Service c5cf8c
  3. Use key to order the ranks
Packit Service c5cf8c
.ve
Packit Service c5cf8c
Packit Service c5cf8c
.N Errors
Packit Service c5cf8c
.N MPI_SUCCESS
Packit Service c5cf8c
.N MPI_ERR_COMM
Packit Service c5cf8c
.N MPI_ERR_EXHAUSTED
Packit Service c5cf8c
Packit Service c5cf8c
.seealso: MPI_Comm_free
Packit Service c5cf8c
@*/
Packit Service c5cf8c
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm * newcomm)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm *comm_ptr = NULL, *newcomm_ptr;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPI_COMM_SPLIT);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_ERRTEST_INITIALIZED_ORDIE();
Packit Service c5cf8c
Packit Service c5cf8c
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPI_COMM_SPLIT);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Validate parameters, especially handles needing to be converted */
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
    {
Packit Service c5cf8c
        MPID_BEGIN_ERROR_CHECKS;
Packit Service c5cf8c
        {
Packit Service c5cf8c
            MPIR_ERRTEST_COMM(comm, mpi_errno);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        MPID_END_ERROR_CHECKS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
#endif /* HAVE_ERROR_CHECKING */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get handles to MPI objects. */
Packit Service c5cf8c
    MPIR_Comm_get_ptr(comm, comm_ptr);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Validate parameters and objects (post conversion) */
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
    {
Packit Service c5cf8c
        MPID_BEGIN_ERROR_CHECKS;
Packit Service c5cf8c
        {
Packit Service c5cf8c
            /* Validate comm_ptr */
Packit Service c5cf8c
            MPIR_Comm_valid_ptr(comm_ptr, mpi_errno, FALSE);
Packit Service c5cf8c
            /* If comm_ptr is not valid, it will be reset to null */
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                goto fn_fail;
Packit Service c5cf8c
            MPIR_ERRTEST_ARGNULL(newcomm, "newcomm", mpi_errno);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        MPID_END_ERROR_CHECKS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif /* HAVE_ERROR_CHECKING */
Packit Service c5cf8c
Packit Service c5cf8c
    /* ... body of routine ...  */
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPIR_Comm_split_impl(comm_ptr, color, key, &newcomm_ptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    if (newcomm_ptr)
Packit Service c5cf8c
        MPIR_OBJ_PUBLISH_HANDLE(*newcomm, newcomm_ptr->handle);
Packit Service c5cf8c
    else
Packit Service c5cf8c
        *newcomm = MPI_COMM_NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    /* ... end of body of routine ... */
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPI_COMM_SPLIT);
Packit Service c5cf8c
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
    {
Packit Service c5cf8c
        mpi_errno =
Packit Service c5cf8c
            MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
Packit Service c5cf8c
                                 "**mpi_comm_split", "**mpi_comm_split %C %d %d %p", comm, color,
Packit Service c5cf8c
                                 key, newcomm);
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
    mpi_errno = MPIR_Err_return_comm(comm_ptr, FCNAME, mpi_errno);
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
}