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