int MPIR_Comm_copy_data(MPID_Comm * comm_ptr, MPID_Comm ** outcomm_ptr) { int mpi_errno = MPI_SUCCESS; MPID_Comm *newcomm_ptr = NULL; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_COPY_DATA); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_COPY_DATA); mpi_errno = MPIR_Comm_create(&newcomm_ptr); if (mpi_errno) goto fn_fail; /* use a large garbage value to ensure errors are caught more easily */ newcomm_ptr->context_id = 32767; newcomm_ptr->recvcontext_id = 32767; /* Save the kind of the communicator */ newcomm_ptr->comm_kind = comm_ptr->comm_kind; newcomm_ptr->local_comm = 0; if (comm_ptr->comm_kind == MPID_INTRACOMM) MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR_L2L); else MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR_R2R); /* If it is an intercomm, duplicate the network address mapping */ if (comm_ptr->comm_kind == MPID_INTERCOMM) { MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR_L2L); } /* Set the sizes and ranks */ newcomm_ptr->rank = comm_ptr->rank; newcomm_ptr->local_size = comm_ptr->local_size; newcomm_ptr->remote_size = comm_ptr->remote_size; newcomm_ptr->is_low_group = comm_ptr->is_low_group; /* only relevant for intercomms */ /* Inherit the error handler (if any) */ MPID_THREAD_CS_ENTER(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr)); newcomm_ptr->errhandler = comm_ptr->errhandler; if (comm_ptr->errhandler) { MPIR_Errhandler_add_ref(comm_ptr->errhandler); } MPID_THREAD_CS_EXIT(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr)); /* FIXME do we want to copy coll_fns here? */ /* Start with no attributes on this communicator */ newcomm_ptr->attributes = 0; *outcomm_ptr = newcomm_ptr; fn_fail: fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_COPY_DATA); return mpi_errno; }
int MPID_Comm_spawn_multiple(int count, char *commands[], char **argvs[], const int maxprocs[], MPIR_Info * info_ptrs[], int root, MPIR_Comm * comm_ptr, MPIR_Comm ** intercomm, int errcodes[]) { char port_name[MPI_MAX_PORT_NAME]; int *info_keyval_sizes = 0, i, mpi_errno = MPI_SUCCESS; PMI_keyval_t **info_keyval_vectors = 0, preput_keyval_vector; int *pmi_errcodes = 0, pmi_errno = 0; int total_num_processes, should_accept = 1; MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_COMM_SPAWN_MULTIPLE); MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_COMM_SPAWN_MULTIPLE); memset(port_name, 0, sizeof(port_name)); if (comm_ptr->rank == root) { total_num_processes = 0; for (i = 0; i < count; i++) total_num_processes += maxprocs[i]; pmi_errcodes = (int *) MPL_malloc(sizeof(int) * total_num_processes, MPL_MEM_BUFFER); MPIR_ERR_CHKANDJUMP(!pmi_errcodes, mpi_errno, MPI_ERR_OTHER, "**nomem"); for (i = 0; i < total_num_processes; i++) pmi_errcodes[i] = 0; mpi_errno = MPID_Open_port(NULL, port_name); if (mpi_errno) MPIR_ERR_POP(mpi_errno); info_keyval_sizes = (int *) MPL_malloc(count * sizeof(int), MPL_MEM_BUFFER); MPIR_ERR_CHKANDJUMP(!info_keyval_sizes, mpi_errno, MPI_ERR_OTHER, "**nomem"); info_keyval_vectors = (PMI_keyval_t **) MPL_malloc(count * sizeof(PMI_keyval_t *), MPL_MEM_BUFFER); MPIR_ERR_CHKANDJUMP(!info_keyval_vectors, mpi_errno, MPI_ERR_OTHER, "**nomem"); if (!info_ptrs) for (i = 0; i < count; i++) { info_keyval_vectors[i] = 0; info_keyval_sizes[i] = 0; } else for (i = 0; i < count; i++) { mpi_errno = mpi_to_pmi_keyvals(info_ptrs[i], &info_keyval_vectors[i], &info_keyval_sizes[i]); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } preput_keyval_vector.key = MPIDI_PARENT_PORT_KVSKEY; preput_keyval_vector.val = port_name; pmi_errno = PMI_Spawn_multiple(count, (const char **) commands, (const char ***) argvs, maxprocs, info_keyval_sizes, (const PMI_keyval_t **) info_keyval_vectors, 1, &preput_keyval_vector, pmi_errcodes); if (pmi_errno != PMI_SUCCESS) MPIR_ERR_SETANDJUMP1(mpi_errno, MPI_ERR_OTHER, "**pmi_spawn_multiple", "**pmi_spawn_multiple %d", pmi_errno); if (errcodes != MPI_ERRCODES_IGNORE) { for (i = 0; i < total_num_processes; i++) { errcodes[i] = pmi_errcodes[0]; should_accept = should_accept && errcodes[i]; } should_accept = !should_accept; } } if (errcodes != MPI_ERRCODES_IGNORE) { MPIR_Errflag_t errflag = MPIR_ERR_NONE; mpi_errno = MPIR_Bcast(&should_accept, 1, MPI_INT, root, comm_ptr, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Bcast(&pmi_errno, 1, MPI_INT, root, comm_ptr, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Bcast(&total_num_processes, 1, MPI_INT, root, comm_ptr, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Bcast(errcodes, total_num_processes, MPI_INT, root, comm_ptr, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } if (should_accept) { mpi_errno = MPID_Comm_accept(port_name, NULL, root, comm_ptr, intercomm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } else { if ((pmi_errno == PMI_SUCCESS) && (errcodes[0] != 0)) { mpi_errno = MPIR_Comm_create(intercomm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } } if (comm_ptr->rank == root) { mpi_errno = MPID_Close_port(port_name); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } fn_exit: if (info_keyval_vectors) { free_pmi_keyvals(info_keyval_vectors, count, info_keyval_sizes); MPL_free(info_keyval_vectors); } MPL_free(info_keyval_sizes); MPL_free(pmi_errcodes); MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_COMM_SPAWN_MULTIPLE); return mpi_errno; fn_fail: goto fn_exit; }
static int MPIDI_CH3I_Initialize_tmp_comm(MPID_Comm **comm_pptr, MPIDI_VC_t *vc_ptr, int is_low_group, int context_id_offset) { int mpi_errno = MPI_SUCCESS; MPID_Comm *tmp_comm, *commself_ptr; MPIDI_STATE_DECL(MPID_STATE_MPIDI_CH3I_INITIALIZE_TMP_COMM); MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_CH3I_INITIALIZE_TMP_COMM); MPID_Comm_get_ptr( MPI_COMM_SELF, commself_ptr ); /* WDG-old code allocated a context id that was then discarded */ mpi_errno = MPIR_Comm_create(&tmp_comm); if (mpi_errno != MPI_SUCCESS) { MPIU_ERR_POP(mpi_errno); } /* fill in all the fields of tmp_comm. */ /* We use the second half of the context ID bits for dynamic * processes. This assumes that the context ID mask array is made * up of uint32_t's. */ /* FIXME: This code is still broken for the following case: * If the same process opens connections to the multiple * processes, this context ID might get out of sync. */ tmp_comm->context_id = MPID_CONTEXT_SET_FIELD(DYNAMIC_PROC, context_id_offset, 1); tmp_comm->recvcontext_id = tmp_comm->context_id; /* sanity: the INVALID context ID value could potentially conflict with the * dynamic proccess space */ MPIU_Assert(tmp_comm->context_id != MPIR_INVALID_CONTEXT_ID); MPIU_Assert(tmp_comm->recvcontext_id != MPIR_INVALID_CONTEXT_ID); /* FIXME - we probably need a unique context_id. */ tmp_comm->remote_size = 1; /* Fill in new intercomm */ tmp_comm->local_size = 1; tmp_comm->rank = 0; tmp_comm->comm_kind = MPID_INTERCOMM; tmp_comm->local_comm = NULL; tmp_comm->is_low_group = is_low_group; /* No pg structure needed since vc has already been set up (connection has been established). */ /* Point local vcr, vcrt at those of commself_ptr */ /* FIXME: Explain why */ tmp_comm->local_vcrt = commself_ptr->vcrt; MPID_VCRT_Add_ref(commself_ptr->vcrt); tmp_comm->local_vcr = commself_ptr->vcr; /* No pg needed since connection has already been formed. FIXME - ensure that the comm_release code does not try to free an unallocated pg */ /* Set up VC reference table */ mpi_errno = MPID_VCRT_Create(tmp_comm->remote_size, &tmp_comm->vcrt); if (mpi_errno != MPI_SUCCESS) { MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER, "**init_vcrt"); } mpi_errno = MPID_VCRT_Get_ptr(tmp_comm->vcrt, &tmp_comm->vcr); if (mpi_errno != MPI_SUCCESS) { MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER, "**init_getptr"); } /* FIXME: Why do we do a dup here? */ MPID_VCR_Dup(vc_ptr, tmp_comm->vcr); /* Even though this is a tmp comm and we don't call MPI_Comm_commit, we still need to call the creation hook because the destruction hook will be called in comm_release */ mpi_errno = MPID_Dev_comm_create_hook(tmp_comm); if (mpi_errno) MPIU_ERR_POP(mpi_errno); *comm_pptr = tmp_comm; fn_exit: MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_CH3I_INITIALIZE_TMP_COMM); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Comm_commit(MPID_Comm * comm) { int mpi_errno = MPI_SUCCESS; int num_local = -1, num_external = -1; int local_rank = -1, external_rank = -1; int *local_procs = NULL, *external_procs = NULL; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_COMMIT); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_COMMIT); /* It's OK to relax these assertions, but we should do so very * intentionally. For now this function is the only place that we create * our hierarchy of communicators */ MPIU_Assert(comm->node_comm == NULL); MPIU_Assert(comm->node_roots_comm == NULL); mpi_errno = set_collops(comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Notify device of communicator creation */ mpi_errno = MPID_Dev_comm_create_hook(comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_Comm_map_free(comm); if (comm->comm_kind == MPID_INTRACOMM) { mpi_errno = MPIU_Find_local_and_external(comm, &num_local, &local_rank, &local_procs, &num_external, &external_rank, &external_procs, &comm->intranode_table, &comm->internode_table); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno) { if (MPIR_Err_is_fatal(mpi_errno)) MPIR_ERR_POP(mpi_errno); /* Non-fatal errors simply mean that this communicator will not have * any node awareness. Node-aware collectives are an optimization. */ MPIU_DBG_MSG_P(COMM, VERBOSE, "MPIU_Find_local_and_external failed for comm_ptr=%p", comm); if (comm->intranode_table) MPIU_Free(comm->intranode_table); if (comm->internode_table) MPIU_Free(comm->internode_table); mpi_errno = MPI_SUCCESS; goto fn_exit; } /* --END ERROR HANDLING-- */ /* defensive checks */ MPIU_Assert(num_local > 0); MPIU_Assert(num_local > 1 || external_rank >= 0); MPIU_Assert(external_rank < 0 || external_procs != NULL); /* if the node_roots_comm and comm would be the same size, then creating * the second communicator is useless and wasteful. */ if (num_external == comm->remote_size) { MPIU_Assert(num_local == 1); goto fn_exit; } /* we don't need a local comm if this process is the only one on this node */ if (num_local > 1) { mpi_errno = MPIR_Comm_create(&comm->node_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); comm->node_comm->context_id = comm->context_id + MPID_CONTEXT_INTRANODE_OFFSET; comm->node_comm->recvcontext_id = comm->node_comm->context_id; comm->node_comm->rank = local_rank; comm->node_comm->comm_kind = MPID_INTRACOMM; comm->node_comm->hierarchy_kind = MPID_HIERARCHY_NODE; comm->node_comm->local_comm = NULL; MPIU_DBG_MSG_D(CH3_OTHER, VERBOSE, "Create node_comm=%p\n", comm->node_comm); comm->node_comm->local_size = num_local; comm->node_comm->remote_size = num_local; MPIR_Comm_map_irregular(comm->node_comm, comm, local_procs, num_local, MPIR_COMM_MAP_DIR_L2L, NULL); mpi_errno = set_collops(comm->node_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Notify device of communicator creation */ mpi_errno = MPID_Dev_comm_create_hook(comm->node_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* don't call MPIR_Comm_commit here */ MPIR_Comm_map_free(comm->node_comm); } /* this process may not be a member of the node_roots_comm */ if (local_rank == 0) { mpi_errno = MPIR_Comm_create(&comm->node_roots_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); comm->node_roots_comm->context_id = comm->context_id + MPID_CONTEXT_INTERNODE_OFFSET; comm->node_roots_comm->recvcontext_id = comm->node_roots_comm->context_id; comm->node_roots_comm->rank = external_rank; comm->node_roots_comm->comm_kind = MPID_INTRACOMM; comm->node_roots_comm->hierarchy_kind = MPID_HIERARCHY_NODE_ROOTS; comm->node_roots_comm->local_comm = NULL; comm->node_roots_comm->local_size = num_external; comm->node_roots_comm->remote_size = num_external; MPIR_Comm_map_irregular(comm->node_roots_comm, comm, external_procs, num_external, MPIR_COMM_MAP_DIR_L2L, NULL); mpi_errno = set_collops(comm->node_roots_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Notify device of communicator creation */ mpi_errno = MPID_Dev_comm_create_hook(comm->node_roots_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* don't call MPIR_Comm_commit here */ MPIR_Comm_map_free(comm->node_roots_comm); } comm->hierarchy_kind = MPID_HIERARCHY_PARENT; } fn_exit: if (external_procs != NULL) MPIU_Free(external_procs); if (local_procs != NULL) MPIU_Free(local_procs); MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_COMMIT); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Comm_copy(MPID_Comm * comm_ptr, int size, MPID_Comm ** outcomm_ptr) { int mpi_errno = MPI_SUCCESS; MPIU_Context_id_t new_context_id, new_recvcontext_id; MPID_Comm *newcomm_ptr = NULL; MPIR_Comm_map_t *map; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_COPY); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_COPY); /* Get a new context first. We need this to be collective over the * input communicator */ /* If there is a context id cache in oldcomm, use it here. Otherwise, * use the appropriate algorithm to get a new context id. Be careful * of intercomms here */ if (comm_ptr->comm_kind == MPID_INTERCOMM) { mpi_errno = MPIR_Get_intercomm_contextid(comm_ptr, &new_context_id, &new_recvcontext_id); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } else { mpi_errno = MPIR_Get_contextid_sparse(comm_ptr, &new_context_id, FALSE); new_recvcontext_id = new_context_id; if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIU_Assert(new_context_id != 0); } /* This is the local size, not the remote size, in the case of * an intercomm */ if (comm_ptr->rank >= size) { *outcomm_ptr = 0; /* always free the recvcontext ID, never the "send" ID */ MPIR_Free_contextid(new_recvcontext_id); goto fn_exit; } /* We're left with the processes that will have a non-null communicator. * Create the object, initialize the data, and return the result */ mpi_errno = MPIR_Comm_create(&newcomm_ptr); if (mpi_errno) goto fn_fail; newcomm_ptr->context_id = new_context_id; newcomm_ptr->recvcontext_id = new_recvcontext_id; /* Save the kind of the communicator */ newcomm_ptr->comm_kind = comm_ptr->comm_kind; newcomm_ptr->local_comm = 0; /* There are two cases here - size is the same as the old communicator, * or it is smaller. If the size is the same, we can just add a reference. * Otherwise, we need to create a new network address mapping. Note that this is the * test that matches the test on rank above. */ if (size == comm_ptr->local_size) { /* Duplicate the network address mapping */ if (comm_ptr->comm_kind == MPID_INTRACOMM) MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR_L2L); else MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR_R2R); } else { int i; if (comm_ptr->comm_kind == MPID_INTRACOMM) MPIR_Comm_map_irregular(newcomm_ptr, comm_ptr, NULL, size, MPIR_COMM_MAP_DIR_L2L, &map); else MPIR_Comm_map_irregular(newcomm_ptr, comm_ptr, NULL, size, MPIR_COMM_MAP_DIR_R2R, &map); for (i = 0; i < size; i++) { /* For rank i in the new communicator, find the corresponding * rank in the input communicator */ map->src_mapping[i] = i; } } /* If it is an intercomm, duplicate the local network address references */ if (comm_ptr->comm_kind == MPID_INTERCOMM) { MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR_L2L); } /* Set the sizes and ranks */ newcomm_ptr->rank = comm_ptr->rank; if (comm_ptr->comm_kind == MPID_INTERCOMM) { newcomm_ptr->local_size = comm_ptr->local_size; newcomm_ptr->remote_size = comm_ptr->remote_size; newcomm_ptr->is_low_group = comm_ptr->is_low_group; } else { newcomm_ptr->local_size = size; newcomm_ptr->remote_size = size; } /* Inherit the error handler (if any) */ MPID_THREAD_CS_ENTER(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr)); newcomm_ptr->errhandler = comm_ptr->errhandler; if (comm_ptr->errhandler) { MPIR_Errhandler_add_ref(comm_ptr->errhandler); } MPID_THREAD_CS_EXIT(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr)); /* FIXME do we want to copy coll_fns here? */ mpi_errno = MPIR_Comm_commit(newcomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Start with no attributes on this communicator */ newcomm_ptr->attributes = 0; /* Copy over the info hints from the original communicator. */ mpi_errno = MPIR_Info_dup_impl(comm_ptr->info, &(newcomm_ptr->info)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_apply_hints(newcomm_ptr, newcomm_ptr->info); if (mpi_errno) MPIR_ERR_POP(mpi_errno); *outcomm_ptr = newcomm_ptr; fn_fail: fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_COPY); return mpi_errno; }
/* comm create impl for intercommunicators, assumes that the standard error * checking has already taken place in the calling function */ PMPI_LOCAL int MPIR_Comm_create_inter(MPIR_Comm *comm_ptr, MPIR_Group *group_ptr, MPIR_Comm **newcomm_ptr) { int mpi_errno = MPI_SUCCESS; MPIR_Context_id_t new_context_id; int *mapping = NULL; int *remote_mapping = NULL; MPIR_Comm *mapping_comm = NULL; int remote_size = -1; int rinfo[2]; MPIR_Errflag_t errflag = MPIR_ERR_NONE; MPIR_CHKLMEM_DECL(1); MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE_INTER); MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_CREATE_INTER); MPIR_Assert(comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM); /* Create a new communicator from the specified group members */ /* If there is a context id cache in oldcomm, use it here. Otherwise, use the appropriate algorithm to get a new context id. Creating the context id is collective over the *input* communicator, so it must be created before we decide if this process is a member of the group */ /* In the multi-threaded case, MPIR_Get_contextid_sparse assumes that the calling routine already holds the single criticial section */ if (!comm_ptr->local_comm) { MPII_Setup_intercomm_localcomm( comm_ptr ); } mpi_errno = MPIR_Get_contextid_sparse( comm_ptr->local_comm, &new_context_id, FALSE ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_Assert(new_context_id != 0); MPIR_Assert(new_context_id != comm_ptr->recvcontext_id); mpi_errno = MPII_Comm_create_calculate_mapping(group_ptr, comm_ptr, &mapping, &mapping_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); *newcomm_ptr = NULL; if (group_ptr->rank != MPI_UNDEFINED) { /* Get the new communicator structure and context id */ mpi_errno = MPIR_Comm_create( newcomm_ptr ); if (mpi_errno) goto fn_fail; (*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 ); (*newcomm_ptr)->local_size = group_ptr->size; (*newcomm_ptr)->pof2 = MPL_pof2((*newcomm_ptr)->local_size); (*newcomm_ptr)->remote_group = 0; (*newcomm_ptr)->is_low_group = comm_ptr->is_low_group; } /* There is an additional step. We must communicate the information on the local context id and the group members, given by the ranks so that the remote process can construct the appropriate network address mapping. First we exchange group sizes and context ids. Then the ranks in the remote group, from which the remote network address mapping can be constructed. We need to use the "collective" context in the original intercommunicator */ if (comm_ptr->rank == 0) { int info[2]; info[0] = new_context_id; info[1] = group_ptr->size; mpi_errno = MPIC_Sendrecv(info, 2, MPI_INT, 0, 0, rinfo, 2, MPI_INT, 0, 0, comm_ptr, MPI_STATUS_IGNORE, &errflag ); if (mpi_errno) { MPIR_ERR_POP( mpi_errno ); } if (*newcomm_ptr != NULL) { (*newcomm_ptr)->context_id = rinfo[0]; } remote_size = rinfo[1]; MPIR_CHKLMEM_MALLOC(remote_mapping,int*, remote_size*sizeof(int), mpi_errno,"remote_mapping",MPL_MEM_ADDRESS); /* Populate and exchange the ranks */ mpi_errno = MPIC_Sendrecv( mapping, group_ptr->size, MPI_INT, 0, 0, remote_mapping, remote_size, MPI_INT, 0, 0, comm_ptr, MPI_STATUS_IGNORE, &errflag ); if (mpi_errno) { MPIR_ERR_POP( mpi_errno ); } /* Broadcast to the other members of the local group */ mpi_errno = MPID_Bcast( rinfo, 2, MPI_INT, 0, comm_ptr->local_comm, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPID_Bcast( remote_mapping, remote_size, MPI_INT, 0, comm_ptr->local_comm, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail"); }
int MPIR_Intercomm_merge_impl(MPID_Comm *comm_ptr, int high, MPID_Comm **new_intracomm_ptr) { int mpi_errno = MPI_SUCCESS; int local_high, remote_high, new_size; MPIU_Context_id_t new_context_id; MPIR_Errflag_t errflag = MPIR_ERR_NONE; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_INTERCOMM_MERGE_IMPL); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_INTERCOMM_MERGE_IMPL); /* Make sure that we have a local intercommunicator */ if (!comm_ptr->local_comm) { /* Manufacture the local communicator */ mpi_errno = MPIR_Setup_intercomm_localcomm( comm_ptr ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } /* Find the "high" value of the other group of processes. This will be used to determine which group is ordered first in the generated communicator. high is logical */ local_high = high; if (comm_ptr->rank == 0) { /* This routine allows use to use the collective communication context rather than the point-to-point context. */ mpi_errno = MPIC_Sendrecv( &local_high, 1, MPI_INT, 0, 0, &remote_high, 1, MPI_INT, 0, 0, comm_ptr, MPI_STATUS_IGNORE, &errflag ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* If local_high and remote_high are the same, then order is arbitrary. we use the gpids of the rank 0 member of the local and remote groups to choose an order in this case. */ if (local_high == remote_high) { MPID_Gpid ingpid, outgpid; mpi_errno = MPID_GPID_Get( comm_ptr, 0, &ingpid ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIC_Sendrecv( &ingpid, sizeof(MPID_Gpid), MPI_BYTE, 0, 1, &outgpid, sizeof(MPID_Gpid), MPI_BYTE, 0, 1, comm_ptr, MPI_STATUS_IGNORE, &errflag ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Note that the gpids cannot be the same because we are starting from a valid intercomm */ int rc = memcmp(&ingpid,&outgpid,sizeof(MPID_Gpid)); if(rc < 0) local_high = 1; else if(rc > 0) local_high = 0; else { /* req#3930: The merge algorithm will deadlock if the gpids are inadvertently the same due to implementation bugs in the MPID_GPID_Get() function */ MPIU_Assert(rc != 0); } } } /* All processes in the local group now need to get the value of local_high, which may have changed if both groups of processes had the same value for high */ mpi_errno = MPIR_Bcast_impl( &local_high, 1, MPI_INT, 0, comm_ptr->local_comm, &errflag ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail"); mpi_errno = MPIR_Comm_create( new_intracomm_ptr ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); new_size = comm_ptr->local_size + comm_ptr->remote_size; /* FIXME: For the intracomm, we need a consistent context id. That means that one of the two groups needs to use the recvcontext_id and the other must use the context_id */ if (local_high) { (*new_intracomm_ptr)->context_id = comm_ptr->recvcontext_id + 2; /* See below */ } else { (*new_intracomm_ptr)->context_id = comm_ptr->context_id + 2; /* See below */ } (*new_intracomm_ptr)->recvcontext_id = (*new_intracomm_ptr)->context_id; (*new_intracomm_ptr)->remote_size = (*new_intracomm_ptr)->local_size = new_size; (*new_intracomm_ptr)->rank = -1; (*new_intracomm_ptr)->comm_kind = MPID_INTRACOMM; /* Now we know which group comes first. Build the new mapping from the existing comm */ mpi_errno = create_and_map(comm_ptr, local_high, (*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* We've setup a temporary context id, based on the context id used by the intercomm. This allows us to perform the allreduce operations within the context id algorithm, since we already have a valid (almost - see comm_create_hook) communicator. */ mpi_errno = MPIR_Comm_commit((*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* printf( "About to get context id \n" ); fflush( stdout ); */ /* In the multi-threaded case, MPIR_Get_contextid_sparse assumes that the calling routine already holds the single criticial section */ new_context_id = 0; mpi_errno = MPIR_Get_contextid_sparse( (*new_intracomm_ptr), &new_context_id, FALSE ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIU_Assert(new_context_id != 0); /* We release this communicator that was involved just to * get valid context id and create true one */ mpi_errno = MPIR_Comm_release(*new_intracomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_create( new_intracomm_ptr ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); (*new_intracomm_ptr)->remote_size = (*new_intracomm_ptr)->local_size = new_size; (*new_intracomm_ptr)->rank = -1; (*new_intracomm_ptr)->comm_kind = MPID_INTRACOMM; (*new_intracomm_ptr)->context_id = new_context_id; (*new_intracomm_ptr)->recvcontext_id = new_context_id; mpi_errno = create_and_map(comm_ptr, local_high, (*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_commit((*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_INTERCOMM_MERGE_IMPL); return mpi_errno; fn_fail: goto fn_exit; }
/* comm create impl for intracommunicators, assumes that the standard error * checking has already taken place in the calling function */ int MPIR_Comm_create_intra(MPIR_Comm *comm_ptr, MPIR_Group *group_ptr, MPIR_Comm **newcomm_ptr) { int mpi_errno = MPI_SUCCESS; MPIR_Context_id_t new_context_id = 0; int *mapping = NULL; int n; MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE_INTRA); MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_CREATE_INTRA); MPIR_Assert(comm_ptr->comm_kind == MPIR_COMM_KIND__INTRACOMM); n = group_ptr->size; *newcomm_ptr = NULL; /* Create a new communicator from the specified group members */ /* Creating the context id is collective over the *input* communicator, so it must be created before we decide if this process is a member of the group */ /* In the multi-threaded case, MPIR_Get_contextid_sparse assumes that the calling routine already holds the single criticial section */ mpi_errno = MPIR_Get_contextid_sparse( comm_ptr, &new_context_id, group_ptr->rank == MPI_UNDEFINED ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_Assert(new_context_id != 0); if (group_ptr->rank != MPI_UNDEFINED) { MPIR_Comm *mapping_comm = NULL; mpi_errno = MPII_Comm_create_calculate_mapping(group_ptr, comm_ptr, &mapping, &mapping_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Get the new communicator structure and context id */ mpi_errno = MPIR_Comm_create( newcomm_ptr ); if (mpi_errno) MPIR_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 ); (*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; (*newcomm_ptr)->pof2 = MPL_pof2(n); /* Setup the communicator's network address mapping. This is for the remote group, which is the same as the local group for intracommunicators */ mpi_errno = MPII_Comm_create_map(n, 0, mapping, NULL, mapping_comm, *newcomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_commit(*newcomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } else { /* This process is not in the group */ new_context_id = 0; } fn_exit: if (mapping) MPL_free(mapping); MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_CREATE_INTRA); return mpi_errno; fn_fail: /* --BEGIN ERROR HANDLING-- */ if (*newcomm_ptr != NULL) { MPIR_Comm_release(*newcomm_ptr); new_context_id = 0; /* MPIR_Comm_release frees the new ctx id */ } if (new_context_id != 0 && group_ptr->rank != MPI_UNDEFINED) { MPIR_Free_contextid(new_context_id); } /* --END ERROR HANDLING-- */ goto fn_exit; }
/* comm create group impl; assumes that the standard error checking * has already taken place in the calling function */ int MPIR_Comm_create_group(MPIR_Comm * comm_ptr, MPIR_Group * group_ptr, int tag, MPIR_Comm ** newcomm_ptr) { int mpi_errno = MPI_SUCCESS; MPIR_Context_id_t new_context_id = 0; int *mapping = NULL; int n; MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE_GROUP); MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_CREATE_GROUP); MPIR_Assert(comm_ptr->comm_kind == MPIR_COMM_KIND__INTRACOMM); n = group_ptr->size; *newcomm_ptr = NULL; /* Create a new communicator from the specified group members */ if (group_ptr->rank != MPI_UNDEFINED) { MPIR_Comm *mapping_comm = NULL; /* 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_Get_contextid_sparse_group( comm_ptr, group_ptr, tag, &new_context_id, 0 ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_Assert(new_context_id != 0); mpi_errno = MPII_Comm_create_calculate_mapping(group_ptr, comm_ptr, &mapping, &mapping_comm); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* Get the new communicator structure and context id */ mpi_errno = MPIR_Comm_create( newcomm_ptr ); if (mpi_errno) MPIR_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 ); (*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; /* Setup the communicator's vc table. This is for the remote group, which is the same as the local group for intracommunicators */ mpi_errno = MPII_Comm_create_map(n, 0, mapping, NULL, mapping_comm, *newcomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_commit(*newcomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } else { /* This process is not in the group */ new_context_id = 0; } fn_exit: if (mapping) MPL_free(mapping); MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_CREATE_GROUP); return mpi_errno; fn_fail: /* --BEGIN ERROR HANDLING-- */ if (*newcomm_ptr != NULL) { MPIR_Comm_release(*newcomm_ptr); new_context_id = 0; /* MPIR_Comm_release frees the new ctx id */ } if (new_context_id != 0) MPIR_Free_contextid(new_context_id); /* --END ERROR HANDLING-- */ goto fn_exit; }
int MPIR_Intercomm_create_impl(MPIR_Comm *local_comm_ptr, int local_leader, MPIR_Comm *peer_comm_ptr, int remote_leader, int tag, MPIR_Comm **new_intercomm_ptr) { int mpi_errno = MPI_SUCCESS; MPIR_Context_id_t final_context_id, recvcontext_id; int remote_size = 0, *remote_lpids = NULL; int comm_info[3]; int is_low_group = 0; int cts_tag; MPIR_Errflag_t errflag = MPIR_ERR_NONE; MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_KIND__INTERCOMM_CREATE_IMPL); MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_KIND__INTERCOMM_CREATE_IMPL); /* Shift tag into the tagged coll space (tag provided by the user is ignored as of MPI 3.0) */ cts_tag = MPIR_COMM_KIND__INTERCOMM_CREATE_TAG | MPIR_Process.tagged_coll_mask; mpi_errno = MPID_Intercomm_exchange_map(local_comm_ptr, local_leader, peer_comm_ptr, remote_leader, &remote_size, &remote_lpids, &is_low_group); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* * Create the contexts. Each group will have a context for sending * to the other group. All processes must be involved. Because * we know that the local and remote groups are disjoint, this * step will complete */ MPL_DBG_MSG_FMT(MPIR_DBG_COMM,VERBOSE, (MPL_DBG_FDEST,"About to get contextid (local_size=%d) on rank %d", local_comm_ptr->local_size, local_comm_ptr->rank )); /* In the multi-threaded case, MPIR_Get_contextid_sparse assumes that the calling routine already holds the single criticial section */ /* TODO: Make sure this is tag-safe */ mpi_errno = MPIR_Get_contextid_sparse( local_comm_ptr, &recvcontext_id, FALSE ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_Assert(recvcontext_id != 0); MPL_DBG_MSG_FMT(MPIR_DBG_COMM,VERBOSE, (MPL_DBG_FDEST,"Got contextid=%d", recvcontext_id)); /* Leaders can now swap context ids and then broadcast the value to the local group of processes */ if (local_comm_ptr->rank == local_leader) { MPIR_Context_id_t remote_context_id; mpi_errno = MPIC_Sendrecv( &recvcontext_id, 1, MPIR_CONTEXT_ID_T_DATATYPE, remote_leader, cts_tag, &remote_context_id, 1, MPIR_CONTEXT_ID_T_DATATYPE, remote_leader, cts_tag, peer_comm_ptr, MPI_STATUS_IGNORE, &errflag ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); final_context_id = remote_context_id; /* Now, send all of our local processes the remote_lpids, along with the final context id */ comm_info[0] = final_context_id; MPL_DBG_MSG(MPIR_DBG_COMM,VERBOSE,"About to bcast on local_comm"); mpi_errno = MPID_Bcast( comm_info, 1, MPI_INT, local_leader, local_comm_ptr, &errflag ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail"); MPL_DBG_MSG_D(MPIR_DBG_COMM,VERBOSE,"end of bcast on local_comm of size %d", local_comm_ptr->local_size ); } else { /* we're the other processes */ MPL_DBG_MSG(MPIR_DBG_COMM,VERBOSE,"About to receive bcast on local_comm"); mpi_errno = MPID_Bcast( comm_info, 1, MPI_INT, local_leader, local_comm_ptr, &errflag ); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail"); /* Extract the context and group sign informatin */ final_context_id = comm_info[0]; } /* At last, we now have the information that we need to build the intercommunicator */ /* All processes in the local_comm now build the communicator */ mpi_errno = MPIR_Comm_create( new_intercomm_ptr ); if (mpi_errno) goto fn_fail; (*new_intercomm_ptr)->context_id = final_context_id; (*new_intercomm_ptr)->recvcontext_id = recvcontext_id; (*new_intercomm_ptr)->remote_size = remote_size; (*new_intercomm_ptr)->local_size = local_comm_ptr->local_size; (*new_intercomm_ptr)->pof2 = local_comm_ptr->pof2; (*new_intercomm_ptr)->rank = local_comm_ptr->rank; (*new_intercomm_ptr)->comm_kind = MPIR_COMM_KIND__INTERCOMM; (*new_intercomm_ptr)->local_comm = 0; (*new_intercomm_ptr)->is_low_group = is_low_group; mpi_errno = MPID_Create_intercomm_from_lpids( *new_intercomm_ptr, remote_size, remote_lpids ); if (mpi_errno) goto fn_fail; MPIR_Comm_map_dup(*new_intercomm_ptr, local_comm_ptr, MPIR_COMM_MAP_DIR__L2L); /* Inherit the error handler (if any) */ MPID_THREAD_CS_ENTER(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(local_comm_ptr)); (*new_intercomm_ptr)->errhandler = local_comm_ptr->errhandler; if (local_comm_ptr->errhandler) { MPIR_Errhandler_add_ref( local_comm_ptr->errhandler ); } MPID_THREAD_CS_EXIT(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(local_comm_ptr)); mpi_errno = MPIR_Comm_commit(*new_intercomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); fn_exit: if (remote_lpids) { MPL_free(remote_lpids); remote_lpids = NULL; } MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_KIND__INTERCOMM_CREATE_IMPL); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Intercomm_merge_impl(MPIR_Comm * comm_ptr, int high, MPIR_Comm ** new_intracomm_ptr) { int mpi_errno = MPI_SUCCESS; int local_high, remote_high, new_size; MPIR_Context_id_t new_context_id; MPIR_Errflag_t errflag = MPIR_ERR_NONE; MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_KIND__INTERCOMM_MERGE_IMPL); MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_KIND__INTERCOMM_MERGE_IMPL); /* Make sure that we have a local intercommunicator */ if (!comm_ptr->local_comm) { /* Manufacture the local communicator */ mpi_errno = MPII_Setup_intercomm_localcomm(comm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } /* Find the "high" value of the other group of processes. This * will be used to determine which group is ordered first in * the generated communicator. high is logical */ local_high = high; if (comm_ptr->rank == 0) { /* This routine allows use to use the collective communication * context rather than the point-to-point context. */ mpi_errno = MPIC_Sendrecv(&local_high, 1, MPI_INT, 0, 0, &remote_high, 1, MPI_INT, 0, 0, comm_ptr, MPI_STATUS_IGNORE, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* If local_high and remote_high are the same, then order is arbitrary. * we use the is_low_group in the intercomm in this case. */ MPL_DBG_MSG_FMT(MPIR_DBG_COMM, VERBOSE, (MPL_DBG_FDEST, "local_high=%d remote_high=%d is_low_group=%d", local_high, remote_high, comm_ptr->is_low_group)); if (local_high == remote_high) { local_high = !(comm_ptr->is_low_group); } } /* * All processes in the local group now need to get the * value of local_high, which may have changed if both groups * of processes had the same value for high */ mpi_errno = MPIR_Bcast(&local_high, 1, MPI_INT, 0, comm_ptr->local_comm, &errflag); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail"); /* * For the intracomm, we need a consistent context id. * That means that one of the two groups needs to use * the recvcontext_id and the other must use the context_id * The recvcontext_id is unique on each process, but another * communicator may use the context_id. Therefore, we do a small hack. * We set both flags indicating a sub-communicator (intra-node and * inter-node) to one. This is normally not possible (a communicator * is either intra- or inter-node) - which makes this context_id unique. * */ new_size = comm_ptr->local_size + comm_ptr->remote_size; mpi_errno = MPIR_Comm_create(new_intracomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); if (local_high) { (*new_intracomm_ptr)->context_id = MPIR_CONTEXT_SET_FIELD(SUBCOMM, comm_ptr->recvcontext_id, 3); } else { (*new_intracomm_ptr)->context_id = MPIR_CONTEXT_SET_FIELD(SUBCOMM, comm_ptr->context_id, 3); } (*new_intracomm_ptr)->recvcontext_id = (*new_intracomm_ptr)->context_id; (*new_intracomm_ptr)->remote_size = (*new_intracomm_ptr)->local_size = new_size; (*new_intracomm_ptr)->pof2 = MPL_pof2(new_size); (*new_intracomm_ptr)->rank = -1; (*new_intracomm_ptr)->comm_kind = MPIR_COMM_KIND__INTRACOMM; /* Now we know which group comes first. Build the new mapping * from the existing comm */ mpi_errno = create_and_map(comm_ptr, local_high, (*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* We've setup a temporary context id, based on the context id * used by the intercomm. This allows us to perform the allreduce * operations within the context id algorithm, since we already * have a valid (almost - see comm_create_hook) communicator. */ mpi_errno = MPIR_Comm_commit((*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* printf("About to get context id \n"); fflush(stdout); */ /* In the multi-threaded case, MPIR_Get_contextid_sparse assumes that the * calling routine already holds the single criticial section */ new_context_id = 0; mpi_errno = MPIR_Get_contextid_sparse((*new_intracomm_ptr), &new_context_id, FALSE); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPIR_Assert(new_context_id != 0); /* We release this communicator that was involved just to * get valid context id and create true one */ mpi_errno = MPIR_Comm_release(*new_intracomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_create(new_intracomm_ptr); if (mpi_errno) MPIR_ERR_POP(mpi_errno); (*new_intracomm_ptr)->remote_size = (*new_intracomm_ptr)->local_size = new_size; (*new_intracomm_ptr)->pof2 = MPL_pof2(new_size); (*new_intracomm_ptr)->rank = -1; (*new_intracomm_ptr)->comm_kind = MPIR_COMM_KIND__INTRACOMM; (*new_intracomm_ptr)->context_id = new_context_id; (*new_intracomm_ptr)->recvcontext_id = new_context_id; mpi_errno = create_and_map(comm_ptr, local_high, (*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPIR_Comm_commit((*new_intracomm_ptr)); if (mpi_errno) MPIR_ERR_POP(mpi_errno); fn_exit: MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_KIND__INTERCOMM_MERGE_IMPL); return mpi_errno; fn_fail: goto fn_exit; }
/* comm create impl for intracommunicators, assumes that the standard error * checking has already taken place in the calling function */ PMPI_LOCAL int MPIR_Comm_create_intra(MPID_Comm *comm_ptr, MPID_Group *group_ptr, MPI_Comm *newcomm) { int mpi_errno = MPI_SUCCESS; MPIR_Context_id_t new_context_id = 0; MPID_Comm *newcomm_ptr = NULL; int *mapping = NULL; int n; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE_INTRA); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_CREATE_INTRA); MPIU_Assert(comm_ptr->comm_kind == MPID_INTRACOMM); n = group_ptr->size; *newcomm = MPI_COMM_NULL; /* Create a new communicator from the specified group members */ /* Creating the context id is collective over the *input* communicator, so it must be created before we decide if this process is a member of the group */ /* In the multi-threaded case, MPIR_Get_contextid assumes that the calling routine already holds the single criticial section */ /* TODO should be converted to use MPIR_Get_contextid_sparse instead */ mpi_errno = MPIR_Get_contextid( comm_ptr, &new_context_id ); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_Assert(new_context_id != 0); if (group_ptr->rank != MPI_UNDEFINED) { MPID_VCR *mapping_vcr = NULL; mpi_errno = MPIR_Comm_create_calculate_mapping(group_ptr, comm_ptr, &mapping_vcr, &mapping); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* Get the new communicator structure and context id */ mpi_errno = MPIR_Comm_create( &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 ); 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; /* 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); /* Notify the device of this new communicator */ MPID_Dev_comm_create_hook( newcomm_ptr ); mpi_errno = MPIR_Comm_commit(newcomm_ptr); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_OBJ_PUBLISH_HANDLE(*newcomm, newcomm_ptr->handle); } else { /* This process is not in the group */ MPIR_Free_contextid( new_context_id ); new_context_id = 0; } fn_exit: if (mapping) MPIU_Free(mapping); MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_CREATE_INTRA); 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); *newcomm = MPI_COMM_NULL; goto fn_exit; }