int MPID_Type_indexed(int count, const int *blocklength_array, const void *displacement_array, int dispinbytes, MPI_Datatype oldtype, MPI_Datatype *newtype) { int mpi_errno = MPI_SUCCESS; int is_builtin, old_is_contig; int i, contig_count; int el_sz, el_ct, old_ct, old_sz; MPI_Aint old_lb, old_ub, old_extent, old_true_lb, old_true_ub; MPI_Aint min_lb = 0, max_ub = 0, eff_disp; MPI_Datatype el_type; MPID_Datatype *new_dtp; if (count == 0) return MPID_Type_zerolen(newtype); /* sanity check that blocklens are all non-negative */ for (i = 0; i < count; ++i) { DLOOP_Assert(blocklength_array[i] >= 0); } /* allocate new datatype object and handle */ new_dtp = (MPID_Datatype *) MPIU_Handle_obj_alloc(&MPID_Datatype_mem); /* --BEGIN ERROR HANDLING-- */ if (!new_dtp) { mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, "MPID_Type_indexed", __LINE__, MPI_ERR_OTHER, "**nomem", 0); return mpi_errno; } /* --END ERROR HANDLING-- */ /* handle is filled in by MPIU_Handle_obj_alloc() */ MPIU_Object_set_ref(new_dtp, 1); new_dtp->is_permanent = 0; new_dtp->is_committed = 0; new_dtp->attributes = NULL; new_dtp->cache_id = 0; new_dtp->name[0] = 0; new_dtp->contents = NULL; new_dtp->dataloop = NULL; new_dtp->dataloop_size = -1; new_dtp->dataloop_depth = -1; new_dtp->hetero_dloop = NULL; new_dtp->hetero_dloop_size = -1; new_dtp->hetero_dloop_depth = -1; is_builtin = (HANDLE_GET_KIND(oldtype) == HANDLE_KIND_BUILTIN); if (is_builtin) { /* builtins are handled differently than user-defined types because * they have no associated dataloop or datatype structure. */ el_sz = MPID_Datatype_get_basic_size(oldtype); old_sz = el_sz; el_ct = 1; el_type = oldtype; old_lb = 0; old_true_lb = 0; old_ub = (MPI_Aint) el_sz; old_true_ub = (MPI_Aint) el_sz; old_extent = (MPI_Aint) el_sz; old_is_contig = 1; new_dtp->has_sticky_ub = 0; new_dtp->has_sticky_lb = 0; new_dtp->alignsize = el_sz; /* ??? */ new_dtp->element_size = (MPI_Aint) el_sz; new_dtp->eltype = el_type; new_dtp->max_contig_blocks = count; } else { /* user-defined base type (oldtype) */ MPID_Datatype *old_dtp; MPID_Datatype_get_ptr(oldtype, old_dtp); /* Ensure that "element_size" fits into an int datatype. */ MPID_Ensure_Aint_fits_in_int(old_dtp->element_size); el_sz = old_dtp->element_size; old_sz = old_dtp->size; el_ct = old_dtp->n_elements; el_type = old_dtp->eltype; old_lb = old_dtp->lb; old_true_lb = old_dtp->true_lb; old_ub = old_dtp->ub; old_true_ub = old_dtp->true_ub; old_extent = old_dtp->extent; old_is_contig = old_dtp->is_contig; new_dtp->has_sticky_lb = old_dtp->has_sticky_lb; new_dtp->has_sticky_ub = old_dtp->has_sticky_ub; new_dtp->element_size = (MPI_Aint) el_sz; new_dtp->eltype = el_type; new_dtp->max_contig_blocks = 0; for(i=0; i<count; i++) new_dtp->max_contig_blocks += old_dtp->max_contig_blocks * ((MPI_Aint ) blocklength_array[i]); } /* find the first nonzero blocklength element */ i = 0; while (i < count && blocklength_array[i] == 0) i++; if (i == count) { MPIU_Handle_obj_free(&MPID_Datatype_mem, new_dtp); return MPID_Type_zerolen(newtype); } /* priming for loop */ old_ct = blocklength_array[i]; eff_disp = (dispinbytes) ? ((MPI_Aint *) displacement_array)[i] : (((MPI_Aint) ((int *) displacement_array)[i]) * old_extent); MPID_DATATYPE_BLOCK_LB_UB((MPI_Aint) blocklength_array[i], eff_disp, old_lb, old_ub, old_extent, min_lb, max_ub); /* determine min lb, max ub, and count of old types in remaining * nonzero size blocks */ for (i++; i < count; i++) { MPI_Aint tmp_lb, tmp_ub; if (blocklength_array[i] > 0) { old_ct += blocklength_array[i]; /* add more oldtypes */ eff_disp = (dispinbytes) ? ((MPI_Aint *) displacement_array)[i] : (((MPI_Aint) ((int *) displacement_array)[i]) * old_extent); /* calculate ub and lb for this block */ MPID_DATATYPE_BLOCK_LB_UB((MPI_Aint)(blocklength_array[i]), eff_disp, old_lb, old_ub, old_extent, tmp_lb, tmp_ub); if (tmp_lb < min_lb) min_lb = tmp_lb; if (tmp_ub > max_ub) max_ub = tmp_ub; } } new_dtp->size = old_ct * old_sz; new_dtp->lb = min_lb; new_dtp->ub = max_ub; new_dtp->true_lb = min_lb + (old_true_lb - old_lb); new_dtp->true_ub = max_ub + (old_true_ub - old_ub); new_dtp->extent = max_ub - min_lb; new_dtp->n_elements = old_ct * el_ct; /* new type is only contig for N types if it's all one big * block, its size and extent are the same, and the old type * was also contiguous. */ new_dtp->is_contig = 0; if(old_is_contig) { contig_count = MPID_Type_indexed_count_contig(count, blocklength_array, displacement_array, dispinbytes, old_extent); new_dtp->max_contig_blocks = contig_count; if( (contig_count == 1) && ((MPI_Aint) new_dtp->size == new_dtp->extent)) { new_dtp->is_contig = 1; } } *newtype = new_dtp->handle; return mpi_errno; }
int MPIR_Pack_impl(const void *inbuf, int incount, MPI_Datatype datatype, void *outbuf, MPI_Aint outsize, MPI_Aint *position) { int mpi_errno = MPI_SUCCESS; MPI_Aint first, last; MPID_Segment *segp; int contig; MPI_Aint dt_true_lb; MPI_Aint data_sz; if (incount == 0) { goto fn_exit; } /* Handle contig case quickly */ if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN) { contig = TRUE; dt_true_lb = 0; data_sz = incount * MPID_Datatype_get_basic_size(datatype); } else { MPID_Datatype *dt_ptr; MPID_Datatype_get_ptr(datatype, dt_ptr); contig = dt_ptr->is_contig; dt_true_lb = dt_ptr->true_lb; data_sz = incount * dt_ptr->size; } if (contig) { MPIU_Memcpy((char *) outbuf + *position, (char *)inbuf + dt_true_lb, data_sz); *position = (int)((MPI_Aint)*position + data_sz); goto fn_exit; } /* non-contig case */ /* TODO: CHECK RETURN VALUES?? */ /* TODO: SHOULD THIS ALL BE IN A MPID_PACK??? */ segp = MPID_Segment_alloc(); MPIU_ERR_CHKANDJUMP1(segp == NULL, mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPID_Segment"); mpi_errno = MPID_Segment_init(inbuf, incount, datatype, segp, 0); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* NOTE: the use of buffer values and positions in MPI_Pack and in * MPID_Segment_pack are quite different. See code or docs or something. */ first = 0; last = SEGMENT_IGNORE_LAST; /* Ensure that pointer increment fits in a pointer */ MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT outbuf) + (MPI_Aint) *position); MPID_Segment_pack(segp, first, &last, (void *) ((char *) outbuf + *position)); /* Ensure that calculation fits into an int datatype. */ MPID_Ensure_Aint_fits_in_int((MPI_Aint)*position + last); *position = (int)((MPI_Aint)*position + last); MPID_Segment_free(segp); fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
/*@ MPID_Type_struct - create a struct datatype Input Parameters: + count - number of blocks in vector . blocklength_array - number of elements in each block . displacement_array - offsets of blocks from start of type in bytes - oldtype_array - types (using handle) of datatypes on which vector is based Output Parameters: . newtype - handle of new struct datatype Return Value: MPI_SUCCESS on success, MPI errno on failure. @*/ int MPID_Type_struct(int count, const int *blocklength_array, const MPI_Aint *displacement_array, const MPI_Datatype *oldtype_array, MPI_Datatype *newtype) { int mpi_errno = MPI_SUCCESS; int i, old_are_contig = 1, definitely_not_contig = 0; int found_sticky_lb = 0, found_sticky_ub = 0, found_true_lb = 0, found_true_ub = 0, found_el_type = 0, found_lb=0, found_ub=0; MPI_Aint el_sz = 0; MPI_Aint size = 0; MPI_Datatype el_type = MPI_DATATYPE_NULL; MPI_Aint true_lb_disp = 0, true_ub_disp = 0, sticky_lb_disp = 0, sticky_ub_disp = 0, lb_disp = 0, ub_disp = 0; MPID_Datatype *new_dtp; if (count == 0) return MPID_Type_zerolen(newtype); #ifdef MPID_STRUCT_DEBUG MPIDI_Datatype_printf(oldtype_array[0], 1, displacement_array[0], blocklength_array[0], 1); for (i=1; i < count; i++) { MPIDI_Datatype_printf(oldtype_array[i], 1, displacement_array[i], blocklength_array[i], 0); } #endif /* allocate new datatype object and handle */ new_dtp = (MPID_Datatype *) MPIU_Handle_obj_alloc(&MPID_Datatype_mem); /* --BEGIN ERROR HANDLING-- */ if (!new_dtp) { mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, "MPID_Type_struct", __LINE__, MPI_ERR_OTHER, "**nomem", 0); return mpi_errno; } /* --END ERROR HANDLING-- */ /* handle is filled in by MPIU_Handle_obj_alloc() */ MPIU_Object_set_ref(new_dtp, 1); new_dtp->is_permanent = 0; new_dtp->is_committed = 0; new_dtp->attributes = NULL; new_dtp->cache_id = 0; new_dtp->name[0] = 0; new_dtp->contents = NULL; new_dtp->dataloop = NULL; new_dtp->dataloop_size = -1; new_dtp->dataloop_depth = -1; new_dtp->hetero_dloop = NULL; new_dtp->hetero_dloop_size = -1; new_dtp->hetero_dloop_depth = -1; /* check for junk struct with all zero blocks */ for (i=0; i < count; i++) if (blocklength_array[i] != 0) break; if (i == count) { MPIU_Handle_obj_free(&MPID_Datatype_mem, new_dtp); return MPID_Type_zerolen(newtype); } new_dtp->max_contig_blocks = 0; for (i=0; i < count; i++) { int is_builtin = (HANDLE_GET_KIND(oldtype_array[i]) == HANDLE_KIND_BUILTIN); MPI_Aint tmp_lb, tmp_ub, tmp_true_lb, tmp_true_ub; MPI_Aint tmp_el_sz; MPI_Datatype tmp_el_type; MPID_Datatype *old_dtp = NULL; /* Interpreting typemap to not include 0 blklen things, including * MPI_LB and MPI_UB. -- Rob Ross, 10/31/2005 */ if (blocklength_array[i] == 0) continue; if (is_builtin) { tmp_el_sz = MPID_Datatype_get_basic_size(oldtype_array[i]); tmp_el_type = oldtype_array[i]; MPID_DATATYPE_BLOCK_LB_UB((MPI_Aint)(blocklength_array[i]), displacement_array[i], 0, tmp_el_sz, tmp_el_sz, tmp_lb, tmp_ub); tmp_true_lb = tmp_lb; tmp_true_ub = tmp_ub; size += tmp_el_sz * blocklength_array[i]; new_dtp->max_contig_blocks++; } else { MPID_Datatype_get_ptr(oldtype_array[i], old_dtp); /* Ensure that "builtin_element_size" fits into an int datatype. */ MPID_Ensure_Aint_fits_in_int(old_dtp->builtin_element_size); tmp_el_sz = old_dtp->builtin_element_size; tmp_el_type = old_dtp->basic_type; MPID_DATATYPE_BLOCK_LB_UB((MPI_Aint) blocklength_array[i], displacement_array[i], old_dtp->lb, old_dtp->ub, old_dtp->extent, tmp_lb, tmp_ub); tmp_true_lb = tmp_lb + (old_dtp->true_lb - old_dtp->lb); tmp_true_ub = tmp_ub + (old_dtp->true_ub - old_dtp->ub); size += old_dtp->size * blocklength_array[i]; new_dtp->max_contig_blocks += old_dtp->max_contig_blocks; } /* element size and type */ if (oldtype_array[i] != MPI_LB && oldtype_array[i] != MPI_UB) { if (found_el_type == 0) { el_sz = tmp_el_sz; el_type = tmp_el_type; found_el_type = 1; } else if (el_sz != tmp_el_sz) { el_sz = -1; el_type = MPI_DATATYPE_NULL; } else if (el_type != tmp_el_type) { /* Q: should we set el_sz = -1 even though the same? */ el_type = MPI_DATATYPE_NULL; } } /* keep lowest sticky lb */ if ((oldtype_array[i] == MPI_LB) || (!is_builtin && old_dtp->has_sticky_lb)) { if (!found_sticky_lb) { found_sticky_lb = 1; sticky_lb_disp = tmp_lb; } else if (sticky_lb_disp > tmp_lb) { sticky_lb_disp = tmp_lb; } } /* keep highest sticky ub */ if ((oldtype_array[i] == MPI_UB) || (!is_builtin && old_dtp->has_sticky_ub)) { if (!found_sticky_ub) { found_sticky_ub = 1; sticky_ub_disp = tmp_ub; } else if (sticky_ub_disp < tmp_ub) { sticky_ub_disp = tmp_ub; } } /* keep lowest lb/true_lb and highest ub/true_ub * * note: checking for contiguity at the same time, to avoid * yet another pass over the arrays */ if (oldtype_array[i] != MPI_UB && oldtype_array[i] != MPI_LB) { if (!found_true_lb) { found_true_lb = 1; true_lb_disp = tmp_true_lb; } else if (true_lb_disp > tmp_true_lb) { /* element starts before previous */ true_lb_disp = tmp_true_lb; definitely_not_contig = 1; } if (!found_lb) { found_lb = 1; lb_disp = tmp_lb; } else if (lb_disp > tmp_lb) { /* lb before previous */ lb_disp = tmp_lb; definitely_not_contig = 1; } if (!found_true_ub) { found_true_ub = 1; true_ub_disp = tmp_true_ub; } else if (true_ub_disp < tmp_true_ub) { true_ub_disp = tmp_true_ub; } else { /* element ends before previous ended */ definitely_not_contig = 1; } if (!found_ub) { found_ub = 1; ub_disp = tmp_ub; } else if (ub_disp < tmp_ub) { ub_disp = tmp_ub; } else { /* ub before previous */ definitely_not_contig = 1; } } if (!is_builtin && !old_dtp->is_contig) { old_are_contig = 0; } } new_dtp->n_builtin_elements = -1; /* TODO */ new_dtp->builtin_element_size = el_sz; new_dtp->basic_type = el_type; new_dtp->has_sticky_lb = found_sticky_lb; new_dtp->true_lb = true_lb_disp; new_dtp->lb = (found_sticky_lb) ? sticky_lb_disp : lb_disp; new_dtp->has_sticky_ub = found_sticky_ub; new_dtp->true_ub = true_ub_disp; new_dtp->ub = (found_sticky_ub) ? sticky_ub_disp : ub_disp; new_dtp->alignsize = MPID_Type_struct_alignsize(count, oldtype_array, displacement_array); new_dtp->extent = new_dtp->ub - new_dtp->lb; if ((!found_sticky_lb) && (!found_sticky_ub)) { /* account for padding */ MPI_Aint epsilon = (new_dtp->alignsize > 0) ? new_dtp->extent % ((MPI_Aint)(new_dtp->alignsize)) : 0; if (epsilon) { new_dtp->ub += ((MPI_Aint)(new_dtp->alignsize) - epsilon); new_dtp->extent = new_dtp->ub - new_dtp->lb; } } new_dtp->size = size; /* new type is contig for N types if its size and extent are the * same, and the old type was also contiguous, and we didn't see * something noncontiguous based on true ub/ub. */ if (((MPI_Aint)(new_dtp->size) == new_dtp->extent) && old_are_contig && (! definitely_not_contig)) { new_dtp->is_contig = 1; } else { new_dtp->is_contig = 0; } *newtype = new_dtp->handle; return mpi_errno; }