/*@ MPI_Group_translate_ranks - Translates the ranks of processes in one group to those in another group Input Parameters: + group1 - group1 (handle) . n - number of ranks in 'ranks1' and 'ranks2' arrays (integer) . ranks1 - array of zero or more valid ranks in 'group1' - group2 - group2 (handle) Output Parameters: . ranks2 - array of corresponding ranks in group2, 'MPI_UNDEFINED' when no correspondence exists. As a special case (see the MPI-2 errata), if the input rank is 'MPI_PROC_NULL', 'MPI_PROC_NULL' is given as the output rank. .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS @*/ int MPI_Group_translate_ranks(MPI_Group group1, int n, const int ranks1[], MPI_Group group2, int ranks2[]) { int mpi_errno = MPI_SUCCESS; MPIR_Group *group_ptr1 = NULL; MPIR_Group *group_ptr2 = NULL; MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPI_GROUP_TRANSLATE_RANKS); MPIR_ERRTEST_INITIALIZED_ORDIE(); /* The routines that setup the group data structures must be executed within a mutex. As most of the group routines are not performance critical, we simple run these routines within the SINGLE_CS */ MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPI_GROUP_TRANSLATE_RANKS); /* Validate parameters, especially handles needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPIR_ERRTEST_GROUP(group1, mpi_errno); MPIR_ERRTEST_GROUP(group2, mpi_errno); } MPID_END_ERROR_CHECKS; } # endif /* Convert MPI object handles to object pointers */ MPIR_Group_get_ptr( group1, group_ptr1 ); MPIR_Group_get_ptr( group2, group_ptr2 ); /* Validate parameters and objects (post conversion) */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { /* Validate group_ptr */ MPIR_Group_valid_ptr( group_ptr1, mpi_errno ); MPIR_Group_valid_ptr( group_ptr2, mpi_errno ); /* If either group_ptr is not valid, it will be reset to null */ MPIR_ERRTEST_ARGNEG(n,"n",mpi_errno); if (group_ptr1) { /* Check that the rank entries are valid */ int size1 = group_ptr1->size; int i; for (i=0; i<n; i++) { if ( (ranks1[i] < 0 && ranks1[i] != MPI_PROC_NULL) || ranks1[i] >= size1) { mpi_errno = MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_RANK, "**rank", "**rank %d %d", ranks1[i], size1 ); goto fn_fail; } } } } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ mpi_errno = MPIR_Group_translate_ranks_impl(group_ptr1, n, ranks1, group_ptr2, ranks2); if (mpi_errno) MPIR_ERR_POP(mpi_errno); /* ... end of body of routine ... */ fn_exit: MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPI_GROUP_TRANSLATE_RANKS); MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); return mpi_errno; /* --BEGIN ERROR HANDLING-- */ fn_fail: { mpi_errno = MPIR_Err_create_code( mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_group_translate_ranks", "**mpi_group_translate_ranks %G %d %p %G %p", group1, n, ranks1, group2, ranks2); } mpi_errno = MPIR_Err_return_comm( NULL, FCNAME, mpi_errno ); goto fn_exit; /* --END ERROR HANDLING-- */ }
/*@ MPI_Dist_graph_create - MPI_DIST_GRAPH_CREATE returns a handle to a new communicator to which the distributed graph topology information is attached. Input Parameters: + comm_old - input communicator (handle) . n - number of source nodes for which this process specifies edges (non-negative integer) . sources - array containing the n source nodes for which this process specifies edges (array of non-negative integers) . degrees - array specifying the number of destinations for each source node in the source node array (array of non-negative integers) . destinations - destination nodes for the source nodes in the source node array (array of non-negative integers) . weights - weights for source to destination edges (array of non-negative integers or MPI_UNWEIGHTED) . info - hints on optimization and interpretation of weights (handle) - reorder - the process may be reordered (true) or not (false) (logical) Output Parameters: . comm_dist_graph - communicator with distributed graph topology added (handle) .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS .N MPI_ERR_ARG .N MPI_ERR_OTHER @*/ int MPI_Dist_graph_create(MPI_Comm comm_old, int n, const int sources[], const int degrees[], const int destinations[], const int weights[], MPI_Info info, int reorder, MPI_Comm *comm_dist_graph) { int mpi_errno = MPI_SUCCESS; MPID_Comm *comm_ptr = NULL; MPID_Comm *comm_dist_graph_ptr = NULL; MPI_Request *reqs = NULL; MPIR_Topology *topo_ptr = NULL; MPIR_Dist_graph_topology *dist_graph_ptr = NULL; int i; int j; int idx; int comm_size = 0; int in_capacity; int out_capacity; int **rout = NULL; int **rin = NULL; int *rin_sizes; int *rout_sizes; int *rin_idx; int *rout_idx; int *rs; int in_out_peers[2] = {-1, -1}; int errflag = FALSE; MPIU_CHKLMEM_DECL(9); MPIU_CHKPMEM_DECL(1); MPID_MPI_STATE_DECL(MPID_STATE_MPI_DIST_GRAPH_CREATE); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPIU_THREAD_CS_ENTER(ALLFUNC,); MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_DIST_GRAPH_CREATE); /* Validate parameters, especially handles needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPIR_ERRTEST_COMM(comm_old, mpi_errno); MPIR_ERRTEST_INFO_OR_NULL(info, mpi_errno); if (mpi_errno != MPI_SUCCESS) goto fn_fail; } MPID_END_ERROR_CHECKS; } # endif /* Convert MPI object handles to object pointers */ MPID_Comm_get_ptr(comm_old, comm_ptr); /* Validate parameters and objects (post conversion) */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { /* Validate comm_ptr */ MPID_Comm_valid_ptr(comm_ptr, mpi_errno); /* If comm_ptr is not valid, it will be reset to null */ if (comm_ptr) { MPIR_ERRTEST_COMM_INTRA(comm_ptr, mpi_errno); } MPIR_ERRTEST_ARGNEG(n, "n", mpi_errno); if (n > 0) { int have_degrees = 0; MPIR_ERRTEST_ARGNULL(sources, "sources", mpi_errno); MPIR_ERRTEST_ARGNULL(degrees, "degrees", mpi_errno); for (i = 0; i < n; ++i) { if (degrees[i]) { have_degrees = 1; break; } } if (have_degrees) { MPIR_ERRTEST_ARGNULL(destinations, "destinations", mpi_errno); if (weights != MPI_UNWEIGHTED) MPIR_ERRTEST_ARGNULL(weights, "weights", mpi_errno); } } if (mpi_errno != MPI_SUCCESS) goto fn_fail; } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ /* Implementation based on Torsten Hoefler's reference implementation * attached to MPI-2.2 ticket #33. */ *comm_dist_graph = MPI_COMM_NULL; comm_size = comm_ptr->local_size; /* following the spirit of the old topo interface, attributes do not * propagate to the new communicator (see MPI-2.1 pp. 243 line 11) */ mpi_errno = MPIR_Comm_copy(comm_ptr, comm_size, &comm_dist_graph_ptr); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_Assert(comm_dist_graph_ptr != NULL); /* rin is an array of size comm_size containing pointers to arrays of * rin_sizes[x]. rin[x] is locally known number of edges into this process * from rank x. * * rout is an array of comm_size containing pointers to arrays of * rout_sizes[x]. rout[x] is the locally known number of edges out of this * process to rank x. */ MPIU_CHKLMEM_MALLOC(rout, int **, comm_size*sizeof(int*), mpi_errno, "rout"); MPIU_CHKLMEM_MALLOC(rin, int **, comm_size*sizeof(int*), mpi_errno, "rin"); MPIU_CHKLMEM_MALLOC(rin_sizes, int *, comm_size*sizeof(int), mpi_errno, "rin_sizes"); MPIU_CHKLMEM_MALLOC(rout_sizes, int *, comm_size*sizeof(int), mpi_errno, "rout_sizes"); MPIU_CHKLMEM_MALLOC(rin_idx, int *, comm_size*sizeof(int), mpi_errno, "rin_idx"); MPIU_CHKLMEM_MALLOC(rout_idx, int *, comm_size*sizeof(int), mpi_errno, "rout_idx"); memset(rout, 0, comm_size*sizeof(int*)); memset(rin, 0, comm_size*sizeof(int*)); memset(rin_sizes, 0, comm_size*sizeof(int)); memset(rout_sizes, 0, comm_size*sizeof(int)); memset(rin_idx, 0, comm_size*sizeof(int)); memset(rout_idx, 0, comm_size*sizeof(int)); /* compute array sizes */ idx = 0; for (i = 0; i < n; ++i) { MPIU_Assert(sources[i] < comm_size); for (j = 0; j < degrees[i]; ++j) { MPIU_Assert(destinations[idx] < comm_size); /* rout_sizes[i] is twice as long as the number of edges to be * sent to rank i by this process */ rout_sizes[sources[i]] += 2; rin_sizes[destinations[idx]] += 2; ++idx; } } /* allocate arrays */ for (i = 0; i < comm_size; ++i) { /* can't use CHKLMEM macros b/c we are in a loop */ if (rin_sizes[i]) { rin[i] = MPIU_Malloc(rin_sizes[i] * sizeof(int)); } if (rout_sizes[i]) { rout[i] = MPIU_Malloc(rout_sizes[i] * sizeof(int)); } } /* populate arrays */ idx = 0; for (i = 0; i < n; ++i) { /* TODO add this assert as proper error checking above */ int s_rank = sources[i]; MPIU_Assert(s_rank < comm_size); MPIU_Assert(s_rank >= 0); for (j = 0; j < degrees[i]; ++j) { int d_rank = destinations[idx]; int weight = (weights == MPI_UNWEIGHTED ? 0 : weights[idx]); /* TODO add this assert as proper error checking above */ MPIU_Assert(d_rank < comm_size); MPIU_Assert(d_rank >= 0); /* XXX DJG what about self-edges? do we need to drop one of these * cases when there is a self-edge to avoid double-counting? */ /* rout[s][2*x] is the value of d for the j'th edge between (s,d) * with weight rout[s][2*x+1], where x is the current end of the * outgoing edge list for s. x==(rout_idx[s]/2) */ rout[s_rank][rout_idx[s_rank]++] = d_rank; rout[s_rank][rout_idx[s_rank]++] = weight; /* rin[d][2*x] is the value of s for the j'th edge between (s,d) * with weight rout[d][2*x+1], where x is the current end of the * incoming edge list for d. x==(rin_idx[d]/2) */ rin[d_rank][rin_idx[d_rank]++] = s_rank; rin[d_rank][rin_idx[d_rank]++] = weight; ++idx; } } for (i = 0; i < comm_size; ++i) { /* sanity check that all arrays are fully populated*/ MPIU_Assert(rin_idx[i] == rin_sizes[i]); MPIU_Assert(rout_idx[i] == rout_sizes[i]); } MPIU_CHKLMEM_MALLOC(rs, int *, 2*comm_size*sizeof(int), mpi_errno, "red-scat source buffer"); for (i = 0; i < comm_size; ++i) { rs[2*i] = (rin_sizes[i] ? 1 : 0); rs[2*i+1] = (rout_sizes[i] ? 1 : 0); } /* compute the number of peers I will recv from */ mpi_errno = MPIR_Reduce_scatter_block_impl(rs, in_out_peers, 2, MPI_INT, MPI_SUM, comm_ptr, &errflag); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail"); MPIU_Assert(in_out_peers[0] <= comm_size && in_out_peers[0] >= 0); MPIU_Assert(in_out_peers[1] <= comm_size && in_out_peers[1] >= 0); idx = 0; /* must be 2*comm_size requests because we will possibly send inbound and * outbound edges to everyone in our communicator */ MPIU_CHKLMEM_MALLOC(reqs, MPI_Request *, 2*comm_size*sizeof(MPI_Request), mpi_errno, "temp request array"); for (i = 0; i < comm_size; ++i) { if (rin_sizes[i]) { /* send edges where i is a destination to process i */ mpi_errno = MPIC_Isend(&rin[i][0], rin_sizes[i], MPI_INT, i, MPIR_TOPO_A_TAG, comm_old, &reqs[idx++]); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } if (rout_sizes[i]) { /* send edges where i is a source to process i */ mpi_errno = MPIC_Isend(&rout[i][0], rout_sizes[i], MPI_INT, i, MPIR_TOPO_B_TAG, comm_old, &reqs[idx++]); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } MPIU_Assert(idx <= (2 * comm_size)); /* Create the topology structure */ MPIU_CHKPMEM_MALLOC(topo_ptr, MPIR_Topology *, sizeof(MPIR_Topology), mpi_errno, "topo_ptr"); topo_ptr->kind = MPI_DIST_GRAPH; dist_graph_ptr = &topo_ptr->topo.dist_graph; dist_graph_ptr->indegree = 0; dist_graph_ptr->in = NULL; dist_graph_ptr->in_weights = NULL; dist_graph_ptr->outdegree = 0; dist_graph_ptr->out = NULL; dist_graph_ptr->out_weights = NULL; dist_graph_ptr->is_weighted = (weights != MPI_UNWEIGHTED); /* can't use CHKPMEM macros for this b/c we need to realloc */ in_capacity = 10; /* arbitrary */ dist_graph_ptr->in = MPIU_Malloc(in_capacity*sizeof(int)); if (dist_graph_ptr->is_weighted) dist_graph_ptr->in_weights = MPIU_Malloc(in_capacity*sizeof(int)); out_capacity = 10; /* arbitrary */ dist_graph_ptr->out = MPIU_Malloc(out_capacity*sizeof(int)); if (dist_graph_ptr->is_weighted) dist_graph_ptr->out_weights = MPIU_Malloc(out_capacity*sizeof(int)); for (i = 0; i < in_out_peers[0]; ++i) { MPI_Status status; int count; int *buf; /* receive inbound edges */ mpi_errno = MPIC_Probe(MPI_ANY_SOURCE, MPIR_TOPO_A_TAG, comm_old, &status); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIR_Get_count_impl(&status, MPI_INT, &count); /* can't use CHKLMEM macros b/c we are in a loop */ buf = MPIU_Malloc(count*sizeof(int)); MPIU_ERR_CHKANDJUMP(!buf, mpi_errno, MPIR_ERR_RECOVERABLE, "**nomem"); mpi_errno = MPIC_Recv(buf, count, MPI_INT, MPI_ANY_SOURCE, MPIR_TOPO_A_TAG, comm_old, MPI_STATUS_IGNORE); if (mpi_errno) MPIU_ERR_POP(mpi_errno); for (j = 0; j < count/2; ++j) { int deg = dist_graph_ptr->indegree++; if (deg >= in_capacity) { in_capacity *= 2; MPIU_REALLOC_ORJUMP(dist_graph_ptr->in, in_capacity*sizeof(int), mpi_errno); if (dist_graph_ptr->is_weighted) MPIU_REALLOC_ORJUMP(dist_graph_ptr->in_weights, in_capacity*sizeof(int), mpi_errno); } dist_graph_ptr->in[deg] = buf[2*j]; if (dist_graph_ptr->is_weighted) dist_graph_ptr->in_weights[deg] = buf[2*j+1]; } MPIU_Free(buf); } for (i = 0; i < in_out_peers[1]; ++i) { MPI_Status status; int count; int *buf; /* receive outbound edges */ mpi_errno = MPIC_Probe(MPI_ANY_SOURCE, MPIR_TOPO_B_TAG, comm_old, &status); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIR_Get_count_impl(&status, MPI_INT, &count); /* can't use CHKLMEM macros b/c we are in a loop */ buf = MPIU_Malloc(count*sizeof(int)); MPIU_ERR_CHKANDJUMP(!buf, mpi_errno, MPIR_ERR_RECOVERABLE, "**nomem"); mpi_errno = MPIC_Recv(buf, count, MPI_INT, MPI_ANY_SOURCE, MPIR_TOPO_B_TAG, comm_old, MPI_STATUS_IGNORE); if (mpi_errno) MPIU_ERR_POP(mpi_errno); for (j = 0; j < count/2; ++j) { int deg = dist_graph_ptr->outdegree++; if (deg >= out_capacity) { out_capacity *= 2; MPIU_REALLOC_ORJUMP(dist_graph_ptr->out, out_capacity*sizeof(int), mpi_errno); if (dist_graph_ptr->is_weighted) MPIU_REALLOC_ORJUMP(dist_graph_ptr->out_weights, out_capacity*sizeof(int), mpi_errno); } dist_graph_ptr->out[deg] = buf[2*j]; if (dist_graph_ptr->is_weighted) dist_graph_ptr->out_weights[deg] = buf[2*j+1]; } MPIU_Free(buf); } mpi_errno = MPIR_Waitall_impl(idx, reqs, MPI_STATUSES_IGNORE); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* remove any excess memory allocation */ MPIU_REALLOC_ORJUMP(dist_graph_ptr->in, dist_graph_ptr->indegree*sizeof(int), mpi_errno); MPIU_REALLOC_ORJUMP(dist_graph_ptr->out, dist_graph_ptr->outdegree*sizeof(int), mpi_errno); if (dist_graph_ptr->is_weighted) { MPIU_REALLOC_ORJUMP(dist_graph_ptr->in_weights, dist_graph_ptr->indegree*sizeof(int), mpi_errno); MPIU_REALLOC_ORJUMP(dist_graph_ptr->out_weights, dist_graph_ptr->outdegree*sizeof(int), mpi_errno); } mpi_errno = MPIR_Topology_put(comm_dist_graph_ptr, topo_ptr); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_CHKPMEM_COMMIT(); MPIU_OBJ_PUBLISH_HANDLE(*comm_dist_graph, comm_dist_graph_ptr->handle); /* ... end of body of routine ... */ fn_exit: for (i = 0; i < comm_size; ++i) { if (rin[i]) MPIU_Free(rin[i]); if (rout[i]) MPIU_Free(rout[i]); } MPIU_CHKLMEM_FREEALL(); MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_DIST_GRAPH_CREATE); MPIU_THREAD_CS_EXIT(ALLFUNC,); return mpi_errno; /* --BEGIN ERROR HANDLING-- */ fn_fail: if (dist_graph_ptr && dist_graph_ptr->in) MPIU_Free(dist_graph_ptr->in); if (dist_graph_ptr && dist_graph_ptr->in_weights) MPIU_Free(dist_graph_ptr->in_weights); if (dist_graph_ptr && dist_graph_ptr->out) MPIU_Free(dist_graph_ptr->out); if (dist_graph_ptr && dist_graph_ptr->out_weights) MPIU_Free(dist_graph_ptr->out_weights); MPIU_CHKPMEM_REAP(); #ifdef HAVE_ERROR_CHECKING mpi_errno = MPIR_Err_create_code( mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_dist_graph_create", "**mpi_dist_graph_create %C %d %p %p %p %p %I %d %p", comm_old, n, sources, degrees, destinations, weights, info, reorder, comm_dist_graph); #endif mpi_errno = MPIR_Err_return_comm(comm_ptr, FCNAME, mpi_errno); goto fn_exit; /* --END ERROR HANDLING-- */ }
/*@ MPI_Type_create_hindexed - Create a datatype for an indexed datatype with displacements in bytes Input Parameters: + count - number of blocks --- also number of entries in array_of_displacements and array_of_blocklengths (integer) . array_of_blocklengths - number of elements in each block (array of nonnegative integers) . array_of_displacements - byte displacement of each block (array of address integers) - oldtype - old datatype (handle) Output Parameters: . newtype - new datatype (handle) .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS .N MPI_ERR_TYPE .N MPI_ERR_ARG @*/ int MPI_Type_create_hindexed(int count, const int array_of_blocklengths[], const MPI_Aint array_of_displacements[], MPI_Datatype oldtype, MPI_Datatype *newtype) { static const char FCNAME[] = "MPI_Type_create_hindexed"; int mpi_errno = MPI_SUCCESS; MPI_Datatype new_handle; MPID_Datatype *new_dtp; int i, *ints; MPIU_CHKLMEM_DECL(1); MPID_MPI_STATE_DECL(MPID_STATE_MPI_TYPE_CREATE_HINDEXED); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_TYPE_CREATE_HINDEXED); # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { int j; MPID_Datatype *datatype_ptr = NULL; MPIR_ERRTEST_COUNT(count, mpi_errno); if (count > 0) { MPIR_ERRTEST_ARGNULL(array_of_blocklengths, "array_of_blocklengths", mpi_errno); MPIR_ERRTEST_ARGNULL(array_of_displacements, "array_of_displacements", mpi_errno); } MPIR_ERRTEST_DATATYPE(oldtype, "datatype", mpi_errno); if (HANDLE_GET_KIND(oldtype) != HANDLE_KIND_BUILTIN) { MPID_Datatype_get_ptr(oldtype, datatype_ptr); MPID_Datatype_valid_ptr(datatype_ptr, mpi_errno); if (mpi_errno != MPI_SUCCESS) goto fn_fail; } for (j=0; j < count; j++) { MPIR_ERRTEST_ARGNEG(array_of_blocklengths[j], "blocklength", mpi_errno); } } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ mpi_errno = MPID_Type_indexed(count, array_of_blocklengths, array_of_displacements, 1, /* displacements in bytes */ oldtype, &new_handle); if (mpi_errno != MPI_SUCCESS) goto fn_fail; MPIU_CHKLMEM_MALLOC_ORJUMP(ints, int *, (count + 1) * sizeof(int), mpi_errno, "content description"); ints[0] = count; for (i=0; i < count; i++) { ints[i+1] = array_of_blocklengths[i]; } MPID_Datatype_get_ptr(new_handle, new_dtp); mpi_errno = MPID_Datatype_set_contents(new_dtp, MPI_COMBINER_HINDEXED, count+1, /* ints (count, blocklengths) */ count, /* aints (displacements) */ 1, /* types */ ints, array_of_displacements, &oldtype); if (mpi_errno != MPI_SUCCESS) goto fn_fail; MPID_OBJ_PUBLISH_HANDLE(*newtype, new_handle); /* ... end of body of routine ... */ fn_exit: MPIU_CHKLMEM_FREEALL(); MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_TYPE_CREATE_HINDEXED); MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); return mpi_errno; fn_fail: /* --BEGIN ERROR HANDLING-- */ # ifdef HAVE_ERROR_CHECKING { mpi_errno = MPIR_Err_create_code( mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_type_create_hindexed", "**mpi_type_create_hindexed %d %p %p %D %p", count, array_of_blocklengths, array_of_displacements, oldtype, newtype); } # endif mpi_errno = MPIR_Err_return_comm(NULL, FCNAME, mpi_errno); goto fn_exit; /* --END ERROR HANDLING-- */ }
/*@ MPI_Type_struct - Creates a struct datatype Input Parameters: + count - number of blocks (integer) -- also number of entries in arrays array_of_types , array_of_displacements and array_of_blocklengths . array_of_blocklengths - number of elements in each block (array) . array_of_displacements - byte displacement of each block (array) - array_of_types - type of elements in each block (array of handles to datatype objects) Output Parameters: . newtype - new datatype (handle) .N Deprecated The replacement for this routine is 'MPI_Type_create_struct' Notes: If an upperbound is set explicitly by using the MPI datatype 'MPI_UB', the corresponding index must be positive. The MPI standard originally made vague statements about padding and alignment; this was intended to allow the simple definition of structures that could be sent with a count greater than one. For example, .vb struct { int a; char b; } foo; .ve may have 'sizeof(foo) > sizeof(int) + sizeof(char)'; for example, 'sizeof(foo) == 2*sizeof(int)'. The initial version of the MPI standard defined the extent of a datatype as including an `epsilon` that would have allowed an implementation to make the extent an MPI datatype for this structure equal to '2*sizeof(int)'. However, since different systems might define different paddings, there was much discussion by the MPI Forum about what was the correct value of epsilon, and one suggestion was to define epsilon as zero. This would have been the best thing to do in MPI 1.0, particularly since the 'MPI_UB' type allows the user to easily set the end of the structure. Unfortunately, this change did not make it into the final document. Currently, this routine does not add any padding, since the amount of padding needed is determined by the compiler that the user is using to build their code, not the compiler used to construct the MPI library. A later version of MPICH may provide for some natural choices of padding (e.g., multiple of the size of the largest basic member), but users are advised to never depend on this, even with vendor MPI implementations. Instead, if you define a structure datatype and wish to send or receive multiple items, you should explicitly include an 'MPI_UB' entry as the last member of the structure. For example, the following code can be used for the structure foo .vb blen[0] = 1; array_of_displacements[0] = 0; oldtypes[0] = MPI_INT; blen[1] = 1; array_of_displacements[1] = &foo.b - &foo; oldtypes[1] = MPI_CHAR; blen[2] = 1; array_of_displacements[2] = sizeof(foo); oldtypes[2] = MPI_UB; MPI_Type_struct( 3, blen, array_of_displacements, oldtypes, &newtype ); .ve .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS .N MPI_ERR_TYPE .N MPI_ERR_COUNT .N MPI_ERR_EXHAUSTED @*/ int MPI_Type_struct(int count, const int *array_of_blocklengths, const MPI_Aint *array_of_displacements, const MPI_Datatype *array_of_types, MPI_Datatype *newtype) { int mpi_errno = MPI_SUCCESS; MPID_MPI_STATE_DECL(MPID_STATE_MPI_TYPE_STRUCT); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_TYPE_STRUCT); /* Validate parameters, especially handles needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { int i; MPID_Datatype *datatype_ptr; MPIR_ERRTEST_COUNT(count,mpi_errno); if (count > 0) { MPIR_ERRTEST_ARGNULL(array_of_blocklengths, "array_of_blocklengths", mpi_errno); MPIR_ERRTEST_ARGNULL(array_of_displacements, "array_of_displacements", mpi_errno); MPIR_ERRTEST_ARGNULL(array_of_types, "array_of_types", mpi_errno); } for (i=0; i < count; i++) { MPIR_ERRTEST_ARGNEG(array_of_blocklengths[i], "blocklength", mpi_errno); MPIR_ERRTEST_DATATYPE(array_of_types[i], "datatype[i]", mpi_errno); if (array_of_types[i] != MPI_DATATYPE_NULL && HANDLE_GET_KIND(array_of_types[i]) != HANDLE_KIND_BUILTIN) { MPID_Datatype_get_ptr(array_of_types[i], datatype_ptr); MPID_Datatype_valid_ptr(datatype_ptr, mpi_errno); } } if (mpi_errno != MPI_SUCCESS) goto fn_fail; } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ mpi_errno = MPIR_Type_struct_impl(count, array_of_blocklengths, array_of_displacements, array_of_types, newtype); if (mpi_errno) goto fn_fail; /* ... end of body of routine ... */ fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_TYPE_STRUCT); MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX); return mpi_errno; fn_fail: /* --BEGIN ERROR HANDLING-- */ # ifdef HAVE_ERROR_CHECKING { mpi_errno = MPIR_Err_create_code( mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_type_struct", "**mpi_type_struct %d %p %p %p %p", count, array_of_blocklengths, array_of_displacements, array_of_types, newtype); } # endif mpi_errno = MPIR_Err_return_comm( NULL, FCNAME, mpi_errno ); goto fn_exit; /* --END ERROR HANDLING-- */ }