Commit 1dd045fa authored by James Dinan's avatar James Dinan
Browse files

[svn-r9590] This patch adds native context id allocation for MPIX_Comm_create_group (MPI

Forum ticket #286) and updates MPI_Intercomm_create to use a collectives tag
space which does not conflict with point-to-point communication (MPI Forum
ticket #305).

In addition, this fixes a deadlock bug in context id allocation and adds
several regression tests (comm_dup_deadlock.c exercises this specific bug).

Reviewer: David Goodell
parent 0fc3f069
......@@ -168,6 +168,10 @@ do { \
if ((comm_ptr)->comm_kind != MPID_INTRACOMM) {\
err = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_COMM,"**commnotintra",0);}
#define MPIR_ERRTEST_COMM_TAG(tag,err) \
if ((tag) < 0 || (tag) > MPIR_Process.attrs.tag_ub) {\
err = MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_TAG, "**tag", "**tag %d", tag);}
/* Tests for totally meaningless datatypes first, then for
* MPI_DATATYPE_NULL as a separate case.
*/
......
......@@ -1322,6 +1322,7 @@ extern MPID_Comm MPID_Comm_direct[];
the device may need to create a new contextid */
int MPIR_Get_contextid( MPID_Comm *, MPIR_Context_id_t *context_id );
int MPIR_Get_contextid_sparse(MPID_Comm *comm_ptr, MPIR_Context_id_t *context_id, int ignore_id);
int MPIR_Get_contextid_sparse_group(MPID_Comm *comm_ptr, MPID_Group *group_ptr, int tag, MPIR_Context_id_t *context_id, int ignore_id);
void MPIR_Free_contextid( MPIR_Context_id_t );
/* ------------------------------------------------------------------------- */
......@@ -1947,6 +1948,7 @@ typedef struct MPICH_PerProcess_t {
that is separate from user's
versions */
PreDefined_attrs attrs; /* Predefined attribute values */
int tagged_coll_mask; /* Tag space mask for tagged collectives */
/* The topology routines dimsCreate is independent of any communicator.
If this pointer is null, the default routine is used */
......@@ -3852,6 +3854,17 @@ int MPIR_Setup_intercomm_localcomm( MPID_Comm * );
int MPIR_Comm_create( MPID_Comm ** );
/* comm_create helper functions, used by both comm_create and comm_create_group */
int MPIR_Comm_create_calculate_mapping(MPID_Group *group_ptr,
MPID_Comm *comm_ptr,
MPID_VCR **mapping_vcr_out,
int **mapping_out);
int MPIR_Comm_create_create_and_map_vcrt(int n,
int *mapping,
MPID_VCR *mapping_vcr,
MPID_VCRT *out_vcrt,
MPID_VCR **out_vcr);
int MPIR_Comm_commit( MPID_Comm * );
int MPIR_Comm_is_node_aware( MPID_Comm * );
......@@ -3862,6 +3875,12 @@ void MPIR_Free_err_dyncodes( void );
int MPIR_Comm_idup_impl(MPID_Comm *comm_ptr, MPID_Comm **newcomm, MPID_Request **reqp);
int MPIR_Allreduce_group(void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr,
MPID_Group *group_ptr, int tag, int *errflag);
int MPIR_Barrier_group(MPID_Comm *comm_ptr, MPID_Group *group_ptr, int tag, int *errflag);
/* begin impl functions for NBC */
int MPIR_Ibarrier_impl(MPID_Comm *comm_ptr, MPI_Request *request);
int MPIR_Ibcast_impl(void *buffer, int count, MPI_Datatype datatype, int root, MPID_Comm *comm_ptr, MPI_Request *request);
......
......@@ -49,6 +49,8 @@ mpi_sources += \
src/mpi/coll/iscatterv.c
lib_lib@MPILIBNAME@_la_SOURCES += \
src/mpi/coll/allred_group.c \
src/mpi/coll/barrier_group.c \
src/mpi/coll/helper_fns.c \
src/mpi/coll/opsum.c \
src/mpi/coll/opmax.c \
......
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
/*
* (C) 2012 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
#include "mpiimpl.h"
/* Map process IDs onto a binary tree.
*
* [in] comm_ptr Parent communicator
* [in] group_ptr Group on which to map the tree (must be a subgroup of comm_ptr's group)
* [out] root Process id of the root
* [out] up Process id of my parent
* [out] left Process id of my left child
* [out] right Process id of my right child
*/
static void MPIR_Allreduce_group_bintree(MPID_Comm *comm_ptr, MPID_Group *group_ptr, int *root,
int *up, int *left, int *right)
{
int ranks_in[4], ranks_out[4];
int me, nproc;
me = group_ptr->rank;
nproc = group_ptr->size;
*root = 0;
*up = (me == 0) ? MPI_PROC_NULL : (me - 1) / 2;
*left = 2*me + 1;
if (*left >= nproc) *left = MPI_PROC_NULL;
*right = 2*me + 2;
if (*right >= nproc) *right = MPI_PROC_NULL;
ranks_in[0] = *root;
ranks_in[1] = *up;
ranks_in[2] = *left;
ranks_in[3] = *right;
MPIR_Group_translate_ranks_impl(group_ptr, 4, ranks_in, comm_ptr->local_group, ranks_out);
*root = ranks_out[0];
*up = ranks_out[1];
*left = ranks_out[2];
*right= ranks_out[3];
}
/* Perform group-collective allreduce (binary tree reduce-broadcast algorithm).
*
* [in] sendbuf Input buffer
* [out] recvbuf Output buffer
* [in] count Number of data elements
* [in] datatype Must be MPI_INT
* [in] op One of: MPI_BAND, MPI_MAX
* [in] comm_ptr Parent communicator
* [in] group_ptr Group of processes that will participate in the allreduce
* (must be a subgroup of comm_ptr's group)
* [in] tag Tag to be used for allreduce messages
* [out] errflag Error flag
*/
int MPIR_Allreduce_group(void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr,
MPID_Group *group_ptr, int tag, int *errflag)
{
MPI_Status status;
int i, bin_root, bin_parent, bin_lchild, bin_rchild;
int *buf_left, *buf_right, *in_buf, *out_buf;
MPIU_Assert(datatype == MPI_INT);
buf_left = (int*) MPIU_Malloc(sizeof(int)*count);
buf_right = (int*) MPIU_Malloc(sizeof(int)*count);
out_buf = (int*) recvbuf;
in_buf = (int*) ((sendbuf == MPI_IN_PLACE) ? recvbuf : sendbuf);
/* Map a binary spanning tree on members of group in comm. Resulting
* ranks will be MPI_PROC_NULL if, e.g., a left child does not exist, so
* it's fine to unconditionally send/recv since these will be no-ops. */
MPIR_Allreduce_group_bintree(comm_ptr, group_ptr, &bin_root, &bin_parent, &bin_lchild, &bin_rchild);
/** REDUCE **/
/* Receive from left child */
MPIC_Recv(buf_left, count, datatype, bin_lchild, tag, comm_ptr->handle, &status);
/* Receive from right child */
MPIC_Recv(buf_right, count, datatype, bin_rchild, tag, comm_ptr->handle, &status);
/* Initialize local reduction output to input values */
if (sendbuf != MPI_IN_PLACE)
for (i = 0; i < count; i++)
out_buf[i] = in_buf[i];
/* Perform local reduction on left-, and right-child values if they exist */
if (op == MPI_BAND) {
if (bin_lchild != MPI_PROC_NULL) {
for (i = 0; i < count; i++)
out_buf[i] = out_buf[i] & buf_left[i];
}
if (bin_rchild != MPI_PROC_NULL) {
for (i = 0; i < count; i++)
out_buf[i] = out_buf[i] & buf_right[i];
}
}
else if (op == MPI_MAX) {
if (bin_lchild != MPI_PROC_NULL) {
for (i = 0; i < count; i++)
out_buf[i] = (out_buf[i] > buf_left[i]) ? out_buf[i] : buf_left[i];
}
if (bin_rchild != MPI_PROC_NULL) {
for (i = 0; i < count; i++)
out_buf[i] = (out_buf[i] > buf_right[i]) ? out_buf[i] : buf_right[i];
}
}
else {
MPIU_Assert(FALSE);
}
/* Send to parent */
MPIC_Send(recvbuf, count, datatype, bin_parent, tag, comm_ptr->handle);
/** BROADCAST **/
/* Receive from parent */
MPIC_Recv(recvbuf, count, datatype, bin_parent, tag, comm_ptr->handle, &status);
/* Send to left child */
MPIC_Send(recvbuf, count, datatype, bin_lchild, tag, comm_ptr->handle);
/* Send to right child */
MPIC_Send(recvbuf, count, datatype, bin_rchild, tag, comm_ptr->handle);
MPIU_Free(buf_left);
MPIU_Free(buf_right);
return MPI_SUCCESS;
}
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
*
* (C) 2001 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
#include "mpiimpl.h"
/* This is the group-collective implementation of the barrier operation. It
currently is built on group allreduce.
This is an intracommunicator barrier only!
*/
int MPIR_Barrier_group( MPID_Comm *comm_ptr, MPID_Group *group_ptr, int tag, int *errflag )
{
int src, dst, mpi_errno = MPI_SUCCESS;
/* Trivial barriers return immediately */
if (comm_ptr->local_size == 1) goto fn_exit;
mpi_errno = MPIR_Allreduce_group(&src, &dst, 1, MPI_INT, MPI_BAND,
comm_ptr, group_ptr, tag, errflag);
if (mpi_errno != MPI_SUCCESS)
*errflag = TRUE;
fn_exit:
return mpi_errno;
fn_fail:
goto fn_exit;
}
......@@ -20,17 +20,6 @@
/* prototypes to make the compiler happy in the case that PMPI_LOCAL expands to
* nothing instead of "static" */
PMPI_LOCAL int MPIR_Comm_create_calculate_mapping(MPID_Group *group_ptr,
MPID_Comm *comm_ptr,
MPID_VCR **mapping_vcr_out,
int **mapping_out);
PMPI_LOCAL int MPIR_Comm_create_create_and_map_vcrt(int n,
int *mapping,
MPID_VCR *mapping_vcr,
MPID_VCRT *out_vcrt,
MPID_VCR **out_vcr);
PMPI_LOCAL int MPIR_Comm_create_intra(MPID_Comm *comm_ptr, MPID_Group *group_ptr,
MPID_Comm **newcomm_ptr);
PMPI_LOCAL int MPIR_Comm_create_inter(MPID_Comm *comm_ptr, MPID_Group *group_ptr,
......@@ -53,10 +42,10 @@ PMPI_LOCAL int MPIR_Comm_create_inter(MPID_Comm *comm_ptr, MPID_Group *group_ptr
#define FUNCNAME MPIR_Comm_create_calculate_mapping
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
PMPI_LOCAL int MPIR_Comm_create_calculate_mapping(MPID_Group *group_ptr,
MPID_Comm *comm_ptr,
MPID_VCR **mapping_vcr_out,
int **mapping_out)
int MPIR_Comm_create_calculate_mapping(MPID_Group *group_ptr,
MPID_Comm *comm_ptr,
MPID_VCR **mapping_vcr_out,
int **mapping_out)
{
int mpi_errno = MPI_SUCCESS;
int subsetOfWorld = 0;
......@@ -192,11 +181,11 @@ fn_fail:
#define FUNCNAME MPIR_Comm_create_and_map_vcrt
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
PMPI_LOCAL int MPIR_Comm_create_create_and_map_vcrt(int n,
int *mapping,
MPID_VCR *mapping_vcr,
MPID_VCRT *out_vcrt,
MPID_VCR **out_vcr)
int MPIR_Comm_create_create_and_map_vcrt(int n,
int *mapping,
MPID_VCR *mapping_vcr,
MPID_VCRT *out_vcrt,
MPID_VCR **out_vcr)
{
int mpi_errno = MPI_SUCCESS;
int i;
......@@ -538,46 +527,40 @@ int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm)
MPIU_THREAD_CS_ENTER(ALLFUNC,);
MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_COMM_CREATE);
/* Validate parameters, and convert MPI object handles to object pointers */
/* Validate parameters, especially handles needing to be converted */
# ifdef HAVE_ERROR_CHECKING
{
MPID_BEGIN_ERROR_CHECKS;
MPID_BEGIN_ERROR_CHECKS
{
MPIR_ERRTEST_COMM(comm, mpi_errno);
MPIR_ERRTEST_COMM(comm, mpi_errno);
MPIR_ERRTEST_GROUP(group, mpi_errno);
if (mpi_errno) goto fn_fail;
}
MPID_END_ERROR_CHECKS;
MPID_Comm_get_ptr( comm, comm_ptr );
MPID_BEGIN_ERROR_CHECKS;
{
/* Validate comm_ptr */
MPID_Comm_valid_ptr( comm_ptr, mpi_errno );
/* If comm_ptr is not valid, it will be reset to null */
}
MPID_END_ERROR_CHECKS
}
# endif
MPIR_ERRTEST_GROUP(group, mpi_errno);
if (mpi_errno) goto fn_fail;
}
MPID_END_ERROR_CHECKS;
MPID_Group_get_ptr( group, group_ptr );
/* Get handles to MPI objects. */
MPID_Comm_get_ptr(comm, comm_ptr);
MPID_Group_get_ptr(group, group_ptr);
MPID_BEGIN_ERROR_CHECKS;
/* Validate parameters and objects (post conversion) */
# ifdef HAVE_ERROR_CHECKING
{
MPID_BEGIN_ERROR_CHECKS
{
/* Check the group ptr */
MPID_Group_valid_ptr( group_ptr, mpi_errno );
/* If comm_ptr is not valid, it will be reset to null */
MPID_Comm_valid_ptr(comm_ptr, mpi_errno);
if (mpi_errno) goto fn_fail;
MPID_Group_valid_ptr(group_ptr, mpi_errno);
if (mpi_errno) goto fn_fail;
}
MPID_END_ERROR_CHECKS;
}
# else
{
MPID_Comm_get_ptr( comm, comm_ptr );
MPID_Group_get_ptr( group, group_ptr );
MPID_END_ERROR_CHECKS
}
# endif
/* ... body of routine ... */
if (comm_ptr->comm_kind == MPID_INTRACOMM) {
mpi_errno = MPIR_Comm_create_intra(comm_ptr, group_ptr, &newcomm_ptr);
......
......@@ -18,6 +18,8 @@
#endif
/* -- End Profiling Symbol Block */
/* PMPI_LOCAL should be dropped and this prototype moved to mpiimpl.h if we ever
* need to use this routine outside of this translation unit */
PMPI_LOCAL int MPIR_Comm_create_group(MPID_Comm * comm_ptr, MPID_Group * group_ptr, int tag,
MPID_Comm ** newcomm);
......@@ -37,134 +39,85 @@ PMPI_LOCAL int MPIR_Comm_create_group(MPID_Comm * comm_ptr, MPID_Group * group_p
PMPI_LOCAL int MPIR_Comm_create_group(MPID_Comm * comm_ptr, MPID_Group * group_ptr, int tag,
MPID_Comm ** newcomm_ptr)
{
int i, grp_me, me, merge_size;
MPID_Comm *tmp_comm_ptr, *tmp_intercomm_ptr, *comm_self_ptr;
MPID_Group *comm_group_ptr = NULL;
int *granks = NULL, *ranks = NULL, rank_count;
int mpi_errno = MPI_SUCCESS;
MPIU_CHKLMEM_DECL(2);
MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE_GROUP);
MPIR_Context_id_t new_context_id = 0;
int *mapping = NULL;
int n;
MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE_GROUP);
MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_CREATE_GROUP);
ranks = NULL;
MPIU_Assert(comm_ptr->comm_kind == MPID_INTRACOMM);
/* Create a group for all of comm and translate it to "group",
* which should be a subset of comm's group. If implemented inside
* MPI, the below translation can be done more efficiently, since
* we have access to the internal lpids directly. */
mpi_errno = MPIR_Comm_group_impl(comm_ptr, &comm_group_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
n = group_ptr->size;
*newcomm_ptr = NULL;
rank_count = group_ptr->size;
/* Create a new communicator from the specified group members */
MPIU_CHKLMEM_MALLOC(granks, int *, rank_count * sizeof(int), mpi_errno, "granks");
MPIU_CHKLMEM_MALLOC(ranks, int *, rank_count * sizeof(int), mpi_errno, "ranks");
if (group_ptr->rank != MPI_UNDEFINED) {
MPID_VCR *mapping_vcr = NULL;
for (i = 0; i < rank_count; i++)
granks[i] = i;
/* For this routine, creation of the id is collective over the input
*group*, so processes not in the group do not participate. */
mpi_errno =
MPIR_Group_translate_ranks_impl(group_ptr, rank_count, granks, comm_group_ptr, ranks);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
mpi_errno = MPIR_Get_contextid_sparse_group( comm_ptr, group_ptr, tag, &new_context_id, 0 );
if (mpi_errno) MPIU_ERR_POP(mpi_errno);
MPIU_Assert(new_context_id != 0);
me = MPIR_Comm_rank(comm_ptr);
mpi_errno = MPIR_Comm_create_calculate_mapping(group_ptr, comm_ptr,
&mapping_vcr, &mapping);
if (mpi_errno) MPIU_ERR_POP(mpi_errno);
/* If the group size is 0, return MPI_COMM_NULL */
if (rank_count == 0) {
*newcomm_ptr = NULL;
goto fn_exit;
}
/* Get the new communicator structure and context id */
MPID_Comm_get_ptr(MPI_COMM_SELF, comm_self_ptr);
mpi_errno = MPIR_Comm_create( newcomm_ptr );
if (mpi_errno) MPIU_ERR_POP(mpi_errno);
/* If I am the only process in the group, return a dup of
* MPI_COMM_SELF */
if (rank_count == 1 && ranks[0] == me) {
mpi_errno = MPIR_Comm_dup_impl(comm_self_ptr, newcomm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
(*newcomm_ptr)->recvcontext_id = new_context_id;
(*newcomm_ptr)->rank = group_ptr->rank;
(*newcomm_ptr)->comm_kind = comm_ptr->comm_kind;
/* Since the group has been provided, let the new communicator know
about the group */
(*newcomm_ptr)->local_comm = 0;
(*newcomm_ptr)->local_group = group_ptr;
MPIR_Group_add_ref( group_ptr );
goto fn_exit;
}
(*newcomm_ptr)->remote_group = group_ptr;
MPIR_Group_add_ref( group_ptr );
(*newcomm_ptr)->context_id = (*newcomm_ptr)->recvcontext_id;
(*newcomm_ptr)->remote_size = (*newcomm_ptr)->local_size = n;
/* If I am not a part of the group, return MPI_COMM_NULL */
grp_me = -1;
for (i = 0; i < rank_count; i++) {
if (ranks[i] == me) {
grp_me = i;
break;
}
}
if (grp_me < 0) {
*newcomm_ptr = NULL;
goto fn_exit;
}
/* Setup the communicator's vc table. This is for the remote group,
which is the same as the local group for intracommunicators */
mpi_errno = MPIR_Comm_create_create_and_map_vcrt(n,
mapping,
mapping_vcr,
&((*newcomm_ptr)->vcrt),
&((*newcomm_ptr)->vcr));
if (mpi_errno) MPIU_ERR_POP(mpi_errno);
mpi_errno = MPIR_Comm_dup_impl(comm_self_ptr, &tmp_comm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
for (merge_size = 1; merge_size < rank_count; merge_size *= 2) {
int gid = grp_me / merge_size;
MPID_Comm *save_comm = tmp_comm_ptr;
if (gid % 2 == 0) {
/* Check if right partner doesn't exist */
if ((gid + 1) * merge_size >= rank_count)
continue;
mpi_errno = MPIR_Intercomm_create_impl(tmp_comm_ptr, 0, comm_ptr,
ranks[(gid + 1) * merge_size], tag,
&tmp_intercomm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
mpi_errno =
MPIR_Intercomm_merge_impl(tmp_intercomm_ptr, 0 /* LOW */ , &tmp_comm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
}
else {
mpi_errno = MPIR_Intercomm_create_impl(tmp_comm_ptr, 0, comm_ptr,
ranks[(gid - 1) * merge_size], tag,
&tmp_intercomm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
mpi_errno =
MPIR_Intercomm_merge_impl(tmp_intercomm_ptr, 1 /* HIGH */ , &tmp_comm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
}
mpi_errno = MPIR_Comm_free_impl(tmp_intercomm_ptr);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
if (save_comm->handle != MPI_COMM_SELF) {
mpi_errno = MPIR_Comm_free_impl(save_comm);
if (mpi_errno)
MPIU_ERR_POP(mpi_errno);
}
mpi_errno = MPIR_Comm_commit(*newcomm_ptr);
if (mpi_errno) MPIU_ERR_POP(mpi_errno);
}
else {
/* This process is not in the group */
new_context_id = 0;
}
*newcomm_ptr = tmp_comm_ptr;
fn_exit:
if (mapping)
MPIU_Free(mapping);
fn_exit:
if (comm_group_ptr != NULL) {
if (mpi_errno) /* avoid squashing a more interesting error code */
MPIR_Group_free_impl(comm_group_ptr);
else
mpi_errno = MPIR_Group_free_impl(comm_group_ptr);
}
MPIU_CHKLMEM_FREEALL();
MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_CREATE_GROUP);
return mpi_errno;
fn_fail:
if (*newcomm_ptr != NULL) {
MPIR_Comm_release(*newcomm_ptr, 0/*isDisconnect*/);
new_context_id = 0; /* MPIR_Comm_release frees the new ctx id */
}
if (new_context_id != 0)
MPIR_Free_contextid(new_context_id);
fn_fail:
goto fn_exit;
}
......@@ -209,54 +162,45 @@ int MPIX_Comm_create_group(MPI_Comm comm, MPI_Group group, int tag, MPI_Comm * n
MPIU_THREAD_CS_ENTER(ALLFUNC,);
MPID_MPI_FUNC_ENTER(MPID_STATE_MPIX_COMM_CREATE_GROUP);
/* Validate parameters, and convert MPI object handles to object pointers */
#ifdef HAVE_ERROR_CHECKING
/* Validate parameters, especially handles needing to be converted */
# ifdef HAVE_ERROR_CHECKING
{
MPID_BEGIN_ERROR_CHECKS;
MPID_BEGIN_ERROR_CHECKS
{
MPIR_ERRTEST_COMM_TAG(tag, mpi_errno);
MPIR_ERRTEST_COMM(comm, mpi_errno);
if (mpi_errno)
goto fn_fail;
MPIR_ERRTEST_GROUP(group, mpi_errno);
if (mpi_errno) goto fn_fail;
}
MPID_END_ERROR_CHECKS;
MPID_END_ERROR_CHECKS
}
# endif
MPID_Comm_get_ptr(comm, comm_ptr);
/* Get handles to MPI objects. */
MPID_Comm_get_ptr(comm, comm_ptr);
MPID_Group_get_ptr(group, group_ptr);
MPID_BEGIN_ERROR_CHECKS;
/* Validate parameters and objects (post conversion) */
# ifdef HAVE_ERROR_CHECKING
{
MPID_BEGIN_ERROR_CHECKS
{
/* Validate comm_ptr */
MPID_Comm_valid_ptr(comm_ptr, mpi_errno);
/* If comm_ptr is not valid, it will be reset to null */
MPID_Comm_valid_ptr(comm_ptr, mpi_errno);
if (mpi_errno) goto fn_fail;
MPIR_ERRTEST_COMM_INTRA(comm_ptr, mpi_errno);
if (mpi_errno) goto fn_fail;