Blame src/mpi/topo/topoutil.c

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
#include "mpiimpl.h"
Packit Service c5cf8c
Packit Service c5cf8c
static int unweighted_dummy = 0x46618;
Packit Service c5cf8c
static int weights_empty_dummy = 0x022284;
Packit Service c5cf8c
/* cannot ==NULL, would be ambiguous */
Packit Service c5cf8c
int *const MPI_UNWEIGHTED = &unweighted_dummy;
Packit Service c5cf8c
int *const MPI_WEIGHTS_EMPTY = &weights_empty_dummy;
Packit Service c5cf8c
Packit Service c5cf8c
/* Keyval for topology information */
Packit Service c5cf8c
static int MPIR_Topology_keyval = MPI_KEYVAL_INVALID;
Packit Service c5cf8c
Packit Service c5cf8c
/* Local functions */
Packit Service c5cf8c
static int MPIR_Topology_copy_fn(MPI_Comm, int, void *, void *, void *, int *);
Packit Service c5cf8c
static int MPIR_Topology_delete_fn(MPI_Comm, int, void *, void *);
Packit Service c5cf8c
static int MPIR_Topology_finalize(void *);
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
  Return a poiner to the topology structure on a communicator.
Packit Service c5cf8c
  Returns null if no topology structure is defined
