Blame src/mpi/group/grouputil.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
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 "group.h"
Packit Service c5cf8c
Packit Service c5cf8c
#ifndef MPID_GROUP_PREALLOC
Packit Service c5cf8c
#define MPID_GROUP_PREALLOC 8
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* Preallocated group objects */
Packit Service c5cf8c
MPIR_Group MPIR_Group_builtin[MPIR_GROUP_N_BUILTIN] = { {0}
Packit Service c5cf8c
};
Packit Service c5cf8c
MPIR_Group MPIR_Group_direct[MPID_GROUP_PREALLOC] = { {0}
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
MPIR_Object_alloc_t MPIR_Group_mem = { 0, 0, 0, 0, MPIR_GROUP,
Packit Service c5cf8c
    sizeof(MPIR_Group), MPIR_Group_direct,
Packit Service c5cf8c
    MPID_GROUP_PREALLOC
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
MPIR_Group *const MPIR_Group_empty = &MPIR_Group_builtin[0];
Packit Service c5cf8c
Packit Service c5cf8c
int MPIR_Group_init(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Assert(MPIR_GROUP_N_BUILTIN == 1);     /* update this func if this ever triggers */
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Group_builtin[0].handle = MPI_GROUP_EMPTY;
Packit Service c5cf8c
    MPIR_Object_set_ref(&MPIR_Group_builtin[0], 1);
Packit Service c5cf8c
    MPIR_Group_builtin[0].size = 0;
Packit Service c5cf8c
    MPIR_Group_builtin[0].rank = MPI_UNDEFINED;
Packit Service c5cf8c
    MPIR_Group_builtin[0].idx_of_first_lpid = -1;
Packit Service c5cf8c
    MPIR_Group_builtin[0].lrank_to_lpid = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    /* TODO hook for device here? */
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
int MPIR_Group_release(MPIR_Group * group_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int inuse;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Group_release_ref(group_ptr, &inuse);
Packit Service c5cf8c
    if (!inuse) {
Packit Service c5cf8c
        /* Only if refcount is 0 do we actually free. */
Packit Service c5cf8c
        MPL_free(group_ptr->lrank_to_lpid);
Packit Service c5cf8c
        MPIR_Handle_obj_free(&MPIR_Group_mem, group_ptr);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Allocate a new group and the group lrank to lpid array.  Does *not*
Packit Service c5cf8c
 * initialize any arrays, but does set the reference count.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#define FCNAME "MPIR_Group_create"
Packit Service c5cf8c
int MPIR_Group_create(int nproc, MPIR_Group ** new_group_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    *new_group_ptr = (MPIR_Group *) MPIR_Handle_obj_alloc(&MPIR_Group_mem);
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (!*new_group_ptr) {
Packit Service c5cf8c
        mpi_errno =
Packit Service c5cf8c
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, "MPIR_Group_create", __LINE__,
Packit Service c5cf8c
                                 MPI_ERR_OTHER, "**nomem", 0);
Packit Service c5cf8c
        return mpi_errno;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
    MPIR_Object_set_ref(*new_group_ptr, 1);
Packit Service c5cf8c
    (*new_group_ptr)->lrank_to_lpid =
Packit Service c5cf8c
        (MPII_Group_pmap_t *) MPL_malloc(nproc * sizeof(MPII_Group_pmap_t), MPL_MEM_GROUP);
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (!(*new_group_ptr)->lrank_to_lpid) {
Packit Service c5cf8c
        MPIR_Handle_obj_free(&MPIR_Group_mem, *new_group_ptr);
Packit Service c5cf8c
        *new_group_ptr = NULL;
Packit Service c5cf8c
        MPIR_CHKMEM_SETERR(mpi_errno, nproc * sizeof(MPII_Group_pmap_t), "newgroup->lrank_to_lpid");
Packit Service c5cf8c
        return mpi_errno;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
    (*new_group_ptr)->size = nproc;
Packit Service c5cf8c
    /* Make sure that there is no question that the list of ranks sorted
Packit Service c5cf8c
     * by pids is marked as uninitialized */
Packit Service c5cf8c
    (*new_group_ptr)->idx_of_first_lpid = -1;
Packit Service c5cf8c
Packit Service c5cf8c
    (*new_group_ptr)->is_local_dense_monotonic = FALSE;
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * return value is the first index in the list
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * This "sorts" an lpid array by lpid value, using a simple merge sort
Packit Service c5cf8c
 * algorithm.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * In actuality, it does not reorder the elements of maparray (these must remain
Packit Service c5cf8c
 * in group rank order).  Instead it builds the traversal order (in increasing
Packit Service c5cf8c
 * lpid order) through the maparray given by the "next_lpid" fields.
Packit Service c5cf8c
 */
Packit Service c5cf8c
static int mergesort_lpidarray(MPII_Group_pmap_t maparray[], int n)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int idx1, idx2, first_idx, cur_idx, next_lpid, idx2_offset;
Packit Service c5cf8c
Packit Service c5cf8c
    if (n == 2) {
Packit Service c5cf8c
        if (maparray[0].lpid > maparray[1].lpid) {
Packit Service c5cf8c
            first_idx = 1;
Packit Service c5cf8c
            maparray[0].next_lpid = -1;
Packit Service c5cf8c
            maparray[1].next_lpid = 0;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            first_idx = 0;
Packit Service c5cf8c
            maparray[0].next_lpid = 1;
Packit Service c5cf8c
            maparray[1].next_lpid = -1;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        return first_idx;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (n == 1) {
Packit Service c5cf8c
        maparray[0].next_lpid = -1;
Packit Service c5cf8c
        return 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (n == 0)
Packit Service c5cf8c
        return -1;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Sort each half */
Packit Service c5cf8c
    idx2_offset = n / 2;
Packit Service c5cf8c
    idx1 = mergesort_lpidarray(maparray, n / 2);
Packit Service c5cf8c
    idx2 = mergesort_lpidarray(maparray + idx2_offset, n - n / 2) + idx2_offset;
Packit Service c5cf8c
    /* merge the results */
Packit Service c5cf8c
    /* There are three lists:
Packit Service c5cf8c
     * first_idx - points to the HEAD of the sorted, merged list
Packit Service c5cf8c
     * cur_idx - points to the LAST element of the sorted, merged list
Packit Service c5cf8c
     * idx1    - points to the HEAD of one sorted list
Packit Service c5cf8c
     * idx2    - points to the HEAD of the other sorted list
Packit Service c5cf8c
     *
Packit Service c5cf8c
     * We first identify the head element of the sorted list.  We then
Packit Service c5cf8c
     * take elements from the remaining lists.  When one list is empty,
Packit Service c5cf8c
     * we add the other list to the end of sorted list.
Packit Service c5cf8c
     *
Packit Service c5cf8c
     * The last wrinkle is that the next_lpid fields in maparray[idx2]
Packit Service c5cf8c
     * are relative to n/2, not 0 (that is, a next_lpid of 1 is
Packit Service c5cf8c
     * really 1 + n/2, relative to the beginning of maparray).
Packit Service c5cf8c
     */
Packit Service c5cf8c
    /* Find the head element */
Packit Service c5cf8c
    if (maparray[idx1].lpid > maparray[idx2].lpid) {
Packit Service c5cf8c
        first_idx = idx2;
Packit Service c5cf8c
        idx2 = maparray[idx2].next_lpid + idx2_offset;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        first_idx = idx1;
Packit Service c5cf8c
        idx1 = maparray[idx1].next_lpid;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* Merge the lists until one is empty */
Packit Service c5cf8c
    cur_idx = first_idx;
Packit Service c5cf8c
    while (idx1 >= 0 && idx2 >= 0) {
Packit Service c5cf8c
        if (maparray[idx1].lpid > maparray[idx2].lpid) {
Packit Service c5cf8c
            next_lpid = maparray[idx2].next_lpid;
Packit Service c5cf8c
            if (next_lpid >= 0)
Packit Service c5cf8c
                next_lpid += idx2_offset;
Packit Service c5cf8c
            maparray[cur_idx].next_lpid = idx2;
Packit Service c5cf8c
            cur_idx = idx2;
Packit Service c5cf8c
            idx2 = next_lpid;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            next_lpid = maparray[idx1].next_lpid;
Packit Service c5cf8c
            maparray[cur_idx].next_lpid = idx1;
Packit Service c5cf8c
            cur_idx = idx1;
Packit Service c5cf8c
            idx1 = next_lpid;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* Add whichever list remains */
Packit Service c5cf8c
    if (idx1 >= 0) {
Packit Service c5cf8c
        maparray[cur_idx].next_lpid = idx1;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        maparray[cur_idx].next_lpid = idx2;
Packit Service c5cf8c
        /* Convert the rest of these next_lpid values to be
Packit Service c5cf8c
         * relative to the beginning of maparray */
Packit Service c5cf8c
        while (idx2 >= 0) {
Packit Service c5cf8c
            next_lpid = maparray[idx2].next_lpid;
Packit Service c5cf8c
            if (next_lpid >= 0) {
Packit Service c5cf8c
                next_lpid += idx2_offset;
Packit Service c5cf8c
                maparray[idx2].next_lpid = next_lpid;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            idx2 = next_lpid;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return first_idx;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Create a list of the lpids, in lpid order.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * Called by group_compare, group_translate_ranks, group_union
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * In the case of a single master thread lock, the lock must
Packit Service c5cf8c
 * be held on entry to this routine.  This forces some of the routines
Packit Service c5cf8c
 * noted above to hold the SINGLE_CS; which would otherwise not be required.
Packit Service c5cf8c
 */
Packit Service c5cf8c
void MPII_Group_setup_lpid_list(MPIR_Group * group_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (group_ptr->idx_of_first_lpid == -1) {
Packit Service c5cf8c
        group_ptr->idx_of_first_lpid =
Packit Service c5cf8c
            mergesort_lpidarray(group_ptr->lrank_to_lpid, group_ptr->size);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
void MPIR_Group_setup_lpid_pairs(MPIR_Group * group_ptr1, MPIR_Group * group_ptr2)
Packit Service c5cf8c
{
Packit Service c5cf8c
    /* If the lpid list hasn't been created, do it now */
Packit Service c5cf8c
    if (group_ptr1->idx_of_first_lpid < 0) {
Packit Service c5cf8c
        MPII_Group_setup_lpid_list(group_ptr1);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (group_ptr2->idx_of_first_lpid < 0) {
Packit Service c5cf8c
        MPII_Group_setup_lpid_list(group_ptr2);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * The following routines are needed only for error checking
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Group_check_valid_ranks
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME "MPIR_Group_check_valid_ranks"
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * This routine is for error checking for a valid ranks array, used
Packit Service c5cf8c
 * by Group_incl and Group_excl.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * Note that because this uses the flag field in the group, it
Packit Service c5cf8c
 * must be used by only on thread at a time (per group).  For the SINGLE_CS
Packit Service c5cf8c
 * case, that means that the SINGLE_CS must be held on entry to this routine.
Packit Service c5cf8c
 */
Packit Service c5cf8c
int MPIR_Group_check_valid_ranks(MPIR_Group * group_ptr, const int ranks[], int n)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS, i;
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < group_ptr->size; i++) {
Packit Service c5cf8c
        group_ptr->lrank_to_lpid[i].flag = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < n; i++) {
Packit Service c5cf8c
        if (ranks[i] < 0 || ranks[i] >= group_ptr->size) {
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_RANK, "**rankarray", "**rankarray %d %d %d", i,
Packit Service c5cf8c
                                     ranks[i], group_ptr->size - 1);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (group_ptr->lrank_to_lpid[ranks[i]].flag) {
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_RANK, "**rankdup", "**rankdup %d %d %d", i, ranks[i],
Packit Service c5cf8c
                                     group_ptr->lrank_to_lpid[ranks[i]].flag - 1);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        group_ptr->lrank_to_lpid[ranks[i]].flag = i + 1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Service routine to check for valid range arguments.  This routine makes use
Packit Service c5cf8c
 of some of the internal fields in a group; in a multithreaded MPI program,
Packit Service c5cf8c
 these must ensure that only one thread is accessing the group at a time.
Packit Service c5cf8c
 In the SINGLE_CS model, this routine requires that the calling routine
Packit Service c5cf8c
 be within the SINGLE_CS (the routines are group_range_incl and
Packit Service c5cf8c
 group_range_excl) */
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Group_check_valid_ranges
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME "MPIR_Group_check_valid_ranges"
Packit Service c5cf8c
int MPIR_Group_check_valid_ranges(MPIR_Group * group_ptr, int ranges[][3], int n)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j, size, first, last, stride, mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    if (n < 0) {
Packit Service c5cf8c
        MPIR_ERR_SETANDSTMT2(mpi_errno, MPI_ERR_ARG,;, "**argneg", "**argneg %s %d", "n", n);
Packit Service c5cf8c
        return mpi_errno;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    size = group_ptr->size;
Packit Service c5cf8c
Packit Service c5cf8c
    /* First, clear the flag */
Packit Service c5cf8c
    for (i = 0; i < size; i++) {
Packit Service c5cf8c
        group_ptr->lrank_to_lpid[i].flag = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < n; i++) {
Packit Service c5cf8c
        int act_last;
Packit Service c5cf8c
Packit Service c5cf8c
        first = ranges[i][0];
Packit Service c5cf8c
        last = ranges[i][1];
Packit Service c5cf8c
        stride = ranges[i][2];
Packit Service c5cf8c
        if (first < 0 || first >= size) {
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_ARG, "**rangestartinvalid",
Packit Service c5cf8c
                                     "**rangestartinvalid %d %d %d", i, first, size);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (stride == 0) {
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_ARG, "**stridezero", 0);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* We must compute the actual last value, taking into account
Packit Service c5cf8c
         * the stride value.  At this point, we know that the stride is
Packit Service c5cf8c
         * non-zero
Packit Service c5cf8c
         */
Packit Service c5cf8c
        act_last = first + stride * ((last - first) / stride);
Packit Service c5cf8c
Packit Service c5cf8c
        if (last < 0 || act_last >= size) {
Packit Service c5cf8c
            /* Use last instead of act_last in the error message since
Packit Service c5cf8c
             * the last value is the one that the user provided */
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_ARG, "**rangeendinvalid", "**rangeendinvalid %d %d %d",
Packit Service c5cf8c
                                     i, last, size);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if ((stride > 0 && first > last) || (stride < 0 && first < last)) {
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_ARG, "**stride", "**stride %d %d %d", first, last,
Packit Service c5cf8c
                                     stride);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* range is valid.  Mark flags */
Packit Service c5cf8c
        if (stride > 0) {
Packit Service c5cf8c
            for (j = first; j <= last; j += stride) {
Packit Service c5cf8c
                if (group_ptr->lrank_to_lpid[j].flag) {
Packit Service c5cf8c
                    mpi_errno =
Packit Service c5cf8c
                        MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                             MPI_ERR_ARG, "**rangedup", "**rangedup %d %d %d", j, i,
Packit Service c5cf8c
                                             group_ptr->lrank_to_lpid[j].flag - 1);
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                } else
Packit Service c5cf8c
                    group_ptr->lrank_to_lpid[j].flag = 1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            for (j = first; j >= last; j += stride) {
Packit Service c5cf8c
                if (group_ptr->lrank_to_lpid[j].flag) {
Packit Service c5cf8c
                    mpi_errno =
Packit Service c5cf8c
                        MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                             MPI_ERR_ARG, "**rangedup", "**rangedup %d %d %d", j, i,
Packit Service c5cf8c
                                             group_ptr->lrank_to_lpid[j].flag - 1);
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                } else
Packit Service c5cf8c
                    /* Set to i + 1 so that we can remember where it was
Packit Service c5cf8c
                     * first set */
Packit Service c5cf8c
                    group_ptr->lrank_to_lpid[j].flag = i + 1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            break;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Given a group and a comm, check that the group is a subset of the processes
Packit Service c5cf8c
   defined by the comm.
Packit Service c5cf8c
Packit Service c5cf8c
   We sort the lpids for the group and the comm.  If the group has an
Packit Service c5cf8c
   lpid that is not in the comm, then report an error.
Packit Service c5cf8c
*/
Packit Service c5cf8c
int MPIR_Group_check_subset(MPIR_Group * group_ptr, MPIR_Comm * comm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int g1_idx, g2_idx, l1_pid, l2_pid, i;
Packit Service c5cf8c
    MPII_Group_pmap_t *vmap = 0;
Packit Service c5cf8c
    int vsize = comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM ? comm_ptr->local_size :
Packit Service c5cf8c
        comm_ptr->remote_size;
Packit Service c5cf8c
    MPIR_CHKLMEM_DECL(1);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Assert(group_ptr != NULL);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKLMEM_MALLOC(vmap, MPII_Group_pmap_t *,
Packit Service c5cf8c
                        vsize * sizeof(MPII_Group_pmap_t), mpi_errno, "", MPL_MEM_GROUP);
Packit Service c5cf8c
    /* Initialize the vmap */
Packit Service c5cf8c
    for (i = 0; i < vsize; i++) {
Packit Service c5cf8c
        MPID_Comm_get_lpid(comm_ptr, i, &vmap[i].lpid, FALSE);
Packit Service c5cf8c
        vmap[i].next_lpid = 0;
Packit Service c5cf8c
        vmap[i].flag = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    MPII_Group_setup_lpid_list(group_ptr);
Packit Service c5cf8c
    g1_idx = group_ptr->idx_of_first_lpid;
Packit Service c5cf8c
    g2_idx = mergesort_lpidarray(vmap, vsize);
Packit Service c5cf8c
    MPL_DBG_MSG_FMT(MPIR_DBG_COMM, VERBOSE, (MPL_DBG_FDEST,
Packit Service c5cf8c
                                             "initial indices: %d %d\n", g1_idx, g2_idx));
Packit Service c5cf8c
    while (g1_idx >= 0 && g2_idx >= 0) {
Packit Service c5cf8c
        l1_pid = group_ptr->lrank_to_lpid[g1_idx].lpid;
Packit Service c5cf8c
        l2_pid = vmap[g2_idx].lpid;
Packit Service c5cf8c
        MPL_DBG_MSG_FMT(MPIR_DBG_COMM, VERBOSE, (MPL_DBG_FDEST,
Packit Service c5cf8c
                                                 "Lpids are %d, %d\n", l1_pid, l2_pid));
Packit Service c5cf8c
        if (l1_pid < l2_pid) {
Packit Service c5cf8c
            /* If we have to advance g1, we didn't find a match, so
Packit Service c5cf8c
             * that's an error. */
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        } else if (l1_pid > l2_pid) {
Packit Service c5cf8c
            g2_idx = vmap[g2_idx].next_lpid;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            /* Equal */
Packit Service c5cf8c
            g1_idx = group_ptr->lrank_to_lpid[g1_idx].next_lpid;
Packit Service c5cf8c
            g2_idx = vmap[g2_idx].next_lpid;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        MPL_DBG_MSG_FMT(MPIR_DBG_COMM, VERBOSE, (MPL_DBG_FDEST,
Packit Service c5cf8c
                                                 "g1 = %d, g2 = %d\n", g1_idx, g2_idx));
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (g1_idx >= 0) {
Packit Service c5cf8c
        MPIR_ERR_SET1(mpi_errno, MPI_ERR_GROUP, "**groupnotincomm", "**groupnotincomm %d", g1_idx);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    MPIR_CHKLMEM_FREEALL();
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#endif /* HAVE_ERROR_CHECKING */