-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpi/topo/dist_gr_create.c
        -:    0:Graph:dist_gr_create.gcno
        -:    0:Data:dist_gr_create.gcda
        -:    0:Runs:4
        -:    0:Programs:1
        -:    1:/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
        -:    2:/*
        -:    3: *
        -:    4: *  (C) 2009 by Argonne National Laboratory.
        -:    5: *      See COPYRIGHT in top-level directory.
        -:    6: */
        -:    7:
        -:    8:#include "mpiimpl.h"
        -:    9:#include "topo.h"
        -:   10:
        -:   11:/* -- Begin Profiling Symbol Block for routine MPI_Dist_graph_create */
        -:   12:#if defined(HAVE_PRAGMA_WEAK)
        -:   13:#pragma weak MPI_Dist_graph_create = PMPI_Dist_graph_create
        -:   14:#elif defined(HAVE_PRAGMA_HP_SEC_DEF)
        -:   15:#pragma _HP_SECONDARY_DEF PMPI_Dist_graph_create  MPI_Dist_graph_create
        -:   16:#elif defined(HAVE_PRAGMA_CRI_DUP)
        -:   17:#pragma _CRI duplicate MPI_Dist_graph_create as PMPI_Dist_graph_create
        -:   18:#endif
        -:   19:/* -- End Profiling Symbol Block */
        -:   20:
        -:   21:/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
        -:   22:   the MPI routines */
        -:   23:#ifndef MPICH_MPI_FROM_PMPI
        -:   24:#undef MPI_Dist_graph_create
        -:   25:#define MPI_Dist_graph_create PMPI_Dist_graph_create
        -:   26:/* any utility functions should go here, usually prefixed with PMPI_LOCAL to
        -:   27: * correctly handle weak symbols and the profiling interface */
        -:   28:#endif
        -:   29:
        -:   30:#undef FUNCNAME
        -:   31:#define FUNCNAME MPI_Dist_graph_create
        -:   32:#undef FCNAME
        -:   33:#define FCNAME MPIU_QUOTE(FUNCNAME)
        -:   34:/*@
        -:   35:MPI_Dist_graph_create - MPI_DIST_GRAPH_CREATE returns a handle to a new
        -:   36:communicator to which the distributed graph topology information is
        -:   37:attached.
        -:   38:
        -:   39:Input Parameters:
        -:   40:+ comm_old - input communicator (handle)
        -:   41:. n - number of source nodes for which this process specifies edges (non-negative integer)
        -:   42:. sources - array containing the n source nodes for which this process specifies edges (array of non-negative integers)
        -:   43:. degrees - array specifying the number of destinations for each source node in the source node array (array of non-negative integers)
        -:   44:. destinations - destination nodes for the source nodes in the source node array (array of non-negative integers)
        -:   45:. weights - weights for source to destination edges (array of non-negative integers)
        -:   46:. info - hints on optimization and interpretation of weights (handle)
        -:   47:- reorder - the process may be reordered (true) or not (false) (logical)
        -:   48:
        -:   49:Output Parameter:
        -:   50:. comm_dist_graph - communicator with distributed graph topology added (handle)
        -:   51:
        -:   52:.N ThreadSafe
        -:   53:
        -:   54:.N Fortran
        -:   55:
        -:   56:.N Errors
        -:   57:.N MPI_SUCCESS
        -:   58:@*/
        -:   59:int MPI_Dist_graph_create(MPI_Comm comm_old, int n, int sources[],
        -:   60:                          int degrees[], int destinations[], int weights[],
        -:   61:                          MPI_Info info, int reorder, MPI_Comm *comm_dist_graph)
      320:   62:{
      320:   63:    int mpi_errno = MPI_SUCCESS;
      320:   64:    MPID_Comm *comm_ptr = NULL;
      320:   65:    MPID_Comm *comm_dist_graph_ptr = NULL;
      320:   66:    MPID_Info *info_ptr = NULL;
      320:   67:    MPI_Request *reqs = NULL;
      320:   68:    MPIR_Topology *topo_ptr = NULL;
      320:   69:    MPIR_Dist_graph_topology *dist_graph_ptr = NULL;
        -:   70:    int i;
        -:   71:    int j;
        -:   72:    int index;
      320:   73:    int comm_size = 0;
        -:   74:    int in_capacity;
        -:   75:    int out_capacity;
      320:   76:    int **rout = NULL;
      320:   77:    int **rin = NULL;
        -:   78:    int *rin_sizes;
        -:   79:    int *rout_sizes;
        -:   80:    int *rin_idx;
        -:   81:    int *rout_idx;
        -:   82:    int *rs;
      320:   83:    int in_out_peers[2] = {-1, -1};
      320:   84:    MPIU_CHKLMEM_DECL(9);
      320:   85:    MPIU_CHKPMEM_DECL(1);
      320:   86:    MPIU_THREADPRIV_DECL;
        -:   87:    MPID_MPI_STATE_DECL(MPID_STATE_MPI_DIST_GRAPH_CREATE);
        -:   88:
      320:   89:    MPIR_ERRTEST_INITIALIZED_ORDIE();
        -:   90:
      320:   91:    MPIU_THREAD_CS_ENTER(ALLFUNC,);
        -:   92:    MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_DIST_GRAPH_CREATE);
        -:   93:
      320:   94:    MPIU_THREADPRIV_GET;
      320:   95:    MPIR_Nest_incr();
        -:   96:
        -:   97:    /* Validate parameters, especially handles needing to be converted */
        -:   98:#   ifdef HAVE_ERROR_CHECKING
        -:   99:    {
        -:  100:        MPID_BEGIN_ERROR_CHECKS;
        -:  101:        {
      320:  102:            MPIR_ERRTEST_COMM(comm_old, mpi_errno);
      320:  103:            MPIR_ERRTEST_INFO_OR_NULL(info, mpi_errno);
      320:  104:            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -:  105:        }
        -:  106:        MPID_END_ERROR_CHECKS;
        -:  107:    }
        -:  108:#   endif
        -:  109:
        -:  110:    /* Convert MPI object handles to object pointers */
      320:  111:    MPID_Comm_get_ptr(comm_old, comm_ptr);
      320:  112:    MPID_Info_get_ptr(info, info_ptr);
        -:  113:
        -:  114:    /* Validate parameters and objects (post conversion) */
        -:  115:#   ifdef HAVE_ERROR_CHECKING
        -:  116:    {
        -:  117:        MPID_BEGIN_ERROR_CHECKS;
        -:  118:        {
        -:  119:            /* Validate comm_ptr */
      320:  120:            MPID_Comm_valid_ptr(comm_ptr, mpi_errno);
        -:  121:            /* If comm_ptr is not valid, it will be reset to null */
      320:  122:            if (comm_ptr) {
      320:  123:                MPIR_ERRTEST_COMM_INTRA(comm_ptr, mpi_errno);
        -:  124:            }
        -:  125:
      320:  126:            MPIR_ERRTEST_ARGNEG(n, "n", mpi_errno);
      320:  127:            if (n > 0) {
      160:  128:                int have_degrees = 0;
      160:  129:                MPIR_ERRTEST_ARGNULL(sources, "sources", mpi_errno);
      160:  130:                MPIR_ERRTEST_ARGNULL(degrees, "degrees", mpi_errno);
      174:  131:                for (i = 0; i < n; ++i) {
      160:  132:                    if (degrees[i]) {
      146:  133:                        have_degrees = 1;
      146:  134:                        break;
        -:  135:                    }
        -:  136:                }
      160:  137:                if (have_degrees) {
      146:  138:                    MPIR_ERRTEST_ARGNULL(destinations, "destinations", mpi_errno);
        -:  139:                    /* in practice this check is currently silly, since
        -:  140:                     * MPI_UNWEIGHTED==NULL */
      146:  141:                    if (weights != MPI_UNWEIGHTED)
      146:  142:                        MPIR_ERRTEST_ARGNULL(weights, "weights", mpi_errno);
        -:  143:                }
        -:  144:            }
        -:  145:
      320:  146:            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -:  147:        }
        -:  148:        MPID_END_ERROR_CHECKS;
        -:  149:    }
        -:  150:#   endif /* HAVE_ERROR_CHECKING */
        -:  151:
        -:  152:
        -:  153:    /* ... body of routine ...  */
        -:  154:    /* Implementation based on Torsten Hoefler's reference implementation
        -:  155:     * attached to MPI-2.2 ticket #33. */
      320:  156:    *comm_dist_graph = MPI_COMM_NULL;
        -:  157:
      320:  158:    comm_size = comm_ptr->local_size;
        -:  159:
        -:  160:    /* following the spirit of the old topo interface, attributes do not
        -:  161:     * propagate to the new communicator (see MPI-2.1 pp. 243 line 11) */
      320:  162:    mpi_errno = MPIR_Comm_copy(comm_ptr, comm_size, &comm_dist_graph_ptr);
      320:  163:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
      320:  164:    MPIU_Assert(comm_dist_graph_ptr != NULL);
        -:  165:
        -:  166:    /* rin is an array of size comm_size containing pointers to arrays of
        -:  167:     * rin_sizes[x].  rin[x] is locally known number of edges into this process
        -:  168:     * from rank x.
        -:  169:     *
        -:  170:     * rout is an array of comm_size containing pointers to arrays of
        -:  171:     * rout_sizes[x].  rout[x] is the locally known number of edges out of this
        -:  172:     * process to rank x. */
      320:  173:    MPIU_CHKLMEM_MALLOC(rout,       int **, comm_size*sizeof(int*), mpi_errno, "rout");
      320:  174:    MPIU_CHKLMEM_MALLOC(rin,        int **, comm_size*sizeof(int*), mpi_errno, "rin");
      320:  175:    MPIU_CHKLMEM_MALLOC(rin_sizes,  int *, comm_size*sizeof(int), mpi_errno, "rin_sizes");
      320:  176:    MPIU_CHKLMEM_MALLOC(rout_sizes, int *, comm_size*sizeof(int), mpi_errno, "rout_sizes");
      320:  177:    MPIU_CHKLMEM_MALLOC(rin_idx,    int *, comm_size*sizeof(int), mpi_errno, "rin_idx");
      320:  178:    MPIU_CHKLMEM_MALLOC(rout_idx,   int *, comm_size*sizeof(int), mpi_errno, "rout_idx");
        -:  179:
      320:  180:    memset(rout,       0, comm_size*sizeof(int*));
      320:  181:    memset(rin,        0, comm_size*sizeof(int*));
      320:  182:    memset(rin_sizes,  0, comm_size*sizeof(int));
      320:  183:    memset(rout_sizes, 0, comm_size*sizeof(int));
      320:  184:    memset(rin_idx,    0, comm_size*sizeof(int));
      320:  185:    memset(rout_idx,   0, comm_size*sizeof(int));
        -:  186:
        -:  187:    /* compute array sizes */
      320:  188:    index = 0;
      748:  189:    for (i = 0; i < n; ++i) {
      428:  190:        MPIU_Assert(sources[i] < comm_size);
      950:  191:        for (j = 0; j < degrees[i]; ++j) {
      522:  192:            MPIU_Assert(destinations[index] < comm_size);
        -:  193:            /* rout_sizes[i] is twice as long as the number of edges to be
        -:  194:             * sent to rank i by this process */
      522:  195:            rout_sizes[sources[i]] += 2;
      522:  196:            rin_sizes[destinations[index]] += 2;
      522:  197:            ++index;
        -:  198:        }
        -:  199:    }
        -:  200:
        -:  201:    /* allocate arrays */
     1600:  202:    for (i = 0; i < comm_size; ++i) {
        -:  203:        /* can't use CHKLMEM macros b/c we are in a loop */
     1280:  204:        if (rin_sizes[i]) {
      298:  205:            rin[i] = MPIU_Malloc(rin_sizes[i] * sizeof(int));
        -:  206:        }
     1280:  207:        if (rout_sizes[i]) {
      306:  208:            rout[i] = MPIU_Malloc(rout_sizes[i] * sizeof(int));
        -:  209:        }
        -:  210:    }
        -:  211:
        -:  212:    /* populate arrays */
      320:  213:    index = 0;
      748:  214:    for (i = 0; i < n; ++i) {
        -:  215:        /* TODO add this assert as proper error checking above */
      428:  216:        int s_rank = sources[i];
      428:  217:        MPIU_Assert(s_rank < comm_size);
      428:  218:        MPIU_Assert(s_rank >= 0);
        -:  219:
      950:  220:        for (j = 0; j < degrees[i]; ++j) {
      522:  221:            int d_rank = destinations[index];
      522:  222:            int weight = (weights == MPI_UNWEIGHTED ? 0 : weights[index]);
        -:  223:            /* TODO add this assert as proper error checking above */
      522:  224:            MPIU_Assert(d_rank < comm_size);
      522:  225:            MPIU_Assert(d_rank >= 0);
        -:  226:
        -:  227:            /* XXX DJG what about self-edges? do we need to drop one of these
        -:  228:             * cases when there is a self-edge to avoid double-counting? */
        -:  229:
        -:  230:            /* rout[s][2*x] is the value of d for the j'th edge between (s,d)
        -:  231:             * with weight rout[s][2*x+1], where x is the current end of the
        -:  232:             * outgoing edge list for s.  x==(rout_idx[s]/2) */
      522:  233:            rout[s_rank][rout_idx[s_rank]++] = d_rank;
      522:  234:            rout[s_rank][rout_idx[s_rank]++] = weight;
        -:  235:
        -:  236:            /* rin[d][2*x] is the value of s for the j'th edge between (s,d)
        -:  237:             * with weight rout[d][2*x+1], where x is the current end of the
        -:  238:             * incoming edge list for d.  x==(rin_idx[d]/2) */
      522:  239:            rin[d_rank][rin_idx[d_rank]++] = s_rank;
      522:  240:            rin[d_rank][rin_idx[d_rank]++] = weight;
        -:  241:
      522:  242:            ++index;
        -:  243:        }
        -:  244:    }
        -:  245:
     1600:  246:    for (i = 0; i < comm_size; ++i) {
        -:  247:        /* sanity check that all arrays are fully populated*/
     1280:  248:        MPIU_Assert(rin_idx[i] == rin_sizes[i]);
     1280:  249:        MPIU_Assert(rout_idx[i] == rout_sizes[i]);
        -:  250:    }
        -:  251:
      320:  252:    MPIU_CHKLMEM_MALLOC(rs, int *, 2*comm_size*sizeof(int), mpi_errno, "red-scat source buffer");
     1600:  253:    for (i = 0; i < comm_size; ++i) {
     1280:  254:        rs[2*i]   = (rin_sizes[i]  ? 1 : 0);
     1280:  255:        rs[2*i+1] = (rout_sizes[i] ? 1 : 0);
        -:  256:    }
        -:  257:
        -:  258:    /* compute the number of peers I will recv from */
      320:  259:    mpi_errno = NMPI_Reduce_scatter_block(rs, in_out_peers, 2, MPI_INT, MPI_SUM, comm_old);
      320:  260:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  261:
      320:  262:    MPIU_Assert(in_out_peers[0] <= comm_size && in_out_peers[0] >= 0);
      320:  263:    MPIU_Assert(in_out_peers[1] <= comm_size && in_out_peers[1] >= 0);
        -:  264:
      320:  265:    index = 0;
        -:  266:    /* must be 2*comm_size requests because we will possibly send inbound and
        -:  267:     * outbound edges to everyone in our communicator */
      320:  268:    MPIU_CHKLMEM_MALLOC(reqs, MPI_Request *, 2*comm_size*sizeof(MPI_Request), mpi_errno, "temp request array");
     1600:  269:    for (i = 0; i < comm_size; ++i) {
     1280:  270:        if (rin_sizes[i]) {
        -:  271:            /* send edges where i is a destination to process i */
      298:  272:            NMPI_Isend(&rin[i][0], rin_sizes[i], MPI_INT, i, MPIR_TOPO_A_TAG, comm_old, &reqs[index++]);
        -:  273:        }
     1280:  274:        if (rout_sizes[i]) {
        -:  275:            /* send edges where i is a source to process i */
      306:  276:            NMPI_Isend(&rout[i][0], rout_sizes[i], MPI_INT, i, MPIR_TOPO_B_TAG, comm_old, &reqs[index++]);
        -:  277:        }
        -:  278:    }
      320:  279:    MPIU_Assert(index <= (2 * comm_size));
        -:  280:
        -:  281:    /* Create the topology structure */
      320:  282:    MPIU_CHKPMEM_MALLOC(topo_ptr, MPIR_Topology *, sizeof(MPIR_Topology), mpi_errno, "topo_ptr");
      320:  283:    topo_ptr->kind = MPI_DIST_GRAPH;
      320:  284:    dist_graph_ptr = &topo_ptr->topo.dist_graph;
      320:  285:    dist_graph_ptr->indegree = 0;
      320:  286:    dist_graph_ptr->in = NULL;
      320:  287:    dist_graph_ptr->in_weights = NULL;
      320:  288:    dist_graph_ptr->outdegree = 0;
      320:  289:    dist_graph_ptr->out = NULL;
      320:  290:    dist_graph_ptr->out_weights = NULL;
        -:  291:
        -:  292:    /* can't use CHKPMEM macros for this b/c we need to realloc */
      320:  293:    in_capacity = 10; /* arbitrary */
      320:  294:    dist_graph_ptr->in = MPIU_Malloc(in_capacity*sizeof(int));
      320:  295:    if (weights != MPI_UNWEIGHTED)
      320:  296:        dist_graph_ptr->in_weights = MPIU_Malloc(in_capacity*sizeof(int));
      320:  297:    out_capacity = 10; /* arbitrary */
      320:  298:    dist_graph_ptr->out = MPIU_Malloc(out_capacity*sizeof(int));
      320:  299:    if (weights != MPI_UNWEIGHTED)
      320:  300:        dist_graph_ptr->out_weights = MPIU_Malloc(out_capacity*sizeof(int));
        -:  301:
      618:  302:    for (i = 0; i < in_out_peers[0]; ++i) {
        -:  303:        MPI_Status status;
        -:  304:        int count;
        -:  305:        int *buf;
        -:  306:        /* receive inbound edges */
      298:  307:        mpi_errno = NMPI_Probe(MPI_ANY_SOURCE, MPIR_TOPO_A_TAG, comm_old, &status);
      298:  308:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
      298:  309:        mpi_errno = NMPI_Get_count(&status, MPI_INT, &count);
      298:  310:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  311:        /* can't use CHKLMEM macros b/c we are in a loop */
      298:  312:        buf = MPIU_Malloc(count*sizeof(int));
      298:  313:        MPIU_ERR_CHKANDJUMP(!buf, mpi_errno, MPIR_ERR_RECOVERABLE, "**nomem");
        -:  314:
      298:  315:        mpi_errno = NMPI_Recv(buf, count, MPI_INT, MPI_ANY_SOURCE, MPIR_TOPO_A_TAG, comm_old, MPI_STATUS_IGNORE);
        -:  316:
      820:  317:        for (j = 0; j < count/2; ++j) {
      522:  318:            int deg = dist_graph_ptr->indegree++;
      522:  319:            if (deg >= in_capacity) {
    #####:  320:                in_capacity *= 2;
    #####:  321:                MPIU_REALLOC_ORJUMP(dist_graph_ptr->in, in_capacity*sizeof(int), mpi_errno);
    #####:  322:                if (weights != MPI_UNWEIGHTED)
    #####:  323:                    MPIU_REALLOC_ORJUMP(dist_graph_ptr->in_weights, in_capacity*sizeof(int), mpi_errno);
        -:  324:            }
      522:  325:            dist_graph_ptr->in[deg] = buf[2*j];
      522:  326:            if (weights != MPI_UNWEIGHTED)
      522:  327:                dist_graph_ptr->in_weights[deg] = buf[2*j+1];
        -:  328:        }
      298:  329:        MPIU_Free(buf);
        -:  330:    }
        -:  331:
      626:  332:    for (i = 0; i < in_out_peers[1]; ++i) {
        -:  333:        MPI_Status status;
        -:  334:        int count;
        -:  335:        int *buf;
        -:  336:        /* receive outbound edges */
      306:  337:        mpi_errno = NMPI_Probe(MPI_ANY_SOURCE, MPIR_TOPO_B_TAG, comm_old, &status);
      306:  338:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
      306:  339:        mpi_errno = NMPI_Get_count(&status, MPI_INT, &count);
      306:  340:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  341:        /* can't use CHKLMEM macros b/c we are in a loop */
      306:  342:        buf = MPIU_Malloc(count*sizeof(int));
      306:  343:        MPIU_ERR_CHKANDJUMP(!buf, mpi_errno, MPIR_ERR_RECOVERABLE, "**nomem");
        -:  344:
      306:  345:        mpi_errno = NMPI_Recv(buf, count, MPI_INT, MPI_ANY_SOURCE, MPIR_TOPO_B_TAG, comm_old, MPI_STATUS_IGNORE);
        -:  346:
      828:  347:        for (j = 0; j < count/2; ++j) {
      522:  348:            int deg = dist_graph_ptr->outdegree++;
      522:  349:            if (deg >= out_capacity) {
    #####:  350:                out_capacity *= 2;
    #####:  351:                MPIU_REALLOC_ORJUMP(dist_graph_ptr->out, out_capacity*sizeof(int), mpi_errno);
    #####:  352:                if (weights != MPI_UNWEIGHTED)
    #####:  353:                    MPIU_REALLOC_ORJUMP(dist_graph_ptr->out_weights, out_capacity*sizeof(int), mpi_errno);
        -:  354:            }
      522:  355:            dist_graph_ptr->out[deg] = buf[2*j];
      522:  356:            if (weights != MPI_UNWEIGHTED)
      522:  357:                dist_graph_ptr->out_weights[deg] = buf[2*j+1];
        -:  358:        }
      306:  359:        MPIU_Free(buf);
        -:  360:    }
        -:  361:
      320:  362:    mpi_errno = NMPI_Waitall(index, reqs, MPI_STATUSES_IGNORE);
      320:  363:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  364:
        -:  365:    /* remove any excess memory allocation */
      320:  366:    MPIU_REALLOC_ORJUMP(dist_graph_ptr->in, dist_graph_ptr->indegree*sizeof(int), mpi_errno);
      320:  367:    MPIU_REALLOC_ORJUMP(dist_graph_ptr->out, dist_graph_ptr->outdegree*sizeof(int), mpi_errno);
      320:  368:    if (weights != MPI_UNWEIGHTED) {
      320:  369:        MPIU_REALLOC_ORJUMP(dist_graph_ptr->in_weights, dist_graph_ptr->indegree*sizeof(int), mpi_errno);
      320:  370:        MPIU_REALLOC_ORJUMP(dist_graph_ptr->out_weights, dist_graph_ptr->outdegree*sizeof(int), mpi_errno);
        -:  371:    }
        -:  372:
      320:  373:    mpi_errno = MPIR_Topology_put(comm_dist_graph_ptr, topo_ptr);
      320:  374:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  375:
      320:  376:    MPIU_CHKPMEM_COMMIT();
      320:  377:    *comm_dist_graph = comm_dist_graph_ptr->handle;
        -:  378:    /* ... end of body of routine ... */
        -:  379:
      320:  380:  fn_exit:
     1600:  381:    for (i = 0; i < comm_size; ++i) {
     1280:  382:        if (rin[i])
      298:  383:            MPIU_Free(rin[i]);
     1280:  384:        if (rout[i])
      306:  385:            MPIU_Free(rout[i]);
        -:  386:    }
        -:  387:
     2560:  388:    MPIU_CHKLMEM_FREEALL();
        -:  389:
      320:  390:    MPIR_Nest_decr();
        -:  391:    MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_DIST_GRAPH_CREATE);
      320:  392:    MPIU_THREAD_CS_EXIT(ALLFUNC,);
      320:  393:    return mpi_errno;
        -:  394:
    #####:  395:  fn_fail:
    #####:  396:    if (dist_graph_ptr && dist_graph_ptr->in)
    #####:  397:        MPIU_Free(dist_graph_ptr->in);
    #####:  398:    if (dist_graph_ptr && dist_graph_ptr->in_weights)
    #####:  399:        MPIU_Free(dist_graph_ptr->in_weights);
    #####:  400:    if (dist_graph_ptr && dist_graph_ptr->out)
    #####:  401:        MPIU_Free(dist_graph_ptr->out);
    #####:  402:    if (dist_graph_ptr && dist_graph_ptr->out_weights)
    #####:  403:        MPIU_Free(dist_graph_ptr->out_weights);
    #####:  404:    MPIU_CHKPMEM_REAP();
        -:  405:    /* --BEGIN ERROR HANDLING-- */
    #####:  406:    mpi_errno = MPIR_Err_create_code(
        -:  407:        mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
        -:  408:        "**mpi_dist_graph_create", "**mpi_dist_graph_create %C %d %p %p %p %p %I %d %p",
        -:  409:        comm_old, n, sources, degrees, destinations, weights, info, reorder, comm_dist_graph);
    #####:  410:    mpi_errno = MPIR_Err_return_comm(comm_ptr, FCNAME, mpi_errno);
    #####:  411:    goto fn_exit;
        -:  412:    /* --END ERROR HANDLING-- */
        -:  413:}
        -:  414: