-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpi/datatype/get_elements.c
        -:    0:Graph:get_elements.gcno
        -:    0:Data:get_elements.gcda
        -:    0:Runs:528
        -:    0:Programs:148
        -:    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_Get_elements */
        -:   11:#if defined(HAVE_PRAGMA_WEAK)
        -:   12:#pragma weak MPI_Get_elements = PMPI_Get_elements
        -:   13:#elif defined(HAVE_PRAGMA_HP_SEC_DEF)
        -:   14:#pragma _HP_SECONDARY_DEF PMPI_Get_elements  MPI_Get_elements
        -:   15:#elif defined(HAVE_PRAGMA_CRI_DUP)
        -:   16:#pragma _CRI duplicate MPI_Get_elements as PMPI_Get_elements
        -:   17:#endif
        -:   18:/* -- End Profiling Symbol Block */
        -:   19:
        -:   20:#ifndef MIN
        -:   21:#define MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b))
        -:   22:#endif
        -:   23:
        -:   24:PMPI_LOCAL int MPIR_Type_get_basic_type_elements(int *bytes_p,
        -:   25:						 int count,
        -:   26:						 MPI_Datatype datatype);
        -:   27:PMPI_LOCAL int MPIR_Type_get_elements(int *bytes_p,
        -:   28:				      int count,
        -:   29:				      MPI_Datatype datatype);
        -:   30:
        -:   31:/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
        -:   32:   the MPI routines */
        -:   33:#ifndef MPICH_MPI_FROM_PMPI
        -:   34:#undef MPI_Get_elements
        -:   35:#define MPI_Get_elements PMPI_Get_elements
        -:   36:
        -:   37:/* Note that all helper routines must be within the
        -:   38: * MPICH_MPI_FROM_PMPI ifdef so that we don't get two copies of the
        -:   39: * helper routines in the case where we don't have weak symbols. */
        -:   40:
        -:   41:/* MPIR_Type_get_basic_type_elements()
        -:   42: *
        -:   43: * Arguments:
        -:   44: * - bytes_p - input/output byte count
        -:   45: * - count - maximum number of this type to subtract from the bytes; a count
        -:   46: *           of -1 indicates use as many as we like
        -:   47: * - datatype - input datatype
        -:   48: *
        -:   49: * Returns number of elements available given the two constraints of number of
        -:   50: * bytes and count of types.  Also reduces the byte count by the amount taken
        -:   51: * up by the types.
        -:   52: *
        -:   53: * Assumptions:
        -:   54: * - the type passed to this function must be a basic *or* a pairtype
        -:   55: *   (which aren't basic types)
        -:   56: * - the count is not zero (otherwise we can't tell between a "no more
        -:   57: *   complete types" case and a "zero count" case)
        -:   58: *
        -:   59: * As per section 4.9.3 of the MPI 1.1 specification, the two-part reduction
        -:   60: * types are to be treated as structs of the constituent types.  So we have to
        -:   61: * do something special to handle them correctly in here.
        -:   62: *
        -:   63: * As per section 3.12.5 get_count and get_elements report the same value for
        -:   64: * basic datatypes; I'm currently interpreting this to *not* include these
        -:   65: * reduction types, as they are considered structs.
        -:   66: */
        -:   67:PMPI_LOCAL int MPIR_Type_get_basic_type_elements(int *bytes_p,
        -:   68:						 int count,
        -:   69:						 MPI_Datatype datatype)
     2359:   70:{
        -:   71:    int elements, usable_bytes, used_bytes, type1_sz, type2_sz;
        -:   72:
     2359:   73:    if (count == 0) return 0;
        -:   74:
        -:   75:    /* determine the maximum number of bytes we should take from the
        -:   76:     * byte count.
        -:   77:     */
     2359:   78:    if (count < 0) {
     2351:   79:	usable_bytes = *bytes_p;
        -:   80:    }
        -:   81:    else {
        8:   82:	usable_bytes = MIN(*bytes_p,
        -:   83:			   count * MPID_Datatype_get_basic_size(datatype));
        -:   84:    }
        -:   85:
     2359:   86:    switch (datatype) {
        -:   87:	/* we don't get valid fortran datatype handles in all cases... */
        -:   88:#ifdef HAVE_FORTRAN_BINDING
        -:   89:	case MPI_2REAL:
    #####:   90: 	    type1_sz = type2_sz = MPID_Datatype_get_basic_size(MPI_REAL);
    #####:   91:	    break;
        -:   92:	case MPI_2DOUBLE_PRECISION:
    #####:   93: 	    type1_sz = type2_sz =
        -:   94:		MPID_Datatype_get_basic_size(MPI_DOUBLE_PRECISION);
    #####:   95:	    break;
        -:   96:	case MPI_2INTEGER:
    #####:   97: 	    type1_sz = type2_sz = MPID_Datatype_get_basic_size(MPI_INTEGER);
    #####:   98:	    break;
        -:   99:#endif
        -:  100:	case MPI_2INT:
    #####:  101: 	    type1_sz = type2_sz = MPID_Datatype_get_basic_size(MPI_INT);
    #####:  102:	    break;
        -:  103:	case MPI_FLOAT_INT:
    #####:  104:	    type1_sz = MPID_Datatype_get_basic_size(MPI_FLOAT);
    #####:  105:	    type2_sz = MPID_Datatype_get_basic_size(MPI_INT);
    #####:  106:	    break;
        -:  107:	case MPI_DOUBLE_INT:
        1:  108:	    type1_sz = MPID_Datatype_get_basic_size(MPI_DOUBLE);
        1:  109:	    type2_sz = MPID_Datatype_get_basic_size(MPI_INT);
        1:  110:	    break;
        -:  111:	case MPI_LONG_INT:
    #####:  112:	    type1_sz = MPID_Datatype_get_basic_size(MPI_LONG);
    #####:  113:	    type2_sz = MPID_Datatype_get_basic_size(MPI_INT);
    #####:  114:	    break;
        -:  115:	case MPI_SHORT_INT:
    #####:  116:	    type1_sz = MPID_Datatype_get_basic_size(MPI_SHORT);
    #####:  117:	    type2_sz = MPID_Datatype_get_basic_size(MPI_INT);
    #####:  118:	    break;
        -:  119:	case MPI_LONG_DOUBLE_INT:
    #####:  120:	    type1_sz = MPID_Datatype_get_basic_size(MPI_LONG_DOUBLE);
    #####:  121:	    type2_sz = MPID_Datatype_get_basic_size(MPI_INT);
    #####:  122:	    break;
        -:  123:	default:
        -:  124:	    /* all other types.  this is more complicated than
        -:  125:	     * necessary for handling these types, but it puts us in the
        -:  126:	     * same code path for all the basics, so we stick with it.
        -:  127:	     */
     2358:  128:	    type1_sz = type2_sz = MPID_Datatype_get_basic_size(datatype);
        -:  129:	    break;
        -:  130:    }
        -:  131:
        -:  132:    /* determine the number of elements in the region */
     2359:  133:    elements = 2 * (usable_bytes / (type1_sz + type2_sz));
     2359:  134:    if (usable_bytes % (type1_sz + type2_sz) >= type1_sz) elements++;
        -:  135:
        -:  136:    /* determine how many bytes we used up with those elements */
     2359:  137:    used_bytes = ((elements / 2) * (type1_sz + type2_sz));
     2359:  138:    if (elements % 2 == 1) used_bytes += type1_sz;
        -:  139:
     2359:  140:    *bytes_p -= used_bytes;
        -:  141:
     2359:  142:    return elements;
        -:  143:}
        -:  144:
        -:  145:
        -:  146:/* MPIR_Type_get_elements
        -:  147: *
        -:  148: * Arguments:
        -:  149: * - bytes_p - input/output byte count
        -:  150: * - count - maximum number of this type to subtract from the bytes; a count
        -:  151: *           of -1 indicates use as many as we like
        -:  152: * - datatype - input datatype
        -:  153: *
        -:  154: * Returns number of elements available given the two constraints of number of
        -:  155: * bytes and count of types.  Also reduces the byte count by the amount taken
        -:  156: * up by the types.
        -:  157: *
        -:  158: * This is called from MPI_Get_elements() when it sees a type with multiple
        -:  159: * element types (datatype_ptr->element_sz = -1).  This function calls itself too.
        -:  160: */
        -:  161:PMPI_LOCAL int MPIR_Type_get_elements(int *bytes_p,
        -:  162:				      int count,
        -:  163:				      MPI_Datatype datatype)
       13:  164:{
       13:  165:    MPID_Datatype *datatype_ptr = NULL;
        -:  166:
       13:  167:    MPID_Datatype_get_ptr(datatype, datatype_ptr); /* invalid if builtin */
        -:  168:
        -:  169:    /* if we have gotten down to a type with only one element type,
        -:  170:     * call MPIR_Type_get_basic_type_elements() and return.
        -:  171:     */
       13:  172:    if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN ||
        -:  173:	datatype == MPI_FLOAT_INT ||
        -:  174:	datatype == MPI_DOUBLE_INT ||
        -:  175:	datatype == MPI_LONG_INT ||
        -:  176:	datatype == MPI_SHORT_INT ||
        -:  177:	datatype == MPI_LONG_DOUBLE_INT)
        -:  178:    {
        9:  179:	return MPIR_Type_get_basic_type_elements(bytes_p, count, datatype);
        -:  180:    }
        4:  181:    else if (datatype_ptr->element_size >= 0) {
    #####:  182:	return MPIR_Type_get_basic_type_elements(bytes_p,
        -:  183:						 count * datatype_ptr->n_elements,
        -:  184:						 datatype_ptr->eltype);
        -:  185:    }
        -:  186:    else {
        -:  187:	/* we have bytes left and still don't have a single element size; must
        -:  188:         * recurse.
        -:  189:	 */
        4:  190:	int i, j, typecount = 0, *ints, nr_elements = 0, last_nr_elements;
        -:  191:	MPI_Aint *aints;
        -:  192:	MPI_Datatype *types;
        -:  193:
        -:  194:	/* Establish locations of arrays; perhaps this should be a fn. call or
        -:  195:         * this fn. should be an MPID one?
        -:  196:	 */
        4:  197:	if (datatype_ptr->contents == NULL)
    #####:  198:	    return MPI_ERR_TYPE;
        4:  199:	types = (MPI_Datatype *) (((char *) datatype_ptr->contents) +
        -:  200:				  sizeof(MPID_Datatype_contents));
        4:  201:	if (types == NULL)
    #####:  202:	    return MPI_ERR_TYPE;
        4:  203:	ints  = (int *) (((char *) types) +
        -:  204:			 datatype_ptr->contents->nr_types * sizeof(MPI_Datatype));
        4:  205:	if (ints == NULL)
    #####:  206:	    return MPI_ERR_TYPE;
        4:  207:	aints = (MPI_Aint *) (((char *) ints) +
        -:  208:			      datatype_ptr->contents->nr_ints * sizeof(int));
        4:  209:	if (aints == NULL)
    #####:  210:	    return MPI_ERR_TYPE;
        -:  211:
        4:  212:	switch (datatype_ptr->contents->combiner) {
        -:  213:	    case MPI_COMBINER_NAMED:
        -:  214:	    case MPI_COMBINER_DUP:
        -:  215:	    case MPI_COMBINER_RESIZED:
    #####:  216:		return MPIR_Type_get_elements(bytes_p, count, *types);
        -:  217:		break;
        -:  218:	    case MPI_COMBINER_CONTIGUOUS:
        -:  219:	    case MPI_COMBINER_VECTOR:
        -:  220:	    case MPI_COMBINER_HVECTOR_INTEGER:
        -:  221:	    case MPI_COMBINER_HVECTOR:
        -:  222:		/* count is first in ints array */
    #####:  223:		return MPIR_Type_get_elements(bytes_p, count * (*ints), *types);
        -:  224:		break;
        -:  225:	    case MPI_COMBINER_INDEXED_BLOCK:
        -:  226:		/* count is first in ints array, blocklength is second */
    #####:  227:		return MPIR_Type_get_elements(bytes_p,
        -:  228:					      count * ints[0] * ints[1],
        -:  229:					      *types);
        -:  230:		break;
        -:  231:	    case MPI_COMBINER_INDEXED:
        -:  232:	    case MPI_COMBINER_HINDEXED_INTEGER:
        -:  233:	    case MPI_COMBINER_HINDEXED:
    #####:  234:		for (i=0; i < (*ints); i++) {
        -:  235:		    /* add up the blocklengths to get a max. # of the next type */
    #####:  236:		    typecount += ints[i+1];
        -:  237:		}
    #####:  238:		return MPIR_Type_get_elements(bytes_p, count * typecount, *types);
        -:  239:		break;
        -:  240:	    case MPI_COMBINER_STRUCT_INTEGER:
        -:  241:	    case MPI_COMBINER_STRUCT:
        -:  242:		/* In this case we can't simply multiply the count of the next
        -:  243:		 * type by the count of the current type, because we need to
        -:  244:		 * cycle through the types just as the struct would.  thus the
        -:  245:		 * nested loops.
        -:  246:		 *
        -:  247:		 * We need to keep going until we see a "0" elements returned
        -:  248:		 * or we run out of bytes.
        -:  249:		 */
        -:  250:
        -:  251:
        4:  252:		last_nr_elements = 1; /* seed value */
        4:  253:		for (j=0;
       12:  254:		     (count == -1 || j < count) &&
        -:  255:			 *bytes_p > 0 && last_nr_elements > 0;
        4:  256:		     j++)
        -:  257:		{
        -:  258:		    /* recurse on each type; bytes are reduced in calls */
       12:  259:		    for (i=0; i < (*ints); i++) {
        -:  260:			/* skip zero-count elements of the struct */
        8:  261:			if (ints[i+1] == 0) continue;
        -:  262:
        8:  263:			last_nr_elements = MPIR_Type_get_elements(bytes_p,
        -:  264:								  ints[i+1],
        -:  265:								  types[i]);
        8:  266:			nr_elements += last_nr_elements;
        -:  267:
        8:  268:			MPIU_Assert(last_nr_elements >= 0);
        -:  269:
        8:  270:			if (last_nr_elements == 0) break;
        -:  271:		    }
        -:  272:		}
        4:  273:		return nr_elements;
        -:  274:		break;
        -:  275:	    case MPI_COMBINER_SUBARRAY:
        -:  276:	    case MPI_COMBINER_DARRAY:
        -:  277:	    case MPI_COMBINER_F90_REAL:
        -:  278:	    case MPI_COMBINER_F90_COMPLEX:
        -:  279:	    case MPI_COMBINER_F90_INTEGER:
        -:  280:	    default:
        -:  281:		/* --BEGIN ERROR HANDLING-- */
    #####:  282:		MPIU_Assert(0);
    #####:  283:		return -1;
        -:  284:		break;
        -:  285:		/* --END ERROR HANDLING-- */
        -:  286:	}
        -:  287:    }
        -:  288:}
        -:  289:#endif
        -:  290:
        -:  291:#undef FUNCNAME
        -:  292:#define FUNCNAME MPI_Get_elements
        -:  293:#undef FCNAME
        -:  294:#define FCNAME "MPI_Get_elements"
        -:  295:
        -:  296:/*@
        -:  297:   MPI_Get_elements - Returns the number of basic elements
        -:  298:                      in a datatype
        -:  299:
        -:  300:Input Parameters:
        -:  301:+ status - return status of receive operation (Status)
        -:  302:- datatype - datatype used by receive operation (handle)
        -:  303:
        -:  304:Output Parameter:
        -:  305:. count - number of received basic elements (integer)
        -:  306:
        -:  307:   Notes:
        -:  308:
        -:  309: If the size of the datatype is zero and the amount of data returned as
        -:  310: determined by 'status' is also zero, this routine will return a count of
        -:  311: zero.  This is consistent with a clarification made by the MPI Forum.
        -:  312:
        -:  313:.N Fortran
        -:  314:
        -:  315:.N Errors
        -:  316:.N MPI_SUCCESS
        -:  317:@*/
        -:  318:int MPI_Get_elements(MPI_Status *status, MPI_Datatype datatype, int *elements)
     2359:  319:{
     2359:  320:    int mpi_errno = MPI_SUCCESS, byte_count;
     2359:  321:    MPID_Datatype *datatype_ptr = NULL;
        -:  322:
        -:  323:    MPID_MPI_STATE_DECL(MPID_STATE_MPI_GET_ELEMENTS);
        -:  324:
     2359:  325:    MPIR_ERRTEST_INITIALIZED_ORDIE();
        -:  326:
        -:  327:    MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_GET_ELEMENTS);
        -:  328:
        -:  329:    /* Validate parameters, especially handles needing to be converted */
        -:  330:#   ifdef HAVE_ERROR_CHECKING
        -:  331:    {
        -:  332:        MPID_BEGIN_ERROR_CHECKS;
        -:  333:        {
     2359:  334:	    MPIR_ERRTEST_DATATYPE(datatype, "datatype", mpi_errno);
     2359:  335:            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -:  336:        }
        -:  337:        MPID_END_ERROR_CHECKS;
        -:  338:    }
        -:  339:#   endif
        -:  340:
        -:  341:    /* Convert MPI object handles to object pointers */
     2358:  342:    MPID_Datatype_get_ptr(datatype, datatype_ptr);
        -:  343:
        -:  344:    /* Validate parameters and objects (post conversion) */
        -:  345:#   ifdef HAVE_ERROR_CHECKING
        -:  346:    {
        -:  347:        MPID_BEGIN_ERROR_CHECKS;
        -:  348:        {
     2358:  349:	    MPIR_ERRTEST_ARGNULL(status, "status", mpi_errno);
     2358:  350:	    MPIR_ERRTEST_ARGNULL(elements, "elements", mpi_errno);
        -:  351:            /* Validate datatype_ptr */
     2358:  352:	    if (HANDLE_GET_KIND(datatype) != HANDLE_KIND_BUILTIN) {
     1035:  353:		MPID_Datatype_get_ptr(datatype, datatype_ptr);
     1035:  354:		MPID_Datatype_valid_ptr(datatype_ptr, mpi_errno);
     1035:  355:		if (mpi_errno == MPI_SUCCESS) {
     1035:  356:		    MPID_Datatype_committed_ptr(datatype_ptr, mpi_errno);
        -:  357:		}
        -:  358:	    }
     2358:  359:            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        -:  360:        }
        -:  361:        MPID_END_ERROR_CHECKS;
        -:  362:    }
        -:  363:#   endif
        -:  364:
        -:  365:    /* ... body of routine ...  */
        -:  366:
        -:  367:    /* three cases:
        -:  368:     * - nice, simple, single element type
        -:  369:     * - derived type with a zero size
        -:  370:     * - type with multiple element types (nastiest)
        -:  371:     */
     2357:  372:    if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN ||
        -:  373:	(datatype_ptr->element_size != -1 && datatype_ptr->size > 0))
        -:  374:    {
     2350:  375:	byte_count = status->count;
        -:  376:
        -:  377:	/* QUESTION: WHAT IF SOMEONE GAVE US AN MPI_UB OR MPI_LB???
        -:  378:	 */
        -:  379:
        -:  380:	/* in both cases we do not limit the number of types that might
        -:  381:	 * be in bytes
        -:  382:	 */
     2350:  383:	if (HANDLE_GET_KIND(datatype) != HANDLE_KIND_BUILTIN) {
     1027:  384:	    *elements = MPIR_Type_get_basic_type_elements(&byte_count,
        -:  385:							  -1,
        -:  386:							  datatype_ptr->eltype);
        -:  387:	}
        -:  388:	else {
        -:  389:	    /* Behaves just like MPI_Get_Count in the predefined case */
        -:  390:	    int size;
     1323:  391:	    MPID_Datatype_get_size_macro(datatype, size);
     1323:  392:            if ((byte_count % size) != 0)
    #####:  393:                *elements = MPI_UNDEFINED;
        -:  394:            else
     1323:  395:                *elements = MPIR_Type_get_basic_type_elements(&byte_count,
        -:  396:							      -1,
        -:  397:							      datatype);
        -:  398:	}
     2350:  399:	MPIU_Assert(byte_count >= 0);
        -:  400:    }
        7:  401:    else if (datatype_ptr->size == 0) {
        2:  402:	if (status->count > 0) {
        -:  403:	    /* --BEGIN ERROR HANDLING-- */
        -:  404:
        -:  405:	    /* datatype size of zero and count > 0 should never happen. */
        -:  406:
    #####:  407:	    (*elements) = MPI_UNDEFINED;
        -:  408:	    /* --END ERROR HANDLING-- */
        -:  409:	}
        -:  410:	else {
        -:  411:	    /* This is ambiguous.  However, discussions on MPI Forum
        -:  412:	     * reached a consensus that this is the correct return
        -:  413:	     * value
        -:  414:	     */
        2:  415:	    (*elements) = 0;
        -:  416:	}
        -:  417:    }
        -:  418:    else /* derived type with weird element type or weird size */ {
        5:  419:	MPIU_Assert(datatype_ptr->element_size == -1);
        -:  420:
        5:  421:	byte_count = status->count;
        5:  422:	*elements = MPIR_Type_get_elements(&byte_count, -1, datatype);
        -:  423:    }
        -:  424:
        -:  425:    /* ... end of body of routine ... */
        -:  426:
        -:  427:#ifdef HAVE_ERROR_CHECKING
     2359:  428:  fn_exit:
        -:  429:#endif
        -:  430:    MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_GET_ELEMENTS);
     2359:  431:    return mpi_errno;
        -:  432:
        -:  433:    /* --BEGIN ERROR HANDLING-- */
        -:  434:#   ifdef HAVE_ERROR_CHECKING
        2:  435:  fn_fail:
        -:  436:    {
        2:  437:	mpi_errno = MPIR_Err_create_code(
        -:  438:	    mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
        -:  439:	    "**mpi_get_elements",
        -:  440:	    "**mpi_get_elements %p %D %p", status, datatype, elements);
        -:  441:    }
        2:  442:    mpi_errno = MPIR_Err_return_comm(0, FCNAME, mpi_errno);
        2:  443:    goto fn_exit;
        -:  444:#   endif
        -:  445:    /* --END ERROR HANDLING-- */
        -:  446:}