Blame src/mpi/group/grouputil.c

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