Packit Service c5cf8c
*/
Packit Service c5cf8c
MPIR_Topology *MPIR_Topology_get(MPIR_Comm * comm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Topology *topo_ptr;
Packit Service c5cf8c
    int flag;
Packit Service c5cf8c
Packit Service c5cf8c
    if (MPIR_Topology_keyval == MPI_KEYVAL_INVALID) {
Packit Service c5cf8c
        return 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPII_Comm_get_attr(comm_ptr->handle, MPIR_Topology_keyval,
Packit Service c5cf8c
                                   &topo_ptr, &flag, MPIR_ATTR_PTR);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        return NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    if (flag)
Packit Service c5cf8c
        return topo_ptr;
Packit Service c5cf8c
    return NULL;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Topology_put
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Topology_put(MPIR_Comm * comm_ptr, MPIR_Topology * topo_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Assert(comm_ptr != NULL);
Packit Service c5cf8c
Packit Service c5cf8c
    if (MPIR_Topology_keyval == MPI_KEYVAL_INVALID) {
Packit Service c5cf8c
        /* Create a new keyval */
Packit Service c5cf8c
        /* FIXME - thread safe code needs a thread lock here, followed
Packit Service c5cf8c
         * by another test on the keyval to see if a different thread
Packit Service c5cf8c
         * got there first */
Packit Service c5cf8c
        mpi_errno = MPIR_Comm_create_keyval_impl(MPIR_Topology_copy_fn,
Packit Service c5cf8c
                                                 MPIR_Topology_delete_fn, &MPIR_Topology_keyval, 0);
Packit Service c5cf8c
        /* Register the finalize handler */
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        MPIR_Add_finalize(MPIR_Topology_finalize, (void *) 0, MPIR_FINALIZE_CALLBACK_PRIO - 1);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    mpi_errno = MPIR_Comm_set_attr_impl(comm_ptr, MPIR_Topology_keyval, topo_ptr, MPIR_ATTR_PTR);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
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
/* Ignore p */
Packit Service c5cf8c
Packit Service c5cf8c
static int MPIR_Topology_finalize(void *p ATTRIBUTE((unused)))
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(p);
Packit Service c5cf8c
Packit Service c5cf8c
    if (MPIR_Topology_keyval != MPI_KEYVAL_INVALID) {
Packit Service c5cf8c
        /* Just in case */
Packit Service c5cf8c
        MPIR_Comm_free_keyval_impl(MPIR_Topology_keyval);
Packit Service c5cf8c
        MPIR_Topology_keyval = MPI_KEYVAL_INVALID;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return 0;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
static int *MPIR_Copy_array(int n, const int a[], int *err)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int *new_p;
Packit Service c5cf8c
Packit Service c5cf8c
    /* the copy of NULL is NULL */
Packit Service c5cf8c
    if (a == NULL) {
Packit Service c5cf8c
        MPIR_Assert(n == 0);
Packit Service c5cf8c
        return NULL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    new_p = (int *) MPL_malloc(n * sizeof(int), MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (!new_p) {
Packit Service c5cf8c
        *err = MPI_ERR_OTHER;
Packit Service c5cf8c
        return 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
    MPIR_Memcpy(new_p, a, n * sizeof(int));
Packit Service c5cf8c
    return new_p;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* The keyval copy and delete functions must handle copying and deleting
Packit Service c5cf8c
   the associated topology structures
Packit Service c5cf8c
Packit Service c5cf8c
   We can reduce the number of allocations by making a single allocation
Packit Service c5cf8c
   of enough integers for all fields (including the ones in the structure)
Packit Service c5cf8c
   and freeing the single object later.
Packit Service c5cf8c
*/
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Topology_copy_fn
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
static int MPIR_Topology_copy_fn(MPI_Comm comm ATTRIBUTE((unused)),
Packit Service c5cf8c
                                 int keyval ATTRIBUTE((unused)),
Packit Service c5cf8c
                                 void *extra_data ATTRIBUTE((unused)),
Packit Service c5cf8c
                                 void *attr_in, void *attr_out, int *flag)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Topology *old_topology = (MPIR_Topology *) attr_in;
Packit Service c5cf8c
    MPIR_Topology *copy_topology = NULL;
Packit Service c5cf8c
    MPIR_CHKPMEM_DECL(5);
Packit Service c5cf8c
    int mpi_errno = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(comm);
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(keyval);
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(extra_data);
Packit Service c5cf8c
Packit Service c5cf8c
    *flag = 0;
Packit Service c5cf8c
    *(void **) attr_out = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKPMEM_MALLOC(copy_topology, MPIR_Topology *, sizeof(MPIR_Topology), mpi_errno,
Packit Service c5cf8c
                        "copy_topology", MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
    MPL_VG_MEM_INIT(copy_topology, sizeof(MPIR_Topology));
Packit Service c5cf8c
Packit Service c5cf8c
    /* simplify copying and error handling */
Packit Service c5cf8c
#define MPIR_ARRAY_COPY_HELPER(kind_,array_field_,count_field_) \
Packit Service c5cf8c
        do { \
Packit Service c5cf8c
            copy_topology->topo.kind_.array_field_ = \
Packit Service c5cf8c
                MPIR_Copy_array(old_topology->topo.kind_.count_field_, \
Packit Service c5cf8c
                                old_topology->topo.kind_.array_field_, \
Packit Service c5cf8c
                                &mpi_errno); \
Packit Service c5cf8c
            if (mpi_errno) MPIR_ERR_POP(mpi_errno); \
Packit Service c5cf8c
            MPIR_CHKPMEM_REGISTER(copy_topology->topo.kind_.array_field_); \
Packit Service c5cf8c
        } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
    copy_topology->kind = old_topology->kind;
Packit Service c5cf8c
    if (old_topology->kind == MPI_CART) {
Packit Service c5cf8c
        copy_topology->topo.cart.ndims = old_topology->topo.cart.ndims;
Packit Service c5cf8c
        copy_topology->topo.cart.nnodes = old_topology->topo.cart.nnodes;
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(cart, dims, ndims);
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(cart, periodic, ndims);
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(cart, position, ndims);
Packit Service c5cf8c
    } else if (old_topology->kind == MPI_GRAPH) {
Packit Service c5cf8c
        copy_topology->topo.graph.nnodes = old_topology->topo.graph.nnodes;
Packit Service c5cf8c
        copy_topology->topo.graph.nedges = old_topology->topo.graph.nedges;
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(graph, index, nnodes);
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(graph, edges, nedges);
Packit Service c5cf8c
    } else if (old_topology->kind == MPI_DIST_GRAPH) {
Packit Service c5cf8c
        copy_topology->topo.dist_graph.indegree = old_topology->topo.dist_graph.indegree;
Packit Service c5cf8c
        copy_topology->topo.dist_graph.outdegree = old_topology->topo.dist_graph.outdegree;
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(dist_graph, in, indegree);
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(dist_graph, in_weights, indegree);
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(dist_graph, out, outdegree);
Packit Service c5cf8c
        MPIR_ARRAY_COPY_HELPER(dist_graph, out_weights, outdegree);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        /* Unknown topology */
Packit Service c5cf8c
        return MPI_ERR_TOPOLOGY;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
#undef MPIR_ARRAY_COPY_HELPER
Packit Service c5cf8c
Packit Service c5cf8c
    *(void **) attr_out = (void *) copy_topology;
Packit Service c5cf8c
    *flag = 1;
Packit Service c5cf8c
    MPIR_CHKPMEM_COMMIT();
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    /* Return mpi_errno in case one of the copy array functions failed */
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    MPIR_CHKPMEM_REAP();
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Topology_delete_fn
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
static int MPIR_Topology_delete_fn(MPI_Comm comm ATTRIBUTE((unused)),
Packit Service c5cf8c
                                   int keyval ATTRIBUTE((unused)),
Packit Service c5cf8c
                                   void *attr_val, void *extra_data ATTRIBUTE((unused)))
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Topology *topology = (MPIR_Topology *) attr_val;
Packit Service c5cf8c
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(comm);
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(keyval);
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(extra_data);
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME - free the attribute data structure */
Packit Service c5cf8c
Packit Service c5cf8c
    if (topology->kind == MPI_CART) {
Packit Service c5cf8c
        MPL_free(topology->topo.cart.dims);
Packit Service c5cf8c
        MPL_free(topology->topo.cart.periodic);
Packit Service c5cf8c
        MPL_free(topology->topo.cart.position);
Packit Service c5cf8c
        MPL_free(topology);
Packit Service c5cf8c
    } else if (topology->kind == MPI_GRAPH) {
Packit Service c5cf8c
        MPL_free(topology->topo.graph.index);
Packit Service c5cf8c
        MPL_free(topology->topo.graph.edges);
Packit Service c5cf8c
        MPL_free(topology);
Packit Service c5cf8c
    } else if (topology->kind == MPI_DIST_GRAPH) {
Packit Service c5cf8c
        MPL_free(topology->topo.dist_graph.in);
Packit Service c5cf8c
        MPL_free(topology->topo.dist_graph.out);
Packit Service c5cf8c
        if (topology->topo.dist_graph.in_weights)
Packit Service c5cf8c
            MPL_free(topology->topo.dist_graph.in_weights);
Packit Service c5cf8c
        if (topology->topo.dist_graph.out_weights)
Packit Service c5cf8c
            MPL_free(topology->topo.dist_graph.out_weights);
Packit Service c5cf8c
        MPL_free(topology);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        return MPI_ERR_TOPOLOGY;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
    return MPI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/* the next two routines implement the following behavior (quoted from Section
Packit Service c5cf8c
 * 7.6 of the MPI-3.0 standard):
Packit Service c5cf8c
 *
Packit Service c5cf8c
 *     For a distributed graph topology, created with MPI_DIST_GRAPH_CREATE, the
Packit Service c5cf8c
 *     sequence of neighbors in the send and receive buffers at each process
Packit Service c5cf8c
 *     is defined as the sequence returned by MPI_DIST_GRAPH_NEIGHBORS for
Packit Service c5cf8c
 *     destinations and sources, respectively. For a general graph topology,
Packit Service c5cf8c
 *     created with MPI_GRAPH_CREATE, the order of neighbors in the send and
Packit Service c5cf8c
 *     receive buffers is defined as the sequence of neighbors as returned by
Packit Service c5cf8c
 *     MPI_GRAPH_NEIGHBORS. Note that general graph topologies should generally
Packit Service c5cf8c
 *     be replaced by the distributed graph topologies.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 *     For a Cartesian topology, created with MPI_CART_CREATE, the sequence of
Packit Service c5cf8c
 *     neighbors in the send and receive buffers at each process is defined by
Packit Service c5cf8c
 *     order of the dimensions, first the neighbor in the negative direction and
Packit Service c5cf8c
 *     then in the positive direction with displacement 1. The numbers of
Packit Service c5cf8c
 *     sources and destinations in the communication routines are 2*ndims with
Packit Service c5cf8c
 *     ndims defined in MPI_CART_CREATE. If a neighbor does not exist, i.e., at
Packit Service c5cf8c
 *     the border of a Cartesian topology in the case of a non-periodic virtual
Packit Service c5cf8c
 *     grid dimension (i.e., periods[...]==false), then this neighbor is defined
Packit Service c5cf8c
 *     to be MPI_PROC_NULL.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Topo_canon_nhb_count
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Topo_canon_nhb_count(MPIR_Comm * comm_ptr, int *indegree, int *outdegree, int *weighted)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Topology *topo_ptr;
Packit Service c5cf8c
Packit Service c5cf8c
    topo_ptr = MPIR_Topology_get(comm_ptr);
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP(!topo_ptr, mpi_errno, MPI_ERR_TOPOLOGY, "**notopology");
Packit Service c5cf8c
Packit Service c5cf8c
    /* TODO consider dispatching via a vtable instead of doing if/else */
Packit Service c5cf8c
    if (topo_ptr->kind == MPI_DIST_GRAPH) {
Packit Service c5cf8c
        mpi_errno = MPIR_Dist_graph_neighbors_count_impl(comm_ptr, indegree, outdegree, weighted);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    } else if (topo_ptr->kind == MPI_GRAPH) {
Packit Service c5cf8c
        int nneighbors = 0;
Packit Service c5cf8c
        mpi_errno = MPIR_Graph_neighbors_count_impl(comm_ptr, comm_ptr->rank, &nneighbors);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        *indegree = *outdegree = nneighbors;
Packit Service c5cf8c
        *weighted = FALSE;
Packit Service c5cf8c
    } else if (topo_ptr->kind == MPI_CART) {
Packit Service c5cf8c
        *indegree = 2 * topo_ptr->topo.cart.ndims;
Packit Service c5cf8c
        *outdegree = 2 * topo_ptr->topo.cart.ndims;
Packit Service c5cf8c
        *weighted = FALSE;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        MPIR_Assert(FALSE);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
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
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Topo_canon_nhb
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Topo_canon_nhb(MPIR_Comm * comm_ptr,
Packit Service c5cf8c
                        int indegree, int sources[], int inweights[],
Packit Service c5cf8c
                        int outdegree, int dests[], int outweights[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Topology *topo_ptr;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_TOPO_CANON_NHB);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_TOPO_CANON_NHB);
Packit Service c5cf8c
Packit Service c5cf8c
    topo_ptr = MPIR_Topology_get(comm_ptr);
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP(!topo_ptr, mpi_errno, MPI_ERR_TOPOLOGY, "**notopology");
Packit Service c5cf8c
Packit Service c5cf8c
    /* TODO consider dispatching via a vtable instead of doing if/else */
Packit Service c5cf8c
    if (topo_ptr->kind == MPI_DIST_GRAPH) {
Packit Service c5cf8c
        mpi_errno = MPIR_Dist_graph_neighbors_impl(comm_ptr,
Packit Service c5cf8c
                                                   indegree, sources, inweights,
Packit Service c5cf8c
                                                   outdegree, dests, outweights);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    } else if (topo_ptr->kind == MPI_GRAPH) {
Packit Service c5cf8c
        MPIR_Assert(indegree == outdegree);
Packit Service c5cf8c
        mpi_errno = MPIR_Graph_neighbors_impl(comm_ptr, comm_ptr->rank, indegree, sources);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        MPIR_Memcpy(dests, sources, outdegree * sizeof(*dests));
Packit Service c5cf8c
        /* ignore inweights/outweights */
Packit Service c5cf8c
    } else if (topo_ptr->kind == MPI_CART) {
Packit Service c5cf8c
        int d;
Packit Service c5cf8c
Packit Service c5cf8c
        MPIR_Assert(indegree == outdegree);
Packit Service c5cf8c
        MPIR_Assert(indegree == 2 * topo_ptr->topo.cart.ndims);
Packit Service c5cf8c
Packit Service c5cf8c
        for (d = 0; d < topo_ptr->topo.cart.ndims; ++d) {
Packit Service c5cf8c
            mpi_errno = MPIR_Cart_shift_impl(comm_ptr, d, 1, &sources[2 * d], &sources[2 * d + 1]);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            dests[2 * d] = sources[2 * d];
Packit Service c5cf8c
            dests[2 * d + 1] = sources[2 * d + 1];
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* ignore inweights/outweights */
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        MPIR_Assert(FALSE);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef MPL_USE_DBG_LOGGING
Packit Service c5cf8c
    {
Packit Service c5cf8c
        int i;
Packit Service c5cf8c
        MPL_DBG_MSG_FMT(MPIR_DBG_PT2PT, VERBOSE,
Packit Service c5cf8c
                        (MPL_DBG_FDEST, "canonical neighbors for comm=0x%x comm_ptr=%p",
Packit Service c5cf8c
                         comm_ptr->handle, comm_ptr));
Packit Service c5cf8c
        for (i = 0; i < outdegree; ++i) {
Packit Service c5cf8c
            MPL_DBG_MSG_FMT(MPIR_DBG_PT2PT, VERBOSE,
Packit Service c5cf8c
                            (MPL_DBG_FDEST, "%d/%d: to   %d", i, outdegree, dests[i]));
Packit Service c5cf8c
        }
Packit Service c5cf8c
        for (i = 0; i < indegree; ++i) {
Packit Service c5cf8c
            MPL_DBG_MSG_FMT(MPIR_DBG_PT2PT, VERBOSE,
Packit Service c5cf8c
                            (MPL_DBG_FDEST, "%d/%d: from %d", i, indegree, sources[i]));
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_TOPO_CANON_NHB);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}