-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpi/coll/allgatherv.c
        -:    0:Graph:allgatherv.gcno
        -:    0:Data:allgatherv.gcda
        -:    0:Runs:585
        -:    0:Programs:151
        -:    1:/* -*- Mode: C; c-basic-offset:4 ; -*- */
        -:    2:/*
        -:    3: *
        -:    4: *  (C) 2001 by Argonne National Laboratory.
        -:    5: *      See COPYRIGHT in top-level directory.
        -:    6: */
        -:    7:
        -:    8:#include "mpiimpl.h"
        -:    9:
        -:   10:/* -- Begin Profiling Symbol Block for routine MPI_Allgatherv */
        -:   11:#if defined(HAVE_PRAGMA_WEAK)
        -:   12:#pragma weak MPI_Allgatherv = PMPI_Allgatherv
        -:   13:#elif defined(HAVE_PRAGMA_HP_SEC_DEF)
        -:   14:#pragma _HP_SECONDARY_DEF PMPI_Allgatherv  MPI_Allgatherv
        -:   15:#elif defined(HAVE_PRAGMA_CRI_DUP)
        -:   16:#pragma _CRI duplicate MPI_Allgatherv as PMPI_Allgatherv
        -:   17:#endif
        -:   18:/* -- End Profiling Symbol Block */
        -:   19:
        -:   20:/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
        -:   21:   the MPI routines */
        -:   22:#ifndef MPICH_MPI_FROM_PMPI
        -:   23:#undef MPI_Allgatherv
        -:   24:#define MPI_Allgatherv PMPI_Allgatherv
        -:   25:
        -:   26:/* This is the default implementation of allgatherv. The algorithm is:
        -:   27:   
        -:   28:   Algorithm: MPI_Allgatherv
        -:   29:
        -:   30:   For short messages and non-power-of-two no. of processes, we use
        -:   31:   the algorithm from the Jehoshua Bruck et al IEEE TPDS Nov 97
        -:   32:   paper. It is a variant of the disemmination algorithm for
        -:   33:   barrier. It takes ceiling(lg p) steps.
        -:   34:
        -:   35:   Cost = lgp.alpha + n.((p-1)/p).beta
        -:   36:   where n is total size of data gathered on each process.
        -:   37:
        -:   38:   For short or medium-size messages and power-of-two no. of
        -:   39:   processes, we use the recursive doubling algorithm.
        -:   40:
        -:   41:   Cost = lgp.alpha + n.((p-1)/p).beta
        -:   42:
        -:   43:   TODO: On TCP, we may want to use recursive doubling instead of the Bruck
        -:   44:   algorithm in all cases because of the pairwise-exchange property of
        -:   45:   recursive doubling (see Benson et al paper in Euro PVM/MPI
        -:   46:   2003).
        -:   47:
        -:   48:   For long messages or medium-size messages and non-power-of-two
        -:   49:   no. of processes, we use a ring algorithm. In the first step, each
        -:   50:   process i sends its contribution to process i+1 and receives
        -:   51:   the contribution from process i-1 (with wrap-around). From the
        -:   52:   second step onwards, each process i forwards to process i+1 the
        -:   53:   data it received from process i-1 in the previous step. This takes
        -:   54:   a total of p-1 steps.
        -:   55:
        -:   56:   Cost = (p-1).alpha + n.((p-1)/p).beta
        -:   57:
        -:   58:   Possible improvements: 
        -:   59:
        -:   60:   End Algorithm: MPI_Allgatherv
        -:   61:*/
        -:   62:
        -:   63:/* begin:nested */
        -:   64:/* not declared static because a machine-specific function may call this one 
        -:   65:   in some cases */
        -:   66:int MPIR_Allgatherv ( 
        -:   67:    void *sendbuf, 
        -:   68:    int sendcount,   
        -:   69:    MPI_Datatype sendtype, 
        -:   70:    void *recvbuf, 
        -:   71:    int *recvcounts, 
        -:   72:    int *displs,   
        -:   73:    MPI_Datatype recvtype, 
        -:   74:    MPID_Comm *comm_ptr )
    16926:   75:{
        -:   76:    static const char FCNAME[] = "MPIR_Allgatherv";
        -:   77:    MPI_Comm comm;
        -:   78:    int        comm_size, rank, j, i, left, right;
    16926:   79:    int        mpi_errno = MPI_SUCCESS;
        -:   80:    MPI_Status status;
        -:   81:    MPI_Aint recvbuf_extent, recvtype_extent, recvtype_true_extent, 
        -:   82:	recvtype_true_lb;
        -:   83:    int curr_cnt, send_cnt, dst, total_count, recvtype_size, pof2, src, rem; 
        -:   84:    int recv_cnt, comm_size_is_pof2;
        -:   85:    void *tmp_buf;
        -:   86:    int mask, dst_tree_root, my_tree_root, is_homogeneous, position,  
        -:   87:        send_offset, recv_offset, last_recv_cnt, nprocs_completed, k,
        -:   88:        offset, tmp_mask, tree_root;
        -:   89:#ifdef MPID_HAS_HETERO
        -:   90:    int tmp_buf_size, nbytes;
        -:   91:#endif
        -:   92:    
    16926:   93:    comm = comm_ptr->handle;
    16926:   94:    comm_size = comm_ptr->local_size;
    16926:   95:    rank = comm_ptr->rank;
        -:   96:    
    16926:   97:    total_count = 0;
    83416:   98:    for (i=0; i<comm_size; i++)
    66490:   99:        total_count += recvcounts[i];
        -:  100:
    16926:  101:    if (total_count == 0) return MPI_SUCCESS;
        -:  102:    
    16732:  103:    MPID_Datatype_get_extent_macro( recvtype, recvtype_extent );
    16732:  104:    MPID_Datatype_get_size_macro(recvtype, recvtype_size);
        -:  105:    
        -:  106:    /* check if comm_size is a power of two */
    16732:  107:    pof2 = 1;
    66494:  108:    while (pof2 < comm_size)
    33030:  109:        pof2 *= 2;
    16732:  110:    if (pof2 == comm_size) 
    11706:  111:        comm_size_is_pof2 = 1;
        -:  112:    else
     5026:  113:        comm_size_is_pof2 = 0;
        -:  114:
        -:  115:    /* check if multiple threads are calling this collective function */
        -:  116:    MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr );
        -:  117:
    16732:  118:    if ((total_count*recvtype_size < MPIR_ALLGATHER_LONG_MSG) &&
        -:  119:        (comm_size_is_pof2 == 1)) {
        -:  120:        /* Short or medium size message and power-of-two no. of processes. Use
        -:  121:         * recursive doubling algorithm */   
        -:  122:
    11130:  123:        is_homogeneous = 1;
        -:  124:#ifdef MPID_HAS_HETERO
        -:  125:        if (comm_ptr->is_hetero)
        -:  126:            is_homogeneous = 0;
        -:  127:#endif
        -:  128:        
    11130:  129:        if (is_homogeneous) {
        -:  130:            /* need to receive contiguously into tmp_buf because
        -:  131:               displs could make the recvbuf noncontiguous */
        -:  132:
    11130:  133:            mpi_errno = NMPI_Type_get_true_extent(recvtype, &recvtype_true_lb,
        -:  134:                                                  &recvtype_true_extent);
        -:  135:	    /* --BEGIN ERROR HANDLING-- */
    11130:  136:            if (mpi_errno)
        -:  137:	    {
    #####:  138:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  139:		return mpi_errno;
        -:  140:	    }
        -:  141:            /* --END ERROR HANDLING-- */
        -:  142:
        -:  143:            MPID_Ensure_Aint_fits_in_pointer(total_count *
        -:  144:                           (MPIR_MAX(recvtype_true_extent, recvtype_extent)));
    11130:  145:            tmp_buf = MPIU_Malloc(total_count*(MPIR_MAX(recvtype_true_extent,recvtype_extent)));
        -:  146:	    /* --BEGIN ERROR HANDLING-- */
    11130:  147:            if (!tmp_buf)
        -:  148:	    {
    #####:  149:                mpi_errno = MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**nomem", 0);
    #####:  150:                return mpi_errno;
        -:  151:            }
        -:  152:	    /* --END ERROR HANDLING-- */
        -:  153:
        -:  154:            /* adjust for potential negative lower bound in datatype */
    11130:  155:            tmp_buf = (void *)((char*)tmp_buf - recvtype_true_lb);
        -:  156:
        -:  157:            /* copy local data into right location in tmp_buf */ 
    11130:  158:            position = 0;
    11130:  159:            for (i=0; i<rank; i++) position += recvcounts[i];
    11130:  160:            if (sendbuf != MPI_IN_PLACE)
        -:  161:	    {
    11026:  162:                mpi_errno = MPIR_Localcopy(sendbuf, sendcount, sendtype,
        -:  163:                                           ((char *)tmp_buf + position*
        -:  164:                                            recvtype_extent), 
        -:  165:                                           recvcounts[rank], recvtype);
        -:  166:	    }
        -:  167:            else
        -:  168:	    {
        -:  169:                /* if in_place specified, local data is found in recvbuf */ 
      104:  170:                mpi_errno = MPIR_Localcopy(((char *)recvbuf +
        -:  171:                                            displs[rank]*recvtype_extent), 
        -:  172:                                           recvcounts[rank], recvtype,
        -:  173:                                           ((char *)tmp_buf + position*
        -:  174:                                            recvtype_extent), 
        -:  175:                                           recvcounts[rank], recvtype);
        -:  176:	    }
        -:  177:	    /* --BEGIN ERROR HANDLING-- */
    11130:  178:            if (mpi_errno)
        -:  179:	    {
    #####:  180:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  181:		return mpi_errno;
        -:  182:	    }
        -:  183:	    /* --END ERROR HANDLING-- */
        -:  184:
    11130:  185:            curr_cnt = recvcounts[rank];
        -:  186:            
    11130:  187:            mask = 0x1;
    11130:  188:            i = 0;
    41366:  189:            while (mask < comm_size) {
    19106:  190:                dst = rank ^ mask;
        -:  191:                
        -:  192:                /* find offset into send and recv buffers. zero out 
        -:  193:                   the least significant "i" bits of rank and dst to 
        -:  194:                   find root of src and dst subtrees. Use ranks of 
        -:  195:                   roots as index to send from and recv into buffer */ 
        -:  196:                
    19106:  197:                dst_tree_root = dst >> i;
    19106:  198:                dst_tree_root <<= i;
        -:  199:                
    19106:  200:                my_tree_root = rank >> i;
    19106:  201:                my_tree_root <<= i;
        -:  202:                
    19106:  203:                if (dst < comm_size) {
    19106:  204:                    send_offset = 0;
    42841:  205:                    for (j=0; j<my_tree_root; j++)
    23735:  206:                        send_offset += recvcounts[j];
        -:  207:                    
    19106:  208:                    recv_offset = 0;
    42841:  209:                    for (j=0; j<dst_tree_root; j++)
    23735:  210:                        recv_offset += recvcounts[j];
        -:  211:
    19106:  212:                    mpi_errno = MPIC_Sendrecv(((char *)tmp_buf + send_offset * recvtype_extent),
        -:  213:                                              curr_cnt, recvtype, dst,
        -:  214:                                              MPIR_ALLGATHERV_TAG,  
        -:  215:                                              ((char *)tmp_buf + recv_offset * recvtype_extent),
        -:  216:                                              total_count - recv_offset, recvtype, dst,
        -:  217:                                              MPIR_ALLGATHERV_TAG,
        -:  218:                                              comm, &status); 
        -:  219:                    /* for convenience, recv is posted for a bigger amount
        -:  220:                       than will be sent */ 
        -:  221:		    /* --BEGIN ERROR HANDLING-- */
    19106:  222:                    if (mpi_errno)
        -:  223:		    {
    #####:  224:			mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  225:			return mpi_errno;
        -:  226:		    }
        -:  227:		    /* --END ERROR HANDLING-- */
        -:  228:                    
    19106:  229:                    NMPI_Get_count(&status, recvtype, &last_recv_cnt);
    19106:  230:                    curr_cnt += last_recv_cnt;
        -:  231:                }
        -:  232:                
        -:  233:                /* if some processes in this process's subtree in this step
        -:  234:                   did not have any destination process to communicate with
        -:  235:                   because of non-power-of-two, we need to send them the
        -:  236:                   data that they would normally have received from those
        -:  237:                   processes. That is, the haves in this subtree must send to
        -:  238:                   the havenots. We use a logarithmic
        -:  239:                   recursive-halfing algorithm for this. */
        -:  240:                
        -:  241:                /* This part of the code will not currently be
        -:  242:                 executed because we are not using recursive
        -:  243:                 doubling for non power of two. Mark it as experimental
        -:  244:                 so that it doesn't show up as red in the coverage
        -:  245:                 tests. */  
        -:  246:
        -:  247:		/* --BEGIN EXPERIMENTAL-- */
    19106:  248:                if (dst_tree_root + mask > comm_size) {
    #####:  249:                    nprocs_completed = comm_size - my_tree_root - mask;
        -:  250:                    /* nprocs_completed is the number of processes in this
        -:  251:                       subtree that have all the data. Send data to others
        -:  252:                       in a tree fashion. First find root of current tree
        -:  253:                       that is being divided into two. k is the number of
        -:  254:                       least-significant bits in this process's rank that
        -:  255:                       must be zeroed out to find the rank of the root */ 
    #####:  256:                    j = mask;
    #####:  257:                    k = 0;
    #####:  258:                    while (j) {
    #####:  259:                        j >>= 1;
    #####:  260:                        k++;
        -:  261:                    }
    #####:  262:                    k--;
        -:  263:                    
    #####:  264:                    tmp_mask = mask >> 1;
        -:  265:                    
    #####:  266:                    while (tmp_mask) {
    #####:  267:                        dst = rank ^ tmp_mask;
        -:  268:                        
    #####:  269:                        tree_root = rank >> k;
    #####:  270:                        tree_root <<= k;
        -:  271:                        
        -:  272:                        /* send only if this proc has data and destination
        -:  273:                           doesn't have data. at any step, multiple processes
        -:  274:                           can send if they have the data */
    #####:  275:                        if ((dst > rank) && 
        -:  276:                            (rank < tree_root + nprocs_completed)
        -:  277:                            && (dst >= tree_root + nprocs_completed)) {
        -:  278:
    #####:  279:                            offset = 0;
    #####:  280:                            for (j=0; j<(my_tree_root+mask); j++)
    #####:  281:                                offset += recvcounts[j];
    #####:  282:                            offset *= recvtype_extent;
        -:  283:
    #####:  284:                            mpi_errno = MPIC_Send(((char *)tmp_buf + offset),
        -:  285:                                                  last_recv_cnt,
        -:  286:                                                  recvtype, dst,
        -:  287:                                                  MPIR_ALLGATHERV_TAG, comm); 
        -:  288:                            /* last_recv_cnt was set in the previous
        -:  289:                               receive. that's the amount of data to be
        -:  290:                               sent now. */
        -:  291:			    /* --BEGIN ERROR HANDLING-- */
    #####:  292:                            if (mpi_errno)
        -:  293:			    {
    #####:  294:				mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  295:				return mpi_errno;
        -:  296:			    }
        -:  297:			    /* --END ERROR HANDLING-- */
        -:  298:                        }
        -:  299:                        /* recv only if this proc. doesn't have data and sender
        -:  300:                           has data */
    #####:  301:                        else if ((dst < rank) && 
        -:  302:                                 (dst < tree_root + nprocs_completed) &&
        -:  303:                                 (rank >= tree_root + nprocs_completed)) {
        -:  304:
    #####:  305:                            offset = 0;
    #####:  306:                            for (j=0; j<(my_tree_root+mask); j++)
    #####:  307:                                offset += recvcounts[j];
        -:  308:
    #####:  309:                            mpi_errno = MPIC_Recv(((char *)tmp_buf + offset * recvtype_extent),
        -:  310:                                                  total_count - offset, recvtype,
        -:  311:                                                  dst, MPIR_ALLGATHERV_TAG,
        -:  312:                                                  comm, &status);
        -:  313:			    /* --BEGIN ERROR HANDLING-- */
    #####:  314:                            if (mpi_errno)
        -:  315:			    {
    #####:  316:				mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  317:				return mpi_errno;
        -:  318:			    }
        -:  319:			    /* --END ERROR HANDLING-- */
        -:  320:                            /* for convenience, recv is posted for a
        -:  321:                               bigger amount than will be sent */ 
        -:  322:                            
    #####:  323:                            NMPI_Get_count(&status, recvtype, &last_recv_cnt);
    #####:  324:                            curr_cnt += last_recv_cnt;
        -:  325:                        }
    #####:  326:                        tmp_mask >>= 1;
    #####:  327:                        k--;
        -:  328:                    }
        -:  329:                }
        -:  330:		/* --END EXPERIMENTAL-- */
        -:  331:                
    19106:  332:                mask <<= 1;
    19106:  333:                i++;
        -:  334:            }
        -:  335:
        -:  336:            /* copy data from tmp_buf to recvbuf */
    11130:  337:            position = 0;
    50682:  338:            for (j=0; j<comm_size; j++) {
    39552:  339:                if ((sendbuf != MPI_IN_PLACE) || (j != rank)) {
        -:  340:                    /* not necessary to copy if in_place and
        -:  341:                       j==rank. otherwise copy. */
    39448:  342:                    MPIR_Localcopy(((char *)tmp_buf + position*recvtype_extent),
        -:  343:                                   recvcounts[j], recvtype,
        -:  344:                                   ((char *)recvbuf + displs[j]*recvtype_extent),
        -:  345:                                   recvcounts[j], recvtype);
        -:  346:                }
    39552:  347:                position += recvcounts[j];
        -:  348:            }
        -:  349:
    11130:  350:            MPIU_Free((char *)tmp_buf+recvtype_true_lb); 
        -:  351:        }
        -:  352:        
        -:  353:#ifdef MPID_HAS_HETERO
        -:  354:        else {
        -:  355:            /* heterogeneous. need to use temp. buffer. */
        -:  356:            NMPI_Pack_size(total_count, recvtype, comm, &tmp_buf_size);
        -:  357:            tmp_buf = MPIU_Malloc(tmp_buf_size);
        -:  358:	    /* --BEGIN ERROR HANDLING-- */
        -:  359:            if (!tmp_buf)
        -:  360:	    {
        -:  361:                mpi_errno = MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**nomem", 0);
        -:  362:                return mpi_errno;
        -:  363:            }
        -:  364:	    /* --END ERROR HANDLING-- */
        -:  365:            
        -:  366:            /* calculate the value of nbytes, the number of bytes in packed
        -:  367:               representation corresponding to a single recvtype. Since
        -:  368:               MPI_Pack_size returns only an upper bound on 
        -:  369:               the size, to get the real size we actually pack some data
        -:  370:               into tmp_buf and see by how much 'position' is incremented. */
        -:  371:            
        -:  372:            position = 0;
        -:  373:            NMPI_Pack(recvbuf, 1, recvtype, tmp_buf, tmp_buf_size,
        -:  374:                      &position, comm);
        -:  375:            nbytes = position;
        -:  376:            
        -:  377:            /* pack local data into right location in tmp_buf */
        -:  378:            position = 0;
        -:  379:            for (i=0; i<rank; i++) position += recvcounts[i];
        -:  380:            position *= nbytes;
        -:  381:            
        -:  382:            if (sendbuf != MPI_IN_PLACE) {
        -:  383:                NMPI_Pack(sendbuf, sendcount, sendtype, tmp_buf,
        -:  384:                          tmp_buf_size, &position, comm);
        -:  385:            }
        -:  386:            else {
        -:  387:                /* if in_place specified, local data is found in recvbuf */ 
        -:  388:                NMPI_Pack(((char *)recvbuf + displs[rank]*recvtype_extent), 
        -:  389:                          recvcounts[rank], recvtype, tmp_buf,
        -:  390:                          tmp_buf_size, &position, comm);
        -:  391:            }
        -:  392:            
        -:  393:            curr_cnt = recvcounts[rank]*nbytes;
        -:  394:            
        -:  395:            mask = 0x1;
        -:  396:            i = 0;
        -:  397:            while (mask < comm_size) {
        -:  398:                dst = rank ^ mask;
        -:  399:                
        -:  400:                /* find offset into send and recv buffers. zero out 
        -:  401:                   the least significant "i" bits of rank and dst to 
        -:  402:                   find root of src and dst subtrees. Use ranks of 
        -:  403:                   roots as index to send from and recv into buffer. */ 
        -:  404:                
        -:  405:                dst_tree_root = dst >> i;
        -:  406:                dst_tree_root <<= i;
        -:  407:                
        -:  408:                my_tree_root = rank >> i;
        -:  409:                my_tree_root <<= i;
        -:  410:                
        -:  411:                send_offset = 0;
        -:  412:                for (j=0; j<my_tree_root; j++)
        -:  413:                    send_offset += recvcounts[j];
        -:  414:                send_offset *= nbytes;
        -:  415:                
        -:  416:                recv_offset = 0;
        -:  417:                for (j=0; j<dst_tree_root; j++)
        -:  418:                    recv_offset += recvcounts[j];
        -:  419:                recv_offset *= nbytes;
        -:  420:                
        -:  421:                if (dst < comm_size) {
        -:  422:                    mpi_errno = MPIC_Sendrecv(((char *)tmp_buf + send_offset),
        -:  423:                                              curr_cnt, MPI_BYTE, dst,
        -:  424:                                              MPIR_ALLGATHERV_TAG,  
        -:  425:                                              ((char *)tmp_buf + recv_offset),
        -:  426:                                              tmp_buf_size-recv_offset, MPI_BYTE, dst,
        -:  427:                                              MPIR_ALLGATHERV_TAG, comm, &status);
        -:  428:                    /* for convenience, recv is posted for a bigger amount
        -:  429:                       than will be sent */ 
        -:  430:		    /* --BEGIN ERROR HANDLING-- */
        -:  431:                    if (mpi_errno)
        -:  432:		    {
        -:  433:			mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
        -:  434:			return mpi_errno;
        -:  435:		    }
        -:  436:		    /* --END ERROR HANDLING-- */
        -:  437:                    
        -:  438:                    NMPI_Get_count(&status, MPI_BYTE, &last_recv_cnt);
        -:  439:                    curr_cnt += last_recv_cnt;
        -:  440:                }
        -:  441:                
        -:  442:                /* if some processes in this process's subtree in this step
        -:  443:                   did not have any destination process to communicate with
        -:  444:                   because of non-power-of-two, we need to send them the
        -:  445:                   data that they would normally have received from those
        -:  446:                   processes. That is, the haves in this subtree must send to
        -:  447:                   the havenots. We use a logarithmic recursive-halfing algorithm
        -:  448:                   for this. */
        -:  449:                
        -:  450:                if (dst_tree_root + mask > comm_size) {
        -:  451:                    nprocs_completed = comm_size - my_tree_root - mask;
        -:  452:                    /* nprocs_completed is the number of processes in this
        -:  453:                       subtree that have all the data. Send data to others
        -:  454:                       in a tree fashion. First find root of current tree
        -:  455:                       that is being divided into two. k is the number of
        -:  456:                       least-significant bits in this process's rank that
        -:  457:                       must be zeroed out to find the rank of the root */ 
        -:  458:                    j = mask;
        -:  459:                    k = 0;
        -:  460:                    while (j) {
        -:  461:                        j >>= 1;
        -:  462:                        k++;
        -:  463:                    }
        -:  464:                    k--;
        -:  465:                    
        -:  466:                    offset = 0;
        -:  467:                    for (j=0; j<(my_tree_root+mask); j++)
        -:  468:                        offset += recvcounts[j];
        -:  469:                    offset *= nbytes;
        -:  470:                    tmp_mask = mask >> 1;
        -:  471:                    
        -:  472:                    while (tmp_mask) {
        -:  473:                        dst = rank ^ tmp_mask;
        -:  474:                        
        -:  475:                        tree_root = rank >> k;
        -:  476:                        tree_root <<= k;
        -:  477:                        
        -:  478:                        /* send only if this proc has data and destination
        -:  479:                           doesn't have data. at any step, multiple processes
        -:  480:                           can send if they have the data */
        -:  481:                        if ((dst > rank) && 
        -:  482:                            (rank < tree_root + nprocs_completed)
        -:  483:                            && (dst >= tree_root + nprocs_completed)) {
        -:  484:                            
        -:  485:                            mpi_errno = MPIC_Send(((char *)tmp_buf + offset),
        -:  486:                                                  last_recv_cnt, MPI_BYTE,
        -:  487:                                                  dst, MPIR_ALLGATHERV_TAG,
        -:  488:                                                  comm);  
        -:  489:                            /* last_recv_cnt was set in the previous
        -:  490:                               receive. that's the amount of data to be
        -:  491:                               sent now. */
        -:  492:			    /* --BEGIN ERROR HANDLING-- */
        -:  493:                            if (mpi_errno)
        -:  494:			    {
        -:  495:				mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
        -:  496:				return mpi_errno;
        -:  497:			    }
        -:  498:			    /* --END ERROR HANDLING-- */
        -:  499:                        }
        -:  500:                        /* recv only if this proc. doesn't have data and sender
        -:  501:                           has data */
        -:  502:                        else if ((dst < rank) && 
        -:  503:                                 (dst < tree_root + nprocs_completed) &&
        -:  504:                                 (rank >= tree_root + nprocs_completed)) {
        -:  505:                            mpi_errno = MPIC_Recv(((char *)tmp_buf + offset),
        -:  506:                                                  tmp_buf_size-offset, MPI_BYTE,
        -:  507:                                                  dst,
        -:  508:                                                  MPIR_ALLGATHERV_TAG,
        -:  509:                                                  comm, &status); 
        -:  510:                            /* for convenience, recv is posted for a bigger amount
        -:  511:                               than will be sent */ 
        -:  512:			    /* --BEGIN ERROR HANDLING-- */
        -:  513:                            if (mpi_errno)
        -:  514:			    {
        -:  515:				mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
        -:  516:				return mpi_errno;
        -:  517:			    }
        -:  518:			    /* --END ERROR HANDLING-- */
        -:  519:                            NMPI_Get_count(&status, MPI_BYTE, &last_recv_cnt);
        -:  520:                            curr_cnt += last_recv_cnt;
        -:  521:                        }
        -:  522:                        tmp_mask >>= 1;
        -:  523:                        k--;
        -:  524:                    }
        -:  525:                }
        -:  526:                mask <<= 1;
        -:  527:                i++;
        -:  528:            }
        -:  529:        
        -:  530:            position = 0;
        -:  531:            for (j=0; j<comm_size; j++) {
        -:  532:                if ((sendbuf != MPI_IN_PLACE) || (j != rank)) {
        -:  533:                    /* not necessary to unpack if in_place and
        -:  534:                       j==rank. otherwise unpack. */
        -:  535:                    NMPI_Unpack(tmp_buf, tmp_buf_size, &position, 
        -:  536:                                ((char *)recvbuf + displs[j]*recvtype_extent),
        -:  537:                                recvcounts[j], recvtype, comm);
        -:  538:                }
        -:  539:            }
        -:  540:            
        -:  541:            MPIU_Free(tmp_buf);
        -:  542:        }
        -:  543:#endif /* MPID_HAS_HETERO */
        -:  544:
        -:  545:    }
        -:  546:
     5602:  547:    else if (total_count*recvtype_size < MPIR_ALLGATHER_SHORT_MSG) {
        -:  548:        /* Short message and non-power-of-two no. of processes. Use
        -:  549:         * Bruck algorithm (see description above). */
        -:  550: 
        -:  551:        /* allocate a temporary buffer of the same size as recvbuf. */
        -:  552:
        -:  553:        /* get true extent of recvtype */
     4024:  554:        mpi_errno = NMPI_Type_get_true_extent(recvtype, 
        -:  555:                                              &recvtype_true_lb,
        -:  556:                                              &recvtype_true_extent);
        -:  557:        /* --BEGIN ERROR HANDLING-- */
     4024:  558:        if (mpi_errno)
        -:  559:	{
    #####:  560:	    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  561:	    return mpi_errno;
        -:  562:	}
        -:  563:        /* --END ERROR HANDLING-- */
        -:  564:            
        -:  565:        MPID_Ensure_Aint_fits_in_pointer(total_count *
        -:  566:                        MPIR_MAX(recvtype_true_extent, recvtype_extent));
     4024:  567:        recvbuf_extent = total_count *
        -:  568:            (MPIR_MAX(recvtype_true_extent, recvtype_extent));
        -:  569:
     4024:  570:        tmp_buf = MPIU_Malloc(recvbuf_extent);
        -:  571:        /* --BEGIN ERROR HANDLING-- */
     4024:  572:        if (!tmp_buf) {
    #####:  573:            mpi_errno = MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**nomem", 0 );
    #####:  574:            return mpi_errno;
        -:  575:        }
        -:  576:	/* --END ERROR HANDLING-- */
        -:  577:            
        -:  578:        /* adjust for potential negative lower bound in datatype */
     4024:  579:        tmp_buf = (void *)((char*)tmp_buf - recvtype_true_lb);
        -:  580:
        -:  581:        /* copy local data to the top of tmp_buf */ 
     4024:  582:        if (sendbuf != MPI_IN_PLACE) {
     3427:  583:            mpi_errno = MPIR_Localcopy (sendbuf, sendcount, sendtype,
        -:  584:                                        tmp_buf, recvcounts[rank], recvtype);
        -:  585:	    /* --BEGIN ERROR HANDLING-- */
     3427:  586:            if (mpi_errno)
        -:  587:	    {
    #####:  588:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  589:		return mpi_errno;
        -:  590:	    }
        -:  591:	    /* --END ERROR HANDLING-- */
        -:  592:        }
        -:  593:        else {
      597:  594:            mpi_errno = MPIR_Localcopy(((char *)recvbuf +
        -:  595:                                        displs[rank]*recvtype_extent), 
        -:  596:                                       recvcounts[rank], recvtype,
        -:  597:                                       tmp_buf, recvcounts[rank], recvtype);
        -:  598:	    /* --BEGIN ERROR HANDLING-- */
      597:  599:            if (mpi_errno)
        -:  600:	    {
    #####:  601:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  602:		return mpi_errno;
        -:  603:	    }
        -:  604:	    /* --END ERROR HANDLING-- */
        -:  605:        }
        -:  606:        
        -:  607:        /* do the first \floor(\lg p) steps */
        -:  608:
     4024:  609:        curr_cnt = recvcounts[rank];
     4024:  610:        pof2 = 1;
    14080:  611:        while (pof2 <= comm_size/2) {
     6032:  612:            src = (rank + pof2) % comm_size;
     6032:  613:            dst = (rank - pof2 + comm_size) % comm_size;
        -:  614:            
     6032:  615:            mpi_errno = MPIC_Sendrecv(tmp_buf, curr_cnt, recvtype, dst,
        -:  616:                                      MPIR_ALLGATHERV_TAG,
        -:  617:                                  ((char *)tmp_buf + curr_cnt*recvtype_extent),
        -:  618:                                      total_count - curr_cnt, recvtype,
        -:  619:                                      src, MPIR_ALLGATHERV_TAG, comm, &status);
        -:  620:	    /* --BEGIN ERROR HANDLING-- */
     6032:  621:            if (mpi_errno)
        -:  622:	    {
    #####:  623:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  624:		return mpi_errno;
        -:  625:	    }
        -:  626:	    /* --END ERROR HANDLING-- */
        -:  627:
     6032:  628:            NMPI_Get_count(&status, recvtype, &recv_cnt);
     6032:  629:            curr_cnt += recv_cnt;
        -:  630:
     6032:  631:            pof2 *= 2;
        -:  632:        }
        -:  633:
        -:  634:        /* if comm_size is not a power of two, one more step is needed */
        -:  635:
     4024:  636:        rem = comm_size - pof2;
     4024:  637:        if (rem) {
     4024:  638:            src = (rank + pof2) % comm_size;
     4024:  639:            dst = (rank - pof2 + comm_size) % comm_size;
        -:  640:
     4024:  641:            send_cnt = 0;
     9094:  642:            for (i=0; i<rem; i++)
     5070:  643:                send_cnt += recvcounts[(rank+i)%comm_size];
        -:  644:
     4024:  645:            mpi_errno = MPIC_Sendrecv(tmp_buf, send_cnt, recvtype,
        -:  646:                                      dst, MPIR_ALLGATHERV_TAG,
        -:  647:                                  ((char *)tmp_buf + curr_cnt*recvtype_extent),
        -:  648:                                      total_count - curr_cnt, recvtype,
        -:  649:                                      src, MPIR_ALLGATHERV_TAG, comm,
        -:  650:                                      MPI_STATUS_IGNORE);
        -:  651:	    /* --BEGIN ERROR HANDLING-- */
     4024:  652:            if (mpi_errno)
        -:  653:	    {
    #####:  654:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  655:		return mpi_errno;
        -:  656:	    }
        -:  657:	    /* --END ERROR HANDLING-- */
        -:  658:        }
        -:  659:
        -:  660:        /* Rotate blocks in tmp_buf down by (rank) blocks and store
        -:  661:         * result in recvbuf. */
        -:  662:
     4024:  663:        send_cnt = 0;
    15401:  664:        for (i=0; i < (comm_size-rank); i++) {
    11377:  665:            j = (rank+i)%comm_size;
    11377:  666:            mpi_errno = MPIR_Localcopy((char *)tmp_buf + send_cnt*recvtype_extent, 
        -:  667:                                       recvcounts[j], recvtype, 
        -:  668:                                  (char *)recvbuf + displs[j]*recvtype_extent, 
        -:  669:                                       recvcounts[j], recvtype);
        -:  670:	    /* --BEGIN ERROR HANDLING-- */
    11377:  671:            if (mpi_errno)
        -:  672:	    {
    #####:  673:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  674:		return mpi_errno;
        -:  675:	    }
        -:  676:	    /* --END ERROR HANDLING-- */
    11377:  677:            send_cnt += recvcounts[j];
        -:  678:        }
        -:  679:
    11377:  680:        for (i=0; i<rank; i++) {
     7353:  681:            mpi_errno = MPIR_Localcopy((char *)tmp_buf + send_cnt*recvtype_extent, 
        -:  682:                                       recvcounts[i], recvtype, 
        -:  683:                                  (char *)recvbuf + displs[i]*recvtype_extent, 
        -:  684:                                       recvcounts[i], recvtype);
        -:  685:	    /* --BEGIN ERROR HANDLING-- */
     7353:  686:            if (mpi_errno)
        -:  687:	    {
    #####:  688:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  689:		return mpi_errno;
        -:  690:	    }
        -:  691:	    /* --END ERROR HANDLING-- */
     7353:  692:            send_cnt += recvcounts[i];
        -:  693:        }
        -:  694:
     4024:  695:        MPIU_Free((char*)tmp_buf + recvtype_true_lb);
        -:  696:    }
        -:  697:    else {
        -:  698:	/* long message or medium-size message and non-power-of-two
        -:  699:	 * no. of processes. Use ring algorithm. */
     1578:  700:	char * sbuf = NULL, * rbuf = NULL;
        -:  701:        int soffset, roffset;
        -:  702:	int torecv, tosend, min;
        -:  703:	int sendnow, recvnow;
        -:  704:	int sindex, rindex;
        -:  705:
     1578:  706:        if (sendbuf != MPI_IN_PLACE) {
        -:  707:            /* First, load the "local" version in the recvbuf. */
     1369:  708:            mpi_errno = MPIR_Localcopy(sendbuf, sendcount, sendtype, 
        -:  709:				       ((char *)recvbuf + displs[rank]*recvtype_extent),
        -:  710:                                       recvcounts[rank], recvtype);
        -:  711:	    /* --BEGIN ERROR HANDLING-- */
     1369:  712:            if (mpi_errno)
        -:  713:	    {
    #####:  714:		mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  715:		return mpi_errno;
        -:  716:	    }
        -:  717:	    /* --END ERROR HANDLING-- */
        -:  718:        }
        -:  719:
     1578:  720:        left  = (comm_size + rank - 1) % comm_size;
     1578:  721:        right = (rank + 1) % comm_size;
        -:  722:
     1578:  723:	torecv = total_count - recvcounts[rank];
     1578:  724:	tosend = total_count - recvcounts[right];
        -:  725:
     1578:  726:	min = recvcounts[0];
     7714:  727:	for (i = 1; i < comm_size; i++)
     6136:  728:	    if (min > recvcounts[i])
     1320:  729:                min = recvcounts[i];
     1578:  730:	if (min * recvtype_extent < MPIR_ALLGATHERV_PIPELINE_MSGSIZE)
      714:  731:	    min = MPIR_ALLGATHERV_PIPELINE_MSGSIZE / recvtype_extent;
        -:  732:        /* Handle the case where the datatype extent is larger than
        -:  733:         * the pipeline size. */
     1578:  734:        if (!min)
    #####:  735:            min = 1;
        -:  736:
     1578:  737:        sindex = rank;
     1578:  738:        rindex = left;
     1578:  739:        soffset = 0;
     1578:  740:        roffset = 0;
    17132:  741:        while (tosend || torecv) { /* While we have data to send or receive */
    13976:  742:            sendnow = ((recvcounts[sindex] - soffset) > min) ? min : (recvcounts[sindex] - soffset);
    13976:  743:            recvnow = ((recvcounts[rindex] - roffset) > min) ? min : (recvcounts[rindex] - roffset);
    13976:  744:            sbuf = (char *)recvbuf + ((displs[sindex] + soffset) * recvtype_extent);
    13976:  745:            rbuf = (char *)recvbuf + ((displs[rindex] + roffset) * recvtype_extent);
        -:  746:
        -:  747:            /* Protect against wrap-around of indices */
    13976:  748:            if (!tosend)
     1710:  749:                sendnow = 0;
    13976:  750:            if (!torecv)
     1710:  751:                recvnow = 0;
        -:  752:
        -:  753:	    /* Communicate */
    13976:  754:	    if (!sendnow && !recvnow) {
        -:  755:		/* Don't do anything. This case is possible if two
        -:  756:		 * consecutive processes contribute 0 bytes each. */
        -:  757:	    }
    13886:  758:	    else if (!sendnow) { /* If there's no data to send, just do a recv call */
     1870:  759:		mpi_errno = MPIC_Recv(rbuf, recvnow, recvtype, left, MPIR_ALLGATHERV_TAG, comm, &status);
        -:  760:		/* --BEGIN ERROR HANDLING-- */
     1870:  761:		if (mpi_errno)
        -:  762:		{
    #####:  763:		    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  764:		    return mpi_errno;
        -:  765:		}
        -:  766:		/* --END ERROR HANDLING-- */
     1870:  767:		torecv -= recvnow;
        -:  768:	    }
    12016:  769:	    else if (!recvnow) { /* If there's no data to receive, just do a send call */
     1870:  770:		mpi_errno = MPIC_Send(sbuf, sendnow, recvtype, right, MPIR_ALLGATHERV_TAG, comm);
        -:  771:		/* --BEGIN ERROR HANDLING-- */
     1870:  772:		if (mpi_errno)
        -:  773:		{
    #####:  774:		    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  775:		    return mpi_errno;
        -:  776:		}
        -:  777:		/* --END ERROR HANDLING-- */
     1870:  778:		tosend -= sendnow;
        -:  779:	    }
        -:  780:	    else { /* There's data to be sent and received */
    10146:  781:		mpi_errno = MPIC_Sendrecv(sbuf, sendnow, recvtype, right, MPIR_ALLGATHERV_TAG, 
        -:  782:					  rbuf, recvnow, recvtype, left, MPIR_ALLGATHERV_TAG,
        -:  783:					  comm, &status);
        -:  784:		/* --BEGIN ERROR HANDLING-- */
    10146:  785:		if (mpi_errno)
        -:  786:		{
    #####:  787:		    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  788:		    return mpi_errno;
        -:  789:		}
        -:  790:		/* --END ERROR HANDLING-- */
    10146:  791:		tosend -= sendnow;
    10146:  792:		torecv -= recvnow;
        -:  793:	    }
        -:  794:
    13976:  795:            soffset += sendnow;
    13976:  796:            roffset += recvnow;
    13976:  797:            if (soffset == recvcounts[sindex]) {
     5986:  798:                soffset = 0;
     5986:  799:                sindex = (sindex + comm_size - 1) % comm_size;
        -:  800:            }
    13976:  801:            if (roffset == recvcounts[rindex]) {
     6136:  802:                roffset = 0;
     6136:  803:                rindex = (rindex + comm_size - 1) % comm_size;
        -:  804:            }
        -:  805:        }
        -:  806:    }
        -:  807:
        -:  808:  /* check if multiple threads are calling this collective function */
        -:  809:    MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr );
        -:  810:
    16732:  811:  return (mpi_errno);
        -:  812:}
        -:  813:/* end:nested */
        -:  814:
        -:  815:/* begin:nested */
        -:  816:/* not declared static because a machine-specific function may call this one in some cases */
        -:  817:int MPIR_Allgatherv_inter ( 
        -:  818:    void *sendbuf, 
        -:  819:    int sendcount,  
        -:  820:    MPI_Datatype sendtype, 
        -:  821:    void *recvbuf, 
        -:  822:    int *recvcounts, 
        -:  823:    int *displs,   
        -:  824:    MPI_Datatype recvtype, 
        -:  825:    MPID_Comm *comm_ptr )
     2880:  826:{
        -:  827:/* Intercommunicator Allgatherv.
        -:  828:   This is done differently from the intercommunicator allgather
        -:  829:   because we don't have all the information to do a local
        -:  830:   intracommunictor gather (sendcount can be different on each
        -:  831:   process). Therefore, we do the following:
        -:  832:   Each group first does an intercommunicator gather to rank 0
        -:  833:   and then does an intracommunicator broadcast. 
        -:  834:*/
        -:  835:    static const char FCNAME[] = "MPIR_Allgatherv_inter";
        -:  836:    int remote_size, mpi_errno, root, rank;
     2880:  837:    MPID_Comm *newcomm_ptr = NULL;
        -:  838:    MPI_Datatype newtype;
        -:  839:
     2880:  840:    remote_size = comm_ptr->remote_size;
     2880:  841:    rank = comm_ptr->rank;
        -:  842:
        -:  843:    /* first do an intercommunicator gatherv from left to right group,
        -:  844:       then from right to left group */
     2880:  845:    if (comm_ptr->is_low_group) {
        -:  846:        /* gatherv from right group */
      992:  847:        root = (rank == 0) ? MPI_ROOT : MPI_PROC_NULL;
      992:  848:        mpi_errno = MPIR_Gatherv(sendbuf, sendcount, sendtype, recvbuf,
        -:  849:                                 recvcounts, displs, recvtype, root,
        -:  850:                                 comm_ptr);
        -:  851:	/* --BEGIN ERROR HANDLING-- */
      992:  852:        if (mpi_errno)
        -:  853:	{
    #####:  854:	    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  855:	    return mpi_errno;
        -:  856:	}
        -:  857:	/* --END ERROR HANDLING-- */
        -:  858:        /* gatherv to right group */
      992:  859:        root = 0;
      992:  860:        mpi_errno = MPIR_Gatherv(sendbuf, sendcount, sendtype, recvbuf,
        -:  861:                                 recvcounts, displs, recvtype, root,
        -:  862:                                 comm_ptr);
        -:  863:	/* --BEGIN ERROR HANDLING-- */
      992:  864:        if (mpi_errno)
        -:  865:	{
    #####:  866:	    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  867:	    return mpi_errno;
        -:  868:	}
        -:  869:	/* --END ERROR HANDLING-- */
        -:  870:    }
        -:  871:    else {
        -:  872:        /* gatherv to left group  */
     1888:  873:        root = 0;
     1888:  874:        mpi_errno = MPIR_Gatherv(sendbuf, sendcount, sendtype, recvbuf,
        -:  875:                                 recvcounts, displs, recvtype, root,
        -:  876:                                 comm_ptr);
        -:  877:	/* --BEGIN ERROR HANDLING-- */
     1888:  878:        if (mpi_errno)
        -:  879:	{
    #####:  880:	    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  881:	    return mpi_errno;
        -:  882:	}
        -:  883:	/* --END ERROR HANDLING-- */
        -:  884:        /* gatherv from left group */
     1888:  885:        root = (rank == 0) ? MPI_ROOT : MPI_PROC_NULL;
     1888:  886:        mpi_errno = MPIR_Gatherv(sendbuf, sendcount, sendtype, recvbuf,
        -:  887:                                 recvcounts, displs, recvtype, root,
        -:  888:                                 comm_ptr);
        -:  889:	/* --BEGIN ERROR HANDLING-- */
     1888:  890:        if (mpi_errno)
        -:  891:	{
    #####:  892:	    mpi_errno = MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**fail", 0);
    #####:  893:	    return mpi_errno;
        -:  894:	}
        -:  895:	/* --END ERROR HANDLING-- */
        -:  896:    }
        -:  897:
        -:  898:    /* now do an intracommunicator broadcast within each group. we use
        -:  899:       a derived datatype to handle the displacements */
        -:  900:
        -:  901:    /* Get the local intracommunicator */
     2880:  902:    if (!comm_ptr->local_comm)
       90:  903:	MPIR_Setup_intercomm_localcomm( comm_ptr );
        -:  904:
     2880:  905:    newcomm_ptr = comm_ptr->local_comm;
        -:  906:
     2880:  907:    NMPI_Type_indexed(remote_size, recvcounts, displs, recvtype,
        -:  908:                      &newtype);
     2880:  909:    NMPI_Type_commit(&newtype);
        -:  910:
     2880:  911:    mpi_errno = MPIR_Bcast(recvbuf, 1, newtype, 0, newcomm_ptr);
        -:  912:
     2880:  913:    NMPI_Type_free(&newtype);
        -:  914:
     2880:  915:    return mpi_errno;
        -:  916:}
        -:  917:/* end:nested */
        -:  918:#endif
        -:  919:
        -:  920:#undef FUNCNAME
        -:  921:#define FUNCNAME MPI_Allgatherv
        -:  922:
        -:  923:/*@
        -:  924:
        -:  925:MPI_Allgatherv - Gathers data from all tasks and deliver the combined data
        -:  926:                 to all tasks
        -:  927:
        -:  928:Input Parameters:
        -:  929:+ sendbuf - starting address of send buffer (choice) 
        -:  930:. sendcount - number of elements in send buffer (integer) 
        -:  931:. sendtype - data type of send buffer elements (handle) 
        -:  932:. recvcounts - integer array (of length group size) 
        -:  933:containing the number of elements that are to be received from each process 
        -:  934:. displs - integer array (of length group size). Entry 
        -:  935: 'i'  specifies the displacement (relative to recvbuf ) at
        -:  936:which to place the incoming data from process  'i'  
        -:  937:. recvtype - data type of receive buffer elements (handle) 
        -:  938:- comm - communicator (handle) 
        -:  939:
        -:  940:Output Parameter:
        -:  941:. recvbuf - address of receive buffer (choice) 
        -:  942:
        -:  943:Notes:
        -:  944: The MPI standard (1.0 and 1.1) says that 
        -:  945:.n
        -:  946:.n
        -:  947: The jth block of data sent from 
        -:  948: each proess is received by every process and placed in the jth block of the 
        -:  949: buffer 'recvbuf'.  
        -:  950:.n
        -:  951:.n
        -:  952: This is misleading; a better description is
        -:  953:.n
        -:  954:.n
        -:  955: The block of data sent from the jth process is received by every
        -:  956: process and placed in the jth block of the buffer 'recvbuf'.
        -:  957:.n
        -:  958:.n
        -:  959: This text was suggested by Rajeev Thakur, and has been adopted as a 
        -:  960: clarification to the MPI standard by the MPI-Forum.
        -:  961:
        -:  962:.N ThreadSafe
        -:  963:
        -:  964:.N Fortran
        -:  965:
        -:  966:.N Errors
        -:  967:.N MPI_ERR_BUFFER
        -:  968:.N MPI_ERR_COUNT
        -:  969:.N MPI_ERR_TYPE
        -:  970:@*/
        -:  971:int MPI_Allgatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype, 
        -:  972:                   void *recvbuf, int *recvcounts, int *displs, 
        -:  973:                   MPI_Datatype recvtype, MPI_Comm comm)
    19814:  974:{
        -:  975:    static const char FCNAME[] = "MPI_Allgatherv";
    19814:  976:    int mpi_errno = MPI_SUCCESS;
    19814:  977:    MPID_Comm *comm_ptr = NULL;
    19814:  978:    MPIU_THREADPRIV_DECL;
        -:  979:    MPID_MPI_STATE_DECL(MPID_STATE_MPI_ALLGATHERV);
        -:  980:
    19814:  981:    MPIR_ERRTEST_INITIALIZED_ORDIE();
        -:  982:    
    19814:  983:    MPIU_THREAD_CS_ENTER(ALLFUNC,);
        -:  984:    MPID_MPI_COLL_FUNC_ENTER(MPID_STATE_MPI_ALLGATHERV);
        -:  985:
        -:  986:    /* Validate parameters, especially handles needing to be converted */
        -:  987:#   ifdef HAVE_ERROR_CHECKING
        -:  988:    {
        -:  989:        MPID_BEGIN_ERROR_CHECKS;
        -:  990:        {
    19814:  991:	    MPIR_ERRTEST_COMM(comm, mpi_errno);
    19814:  992:            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -:  993:	}
        -:  994:        MPID_END_ERROR_CHECKS;
        -:  995:    }
        -:  996:#   endif /* HAVE_ERROR_CHECKING */
        -:  997:
        -:  998:    /* Convert MPI object handles to object pointers */
    19812:  999:    MPID_Comm_get_ptr( comm, comm_ptr );
        -: 1000:
        -: 1001:    /* Validate parameters and objects (post conversion) */
        -: 1002:#   ifdef HAVE_ERROR_CHECKING
        -: 1003:    {
        -: 1004:        MPID_BEGIN_ERROR_CHECKS;
        -: 1005:        {
    19812: 1006:            MPID_Datatype *recvtype_ptr=NULL, *sendtype_ptr=NULL;
        -: 1007:            int i, comm_size;
        -: 1008:	    
    19812: 1009:            MPID_Comm_valid_ptr( comm_ptr, mpi_errno );
    19812: 1010:            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -: 1011:
    19810: 1012:	    if (comm_ptr->comm_kind == MPID_INTERCOMM)
     2880: 1013:                MPIR_ERRTEST_SENDBUF_INPLACE(sendbuf, sendcount, mpi_errno);
    19810: 1014:            if (sendbuf != MPI_IN_PLACE) {
    18900: 1015:                MPIR_ERRTEST_COUNT(sendcount, mpi_errno);
    18900: 1016:                MPIR_ERRTEST_DATATYPE(sendtype, "sendtype", mpi_errno);
    18900: 1017:                if (HANDLE_GET_KIND(sendtype) != HANDLE_KIND_BUILTIN) {
      362: 1018:                    MPID_Datatype_get_ptr(sendtype, sendtype_ptr);
      362: 1019:                    MPID_Datatype_valid_ptr( sendtype_ptr, mpi_errno );
      362: 1020:                    MPID_Datatype_committed_ptr( sendtype_ptr, mpi_errno );
        -: 1021:                }
    18900: 1022:                MPIR_ERRTEST_USERBUFFER(sendbuf,sendcount,sendtype,mpi_errno);
        -: 1023:            }
        -: 1024:
    19810: 1025:            if (comm_ptr->comm_kind == MPID_INTRACOMM) 
    16930: 1026:                comm_size = comm_ptr->local_size;
        -: 1027:            else
     2880: 1028:                comm_size = comm_ptr->remote_size;
        -: 1029:
    93540: 1030:            for (i=0; i<comm_size; i++) {
    73730: 1031:                MPIR_ERRTEST_COUNT(recvcounts[i], mpi_errno);
    73730: 1032:                MPIR_ERRTEST_DATATYPE(recvtype, "recvtype", mpi_errno);
        -: 1033:            }
        -: 1034:
    19810: 1035:            if (HANDLE_GET_KIND(recvtype) != HANDLE_KIND_BUILTIN) {
      360: 1036:                MPID_Datatype_get_ptr(recvtype, recvtype_ptr);
      360: 1037:                MPID_Datatype_valid_ptr( recvtype_ptr, mpi_errno );
      360: 1038:                MPID_Datatype_committed_ptr( recvtype_ptr, mpi_errno );
        -: 1039:            }
    22238: 1040:            for (i=0; i<comm_size; i++) {
    21100: 1041:                if (recvcounts[i] > 0) {
    18672: 1042:                    MPIR_ERRTEST_RECVBUF_INPLACE(recvbuf,recvcounts[i],mpi_errno);
    18672: 1043:                    MPIR_ERRTEST_USERBUFFER(recvbuf,recvcounts[i],recvtype,mpi_errno); 
        -: 1044:                    break;
        -: 1045:                }
        -: 1046:            }
        -: 1047:
    19810: 1048:	    if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -: 1049:        }
        -: 1050:        MPID_END_ERROR_CHECKS;
        -: 1051:    }
        -: 1052:#   endif /* HAVE_ERROR_CHECKING */
        -: 1053:
        -: 1054:    /* ... body of routine ...  */
        -: 1055:
    19806: 1056:    if (comm_ptr->coll_fns != NULL && comm_ptr->coll_fns->Allgatherv != NULL)
        -: 1057:    {
    #####: 1058:	mpi_errno = comm_ptr->coll_fns->Allgatherv(sendbuf, sendcount,
        -: 1059:                                                   sendtype, recvbuf,
        -: 1060:                                                   recvcounts, displs,
        -: 1061:                                                   recvtype, comm_ptr);
        -: 1062:    }
        -: 1063:    else
        -: 1064:    {
    19806: 1065:	MPIU_THREADPRIV_GET;
        -: 1066:
    19806: 1067:	MPIR_Nest_incr();
    19806: 1068:        if (comm_ptr->comm_kind == MPID_INTRACOMM) 
        -: 1069:            /* intracommunicator */
    16926: 1070:            mpi_errno = MPIR_Allgatherv(sendbuf, sendcount, 
        -: 1071:                                        sendtype, recvbuf,
        -: 1072:                                        recvcounts, displs,
        -: 1073:                                        recvtype, comm_ptr); 
        -: 1074:        else {
        -: 1075:            /* intracommunicator */
     2880: 1076:            mpi_errno = MPIR_Allgatherv_inter(sendbuf, sendcount, 
        -: 1077:					      sendtype, recvbuf,
        -: 1078:					      recvcounts, displs,
        -: 1079:					      recvtype, comm_ptr); 
        -: 1080:        }
    19806: 1081:	MPIR_Nest_decr();
        -: 1082:    }
        -: 1083:
    19806: 1084:    if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -: 1085:
        -: 1086:    /* ... end of body of routine ... */
        -: 1087:
    19814: 1088:  fn_exit:
        -: 1089:    MPID_MPI_COLL_FUNC_EXIT(MPID_STATE_MPI_ALLGATHERV);
    19814: 1090:    MPIU_THREAD_CS_EXIT(ALLFUNC,);
    19814: 1091:    return mpi_errno;
        -: 1092:
        8: 1093:  fn_fail:
        -: 1094:    /* --BEGIN ERROR HANDLING-- */
        -: 1095:#   ifdef HAVE_ERROR_CHECKING
        -: 1096:    {
        8: 1097:	mpi_errno = MPIR_Err_create_code(
        -: 1098:	    mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_allgatherv",
        -: 1099:	    "**mpi_allgatherv %p %d %D %p %p %p %D %C", sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm);
        -: 1100:    }
        -: 1101:#   endif
        8: 1102:    mpi_errno = MPIR_Err_return_comm( comm_ptr, FCNAME, mpi_errno );
        8: 1103:    goto fn_exit;
        -: 1104:    /* --END ERROR HANDLING-- */
        -: 1105:}