static int barrier_smp_intra(MPID_Comm *comm_ptr, mpir_errflag_t *errflag) { int mpi_errno=MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; MPIU_Assert(MPIR_CVAR_ENABLE_SMP_COLLECTIVES && MPIR_CVAR_ENABLE_SMP_BARRIER && MPIR_Comm_is_node_aware(comm_ptr)); /* do the intranode barrier on all nodes */ if (comm_ptr->node_comm != NULL) { mpi_errno = MPIR_Barrier_impl(comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* do the barrier across roots of all nodes */ if (comm_ptr->node_roots_comm != NULL) { mpi_errno = MPIR_Barrier_impl(comm_ptr->node_roots_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* release the local processes on each node with a 1-byte broadcast (0-byte broadcast just returns without doing anything) */ if (comm_ptr->node_comm != NULL) { int i=0; mpi_errno = MPIR_Bcast_impl(&i, 1, MPI_BYTE, 0, comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } fn_exit: if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag != MPIR_ERR_NONE) MPIU_ERR_SET(mpi_errno, *errflag, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Barrier_intra( MPID_Comm *comm_ptr, mpir_errflag_t *errflag ) { int size, rank, src, dst, mask, mpi_errno=MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; /* Only one collective operation per communicator can be active at any time */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); size = comm_ptr->local_size; /* Trivial barriers return immediately */ if (size == 1) goto fn_exit; if (MPIR_CVAR_ENABLE_SMP_COLLECTIVES && MPIR_CVAR_ENABLE_SMP_BARRIER && MPIR_Comm_is_node_aware(comm_ptr)) { mpi_errno = barrier_smp_intra(comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } goto fn_exit; } rank = comm_ptr->rank; mask = 0x1; while (mask < size) { dst = (rank + mask) % size; src = (rank - mask + size) % size; mpi_errno = MPIC_Sendrecv(NULL, 0, MPI_BYTE, dst, MPIR_BARRIER_TAG, NULL, 0, MPI_BYTE, src, MPIR_BARRIER_TAG, comm_ptr, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } mask <<= 1; } fn_exit: MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag != MPIR_ERR_NONE) MPIU_ERR_SET(mpi_errno, *errflag, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPID_nem_tcp_ckpt_continue_vc(MPIDI_VC_t *vc) { int mpi_errno = MPI_SUCCESS; MPID_PKT_DECL_CAST(upkt, MPIDI_nem_tcp_pkt_unpause_t, unpause_pkt); MPID_Request *unpause_req; MPIDI_STATE_DECL(MPID_STATE_MPID_NEM_TCP_CKPT_CONTINUE_VC); MPIDI_FUNC_ENTER(MPID_STATE_MPID_NEM_TCP_CKPT_CONTINUE_VC); unpause_pkt->type = MPIDI_NEM_PKT_NETMOD; unpause_pkt->subtype = MPIDI_NEM_TCP_PKT_UNPAUSE; mpi_errno = MPID_nem_tcp_iStartContigMsg_paused(vc, &upkt, sizeof(MPIDI_nem_tcp_pkt_unpause_t), NULL, 0, &unpause_req); if (mpi_errno) MPIU_ERR_POP(mpi_errno); if (unpause_req) { if (unpause_req->status.MPI_ERROR) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPID_Request_release(unpause_req); if (mpi_errno) goto fn_fail; } fn_exit: MPIDI_FUNC_EXIT(MPID_STATE_MPID_NEM_TCP_CKPT_CONTINUE_VC); return mpi_errno; fn_fail: goto fn_exit; }
/* This dequeues req from the posted recv queue, set req's error code to comm_fail, and updates the req pointer. Note that this creates a new error code if one hasn't already been created (i.e., if *error is MPI_SUCCESS). */ static inline void dequeue_and_set_error(MPID_Request **req, MPID_Request *prev_req, int *error, int rank) { MPID_Request *next = (*req)->dev.next; if (*error == MPI_SUCCESS) { if (rank == MPI_PROC_NULL) MPIU_ERR_SET(*error, MPIX_ERR_PROC_FAIL_STOP, "**comm_fail"); else MPIU_ERR_SET1(*error, MPIX_ERR_PROC_FAIL_STOP, "**comm_fail", "**comm_fail %d", rank); } /* remove from queue */ if (recvq_posted_head == *req) recvq_posted_head = (*req)->dev.next; else prev_req->dev.next = (*req)->dev.next; if (recvq_posted_tail == *req) recvq_posted_tail = prev_req; MPIR_T_DEC(RECVQ_STATISTICS, posted_qlen); /* set error and complete */ (*req)->status.MPI_ERROR = *error; MPIDI_CH3U_Request_complete(*req); MPIU_DBG_MSG_FMT(CH3_OTHER, VERBOSE, (MPIU_DBG_FDEST, "set error of req %p (%#08x) to %#x and completing.", *req, (*req)->handle, *error)); *req = next; }
int MPIR_Barrier_intra( MPID_Comm *comm_ptr, int *errflag ) { int size, rank, src, dst, mask, mpi_errno=MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; MPI_Comm comm; /* Only one collective operation per communicator can be active at any time */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); size = comm_ptr->local_size; /* Trivial barriers return immediately */ if (size == 1) goto fn_exit; rank = comm_ptr->rank; comm = comm_ptr->handle; mask = 0x1; while (mask < size) { dst = (rank + mask) % size; src = (rank - mask + size) % size; mpi_errno = MPIC_Sendrecv_ft(NULL, 0, MPI_BYTE, dst, MPIR_BARRIER_TAG, NULL, 0, MPI_BYTE, src, MPIR_BARRIER_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } mask <<= 1; } fn_exit: MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPID_nem_mx_improbe(MPIDI_VC_t *vc, int source, int tag, MPID_Comm *comm, int context_offset, int *flag, MPID_Request **message, MPI_Status *status) { int mpi_errno = MPI_SUCCESS; /* not currently implemented for MX */ MPIU_ERR_SET(mpi_errno, MPI_ERR_INTERN, "**nomprobe"); fn_exit: return mpi_errno; fn_fail: ATTRIBUTE((unused)) goto fn_exit; }
static inline int connection_post_recv_pkt(MPIDI_CH3I_Connection_t * conn) { int mpi_errno = MPI_SUCCESS; MPIDI_STATE_DECL(MPID_STATE_CONNECTION_POST_RECV_PKT); MPIDI_FUNC_ENTER(MPID_STATE_CONNECTION_POST_RECV_PKT); mpi_errno = MPIDU_Sock_post_read(conn->sock, &conn->pkt, sizeof(conn->pkt), sizeof(conn->pkt), NULL); if (mpi_errno != MPI_SUCCESS) { MPIU_ERR_SET(mpi_errno,MPI_ERR_OTHER, "**fail"); } MPIDI_FUNC_EXIT(MPID_STATE_CONNECTION_POST_RECV_PKT); return mpi_errno; }
int MPIR_Barrier_impl(MPID_Comm *comm_ptr, mpir_errflag_t *errflag) { int mpi_errno = MPI_SUCCESS; if (comm_ptr->coll_fns != NULL && comm_ptr->coll_fns->Barrier != NULL) { /* --BEGIN USEREXTENSION-- */ mpi_errno = comm_ptr->coll_fns->Barrier(comm_ptr, errflag); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* --END USEREXTENSION-- */ } else { mpi_errno = MPIR_Barrier(comm_ptr, errflag); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } fn_exit: if (*errflag != MPIR_ERR_NONE) MPIU_ERR_SET(mpi_errno, *errflag, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
/* Find the requested attribute. If it exists, return either the attribute entry or the address of the entry, based on whether the request is for a pointer-valued attribute (C or C++) or an integer-valued attribute (Fortran, either 77 or 90). If the attribute has the same type as the request, it is returned as-is. Otherwise, the address of the attribute is returned. */ int MPIR_CommGetAttr( MPI_Comm comm, int comm_keyval, void *attribute_val, int *flag, MPIR_AttrType outAttrType ) { static const char FCNAME[] = "MPIR_CommGetAttr"; int mpi_errno = MPI_SUCCESS; MPID_Comm *comm_ptr = NULL; static PreDefined_attrs attr_copy; /* Used to provide a copy of the predefined attributes */ MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_GET_ATTR); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_GET_ATTR); /* Validate parameters, especially handles needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPIR_ERRTEST_COMM(comm, mpi_errno); MPIR_ERRTEST_KEYVAL(comm_keyval, MPID_COMM, "communicator", mpi_errno); # ifdef NEEDS_POINTER_ALIGNMENT_ADJUST /* A common user error is to pass the address of a 4-byte int when the address of a pointer (or an address-sized int) should have been used. We can test for this specific case. Note that this code assumes sizeof(MPIR_Pint) is a power of 2. */ if ((MPIR_Pint)attribute_val & (sizeof(MPIR_Pint)-1)) { MPIU_ERR_SET(mpi_errno,MPI_ERR_ARG,"**attrnotptr"); } # endif 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, 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 */ MPIR_ERRTEST_ARGNULL(attribute_val, "attr_val", mpi_errno); MPIR_ERRTEST_ARGNULL(flag, "flag", mpi_errno); if (mpi_errno) goto fn_fail; } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ /* Check for builtin attribute */ /* This code is ok for correct programs, but it would be better to copy the values from the per-process block and pass the user a pointer to a copy */ /* Note that if we are called from Fortran, we must return the values, not the addresses, of these attributes */ if (HANDLE_GET_KIND(comm_keyval) == HANDLE_KIND_BUILTIN) { int attr_idx = comm_keyval & 0x0000000f; void **attr_val_p = (void **)attribute_val; #ifdef HAVE_FORTRAN_BINDING /* This is an address-sized int instead of a Fortran (MPI_Fint) integer because, even for the Fortran keyvals, the C interface is used which stores the result in a pointer (hence we need a pointer-sized int). Thus we use MPIR_Pint instead of MPI_Fint. On some 64-bit plaforms, such as Solaris-SPARC, using an MPI_Fint will cause the value to placed into the high, rather than low, end of the output value. */ #endif *flag = 1; /* FIXME : We could initialize some of these here; only tag_ub is used in the error checking. */ /* * The C versions of the attributes return the address of a * *COPY* of the value (to prevent the user from changing it) * and the Fortran versions provide the actual value (as an Fint) */ attr_copy = MPIR_Process.attrs; switch (attr_idx) { case 1: /* TAG_UB */ case 2: *attr_val_p = &attr_copy.tag_ub; break; case 3: /* HOST */ case 4: *attr_val_p = &attr_copy.host; break; case 5: /* IO */ case 6: *attr_val_p = &attr_copy.io; break; case 7: /* WTIME */ case 8: *attr_val_p = &attr_copy.wtime_is_global; break; case 9: /* UNIVERSE_SIZE */ case 10: /* This is a special case. If universe is not set, then we attempt to get it from the device. If the device is doesn't supply a value, then we set the flag accordingly */ if (attr_copy.universe >= 0) { *attr_val_p = &attr_copy.universe; } else if (attr_copy.universe == MPIR_UNIVERSE_SIZE_NOT_AVAILABLE) { *flag = 0; } else { mpi_errno = MPID_Get_universe_size(&attr_copy.universe); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno != MPI_SUCCESS) { attr_copy.universe = MPIR_UNIVERSE_SIZE_NOT_AVAILABLE; goto fn_fail; } /* --END ERROR HANDLING-- */ if (attr_copy.universe >= 0) { *attr_val_p = &attr_copy.universe; } else { attr_copy.universe = MPIR_UNIVERSE_SIZE_NOT_AVAILABLE; *flag = 0; } } break; case 11: /* LASTUSEDCODE */ case 12: *attr_val_p = &attr_copy.lastusedcode; break; case 13: /* APPNUM */ case 14: /* This is another special case. If appnum is negative, we take that as indicating no value of APPNUM, and set the flag accordingly */ if (attr_copy.appnum < 0) { *flag = 0; } else { *attr_val_p = &attr_copy.appnum; } break; } /* All of the predefined attributes are INTEGER; since we've set the output value as the pointer to these, we need to dereference it here. */ if (*flag) { /* Use the internal pointer-sized-int for systems (e.g., BG/P) that define MPI_Aint as a different size than MPIR_Pint. The casts must be as they are: On the right, the value is a pointer to an int, so to get the correct value, we need to extract the int. On the left, the output type is given by the argument outAttrType - and the cast must match the intended results */ if (outAttrType == MPIR_ATTR_AINT) *(MPIR_Pint*)attr_val_p = *(int*)*(void **)attr_val_p; else if (outAttrType == MPIR_ATTR_INT) *(int*)attr_val_p = *(int *)*(void **)attr_val_p; } } else { MPID_Attribute *p = comm_ptr->attributes; /* */ *flag = 0; while (p) { if (p->keyval->handle == comm_keyval) { *flag = 1; if (outAttrType == MPIR_ATTR_PTR) { if (p->attrType == MPIR_ATTR_INT) { /* This is the tricky case: if the system is bigendian, and we have to return a pointer to an int, then we may need to point to the correct location in the word. */ #if defined(WORDS_LITTLEENDIAN) || (SIZEOF_VOID_P == SIZEOF_INT) *(void**)attribute_val = &(p->value); #else int *p_loc = (int *)&(p->value); #if SIZEOF_VOID_P == 2 * SIZEOF_INT p_loc++; #else #error Expected sizeof(void*) to be either sizeof(int) or 2*sizeof(int) #endif *(void **)attribute_val = p_loc; #endif } else if (p->attrType == MPIR_ATTR_AINT) { *(void**)attribute_val = &(p->value); } else { *(void**)attribute_val = (void *)(MPIR_Pint)(p->value); } } else *(void**)attribute_val = (void *)(MPIR_Pint)(p->value); break; } p = p->next; } } /* ... end of body of routine ... */ fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_GET_ATTR); 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, "**mpir_comm_get_attr", "**mpir_comm_get_attr %C %d %p %p", comm, comm_keyval, attribute_val, flag); } # endif mpi_errno = MPIR_Err_return_comm( comm_ptr, FCNAME, mpi_errno ); goto fn_exit; /* --END ERROR HANDLING-- */ }
static int barrier_smp_intra(MPID_Comm *comm_ptr, MPIR_Errflag_t *errflag) { int mpi_errno=MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; MPIU_Assert(MPIR_CVAR_ENABLE_SMP_COLLECTIVES && MPIR_CVAR_ENABLE_SMP_BARRIER && MPIR_Comm_is_node_aware(comm_ptr)); #if defined(FINEGRAIN_MPI) int colocated_size = -1; int colocated_sense = -1; /* do barrier on osproc_colocated_comm */ if (comm_ptr->osproc_colocated_comm != NULL) { colocated_size = comm_ptr->osproc_colocated_comm->local_size; MPIU_Assert( (comm_ptr->osproc_colocated_comm->co_shared_vars != NULL) && (comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars != NULL) ); MPIU_Assert(colocated_size > 1 ); colocated_sense = comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_signal; if( comm_ptr->osproc_colocated_comm->rank != 0 ) { /* non-leader */ (comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_counter)++; if (comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_counter == (colocated_size-1)){ /* excluding the leader */ comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->leader_signal = 1; } while(comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_signal == colocated_sense) { FG_Yield(); } } else { /* leader */ while(comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->leader_signal == 0) { FG_Yield(); } } #if 0 /* Non-optimized version */ mpi_errno = MPIR_Barrier_impl(comm_ptr->osproc_colocated_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } #endif } #endif /* do the intranode barrier on all nodes */ if (comm_ptr->node_comm != NULL) { mpi_errno = MPIR_Barrier_impl(comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIR_ERR_SET(mpi_errno, *errflag, "**fail"); MPIR_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* do the barrier across roots of all nodes */ if (comm_ptr->node_roots_comm != NULL) { mpi_errno = MPIR_Barrier_impl(comm_ptr->node_roots_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIR_ERR_SET(mpi_errno, *errflag, "**fail"); MPIR_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* release the local processes on each node with a 1-byte broadcast (0-byte broadcast just returns without doing anything) */ if (comm_ptr->node_comm != NULL) { int i=0; mpi_errno = MPIR_Bcast_impl(&i, 1, MPI_BYTE, 0, comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIR_ERR_SET(mpi_errno, *errflag, "**fail"); MPIR_ERR_ADD(mpi_errno_ret, mpi_errno); } } #if defined(FINEGRAIN_MPI) if (comm_ptr->osproc_colocated_comm != NULL) { if (comm_ptr->osproc_colocated_comm->rank == 0) { /* leader */ comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->leader_signal = 0; comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_counter = 0; comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_signal = 1 - comm_ptr->osproc_colocated_comm->co_shared_vars->co_barrier_vars->coproclet_signal; } #if 0 /* Non-optimized version */ /* release the colocated processes in each OS-process with a 1-byte broadcast (0-byte broadcast just returns without doing anything) */ int i=0; mpi_errno = MPIR_Bcast_impl(&i, 1, MPI_BYTE, 0, comm_ptr->osproc_colocated_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } #endif } #endif fn_exit: if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag != MPIR_ERR_NONE) MPIR_ERR_SET(mpi_errno, *errflag, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
static int MPIR_Scan_generic ( const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, int *errflag ) { MPI_Status status; int rank, comm_size; int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; int mask, dst, is_commutative; MPI_Aint true_extent, true_lb, extent; void *partial_scan, *tmp_buf; MPID_Op *op_ptr; MPI_Comm comm; MPIU_THREADPRIV_DECL; MPIU_CHKLMEM_DECL(2); if (count == 0) return MPI_SUCCESS; /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); comm = comm_ptr->handle; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; MPIU_THREADPRIV_GET; /* set op_errno to 0. stored in perthread structure */ MPIU_THREADPRIV_FIELD(op_errno) = 0; if (HANDLE_GET_KIND(op) == HANDLE_KIND_BUILTIN) { is_commutative = 1; } else { MPID_Op_get_ptr(op, op_ptr); if (op_ptr->kind == MPID_OP_USER_NONCOMMUTE) is_commutative = 0; else is_commutative = 1; } /* need to allocate temporary buffer to store partial scan*/ MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); MPID_Datatype_get_extent_macro(datatype, extent); MPIU_CHKLMEM_MALLOC(partial_scan, void *, count*(MPIR_MAX(extent,true_extent)), mpi_errno, "partial_scan"); /* This eventually gets malloc()ed as a temp buffer, not added to * any user buffers */ MPID_Ensure_Aint_fits_in_pointer(count * MPIR_MAX(extent, true_extent)); /* adjust for potential negative lower bound in datatype */ partial_scan = (void *)((char*)partial_scan - true_lb); /* need to allocate temporary buffer to store incoming data*/ MPIU_CHKLMEM_MALLOC(tmp_buf, void *, count*(MPIR_MAX(extent,true_extent)), mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - true_lb); /* Since this is an inclusive scan, copy local contribution into recvbuf. */ if (sendbuf != MPI_IN_PLACE) { mpi_errno = MPIR_Localcopy(sendbuf, count, datatype, recvbuf, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } if (sendbuf != MPI_IN_PLACE) mpi_errno = MPIR_Localcopy(sendbuf, count, datatype, partial_scan, count, datatype); else mpi_errno = MPIR_Localcopy(recvbuf, count, datatype, partial_scan, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mask = 0x1; while (mask < comm_size) { dst = rank ^ mask; if (dst < comm_size) { /* Send partial_scan to dst. Recv into tmp_buf */ mpi_errno = MPIC_Sendrecv(partial_scan, count, datatype, dst, MPIR_SCAN_TAG, tmp_buf, count, datatype, dst, MPIR_SCAN_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } if (rank > dst) { mpi_errno = MPIR_Reduce_local_impl( tmp_buf, partial_scan, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPIR_Reduce_local_impl( tmp_buf, recvbuf, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } else { if (is_commutative) { mpi_errno = MPIR_Reduce_local_impl( tmp_buf, partial_scan, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } else { mpi_errno = MPIR_Reduce_local_impl( partial_scan, tmp_buf, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPIR_Localcopy(tmp_buf, count, datatype, partial_scan, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } } mask <<= 1; } if (MPIU_THREADPRIV_FIELD(op_errno)) { mpi_errno = MPIU_THREADPRIV_FIELD(op_errno); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } fn_exit: MPIU_CHKLMEM_FREEALL(); /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Comm_agree(MPID_Comm *comm_ptr, int *flag) { int mpi_errno = MPI_SUCCESS, mpi_errno_tmp = MPI_SUCCESS; MPID_Group *comm_grp, *failed_grp, *new_group_ptr, *global_failed; int result, success = 1; int errflag = 0; int values[2]; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_AGREE); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_AGREE); MPIR_Comm_group_impl(comm_ptr, &comm_grp); /* Get the locally known (not acknowledged) group of failed procs */ mpi_errno = MPID_Comm_failure_get_acked(comm_ptr, &failed_grp); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* First decide on the group of failed procs. */ mpi_errno = MPID_Comm_get_all_failed_procs(comm_ptr, &global_failed, MPIR_AGREE_TAG); if (mpi_errno) errflag = 1; mpi_errno = MPIR_Group_compare_impl(failed_grp, global_failed, &result); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* Create a subgroup without the failed procs */ mpi_errno = MPIR_Group_difference_impl(comm_grp, global_failed, &new_group_ptr); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* If that group isn't the same as what we think is failed locally, then * mark it as such. */ if (result == MPI_UNEQUAL || errflag) success = 0; /* Do an allreduce to decide whether or not anyone thinks the group * has changed */ mpi_errno_tmp = MPIR_Allreduce_group(MPI_IN_PLACE, &success, 1, MPI_INT, MPI_MIN, comm_ptr, new_group_ptr, MPIR_AGREE_TAG, &errflag); if (!success || errflag || mpi_errno_tmp) success = 0; values[0] = success; values[1] = *flag; /* Determine both the result of this function (mpi_errno) and the result * of flag that will be returned to the user. */ MPIR_Allreduce_group(MPI_IN_PLACE, values, 2, MPI_INT, MPI_BAND, comm_ptr, new_group_ptr, MPIR_AGREE_TAG, &errflag); /* Ignore the result of the operation this time. Everyone will either * return a failure because of !success earlier or they will return * something useful for flag because of this operation. If there was a new * failure in between the first allreduce and the second one, it's ignored * here. */ if (failed_grp != MPID_Group_empty) MPIR_Group_release(failed_grp); MPIR_Group_release(new_group_ptr); MPIR_Group_release(comm_grp); if (global_failed != MPID_Group_empty) MPIR_Group_release(global_failed); success = values[0]; *flag = values[1]; if (!success) { MPIU_ERR_SET(mpi_errno_tmp, MPIX_ERR_PROC_FAILED, "**mpix_comm_agree"); MPIU_ERR_ADD(mpi_errno, mpi_errno_tmp); } fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_AGREE); return mpi_errno; fn_fail: goto fn_exit; }
int MPID_Isend(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPID_Comm * comm, int context_offset, MPID_Request ** request) { MPIDI_msg_sz_t data_sz; int dt_contig; MPI_Aint dt_true_lb; MPID_Datatype * dt_ptr; MPID_Request * sreq; MPIDI_VC_t * vc=0; #if defined(MPID_USE_SEQUENCE_NUMBERS) MPID_Seqnum_t seqnum; #endif int mpi_errno = MPI_SUCCESS; MPIDI_STATE_DECL(MPID_STATE_MPID_ISEND); MPIDI_FUNC_ENTER(MPID_STATE_MPID_ISEND); MPIU_DBG_MSG_FMT(CH3_OTHER,VERBOSE,(MPIU_DBG_FDEST, "rank=%d, tag=%d, context=%d", rank, tag, comm->context_id + context_offset)); if (rank == comm->rank && comm->comm_kind != MPID_INTERCOMM) { #if defined (_OSU_PSM_) goto skip_self_send; /* psm will internally do self-send, no special handling is needed here */ #endif /* _OSU_PSM_ */ mpi_errno = MPIDI_Isend_self(buf, count, datatype, rank, tag, comm, context_offset, MPIDI_REQUEST_TYPE_SEND, &sreq); goto fn_exit; } #if defined (_OSU_PSM_) skip_self_send: #endif if (rank != MPI_PROC_NULL) { MPIDI_Comm_get_vc_set_active(comm, rank, &vc); #ifdef ENABLE_COMM_OVERRIDES /* this needs to come before the sreq is created, since the override * function is responsible for creating its own request */ if (vc->comm_ops && vc->comm_ops->isend) { mpi_errno = vc->comm_ops->isend( vc, buf, count, datatype, rank, tag, comm, context_offset, &sreq); goto fn_exit; } #endif } MPIDI_Request_create_sreq(sreq, mpi_errno, goto fn_exit); MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_SEND); if (rank == MPI_PROC_NULL) { MPIU_Object_set_ref(sreq, 1); MPID_cc_set(&sreq->cc, 0); goto fn_exit; } MPIDI_Datatype_get_info(count, datatype, dt_contig, data_sz, dt_ptr, dt_true_lb); if (data_sz == 0) { #if defined (_OSU_PSM_) goto eager_send; #endif /* _OSU_PSM_ */ MPIDI_CH3_Pkt_t upkt; MPIDI_CH3_Pkt_eager_send_t * const eager_pkt = &upkt.eager_send; MPIDI_Request_set_msg_type(sreq, MPIDI_REQUEST_EAGER_MSG); sreq->dev.OnDataAvail = 0; MPIU_DBG_MSG(CH3_OTHER,VERBOSE,"sending zero length message"); MPIDI_Pkt_init(eager_pkt, MPIDI_CH3_PKT_EAGER_SEND); eager_pkt->match.parts.rank = comm->rank; eager_pkt->match.parts.tag = tag; eager_pkt->match.parts.context_id = comm->context_id + context_offset; eager_pkt->sender_req_id = sreq->handle; eager_pkt->data_sz = 0; MPIDI_VC_FAI_send_seqnum(vc, seqnum); MPIDI_Pkt_set_seqnum(eager_pkt, seqnum); MPIDI_Request_set_seqnum(sreq, seqnum); MPIU_THREAD_CS_ENTER(CH3COMM,vc); mpi_errno = MPIU_CALL(MPIDI_CH3,iSend(vc, sreq, eager_pkt, sizeof(*eager_pkt))); MPIU_THREAD_CS_EXIT(CH3COMM,vc); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno != MPI_SUCCESS) { MPIU_Object_set_ref(sreq, 0); MPIDI_CH3_Request_destroy(sreq); sreq = NULL; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**ch3|eagermsg"); goto fn_exit; } /* --END ERROR HANDLING-- */ goto fn_exit; } #if defined (_OSU_PSM_) if(HANDLE_GET_KIND(datatype) != HANDLE_KIND_BUILTIN) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); sreq->psm_flags |= PSM_NEED_DTYPE_RELEASE; } if(vc->force_eager) goto eager_send; #endif /* _OSU_PSM_ */ #if defined(_OSU_MVAPICH_) int i; for (i = 0 ; i < rdma_num_extra_polls; i++) { if (rdma_global_ext_sendq_size > 1) MPID_Progress_test(); } #endif /* FIXME: flow control: limit number of outstanding eager messsages containing data and need to be buffered by the receiver */ #if defined(_OSU_MVAPICH_) if (data_sz + sizeof(MPIDI_CH3_Pkt_eager_send_t) <= vc->eager_max_msg_sz && !vc->force_rndv) #else /* defined(_OSU_MVAPICH_) */ if (data_sz + sizeof(MPIDI_CH3_Pkt_eager_send_t) <= vc->eager_max_msg_sz) #endif /* defined(_OSU_MVAPICH_) */ { #if defined (_OSU_PSM_) eager_send: #endif /* _OSU_PSM */ if (dt_contig) { mpi_errno = MPIDI_CH3_EagerContigIsend( &sreq, MPIDI_CH3_PKT_EAGER_SEND, (char*)buf + dt_true_lb, data_sz, rank, tag, comm, context_offset ); } else { #if defined (_OSU_PSM_) sreq->psm_flags |= PSM_NON_BLOCKING_SEND; #endif mpi_errno = MPIDI_CH3_EagerNoncontigSend( &sreq, MPIDI_CH3_PKT_EAGER_SEND, buf, count, datatype, data_sz, rank, tag, comm, context_offset ); #if defined (_OSU_PSM_) goto fn_exit; #endif /* If we're not complete, then add a reference to the datatype */ if (sreq && sreq->dev.OnDataAvail) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); } } } else { /* Note that the sreq was created above */ MPIDI_Request_set_msg_type( sreq, MPIDI_REQUEST_RNDV_MSG ); mpi_errno = vc->rndvSend_fn( &sreq, buf, count, datatype, dt_contig, data_sz, dt_true_lb, rank, tag, comm, context_offset ); /* FIXME: fill temporary IOV or pack temporary buffer after send to hide some latency. This requires synchronization because the CTS packet could arrive and be processed before the above iStartmsg completes (depending on the progress engine, threads, etc.). */ #if defined(_OSU_MVAPICH_) /* rndv transfers need to process CTS packet to initiate the actual RDMA transfer */ MPID_Progress_test(); #endif /* defined(_OSU_MVAPICH_) */ if (sreq && dt_ptr != NULL) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); } } fn_exit: *request = sreq; #if defined(_OSU_MVAPICH_) for (i = 0 ; i < rdma_num_extra_polls; i++) { if (rdma_global_ext_sendq_size > 1) MPID_Progress_test(); } #endif MPIU_DBG_STMT(CH3_OTHER,VERBOSE, { if (sreq != NULL) { MPIU_DBG_MSG_P(CH3_OTHER,VERBOSE,"request allocated, handle=0x%08x", sreq->handle); } } );
static int MPIR_Reduce_scatter_block_noncomm ( const void *sendbuf, void *recvbuf, int recvcount, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, int *errflag ) { int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; int comm_size = comm_ptr->local_size; int rank = comm_ptr->rank; int pof2; int log2_comm_size; int i, k; int recv_offset, send_offset; int block_size, total_count, size; MPI_Aint true_extent, true_lb; int buf0_was_inout; void *tmp_buf0; void *tmp_buf1; void *result_ptr; MPI_Comm comm = comm_ptr->handle; MPIU_CHKLMEM_DECL(3); MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); pof2 = 1; log2_comm_size = 0; while (pof2 < comm_size) { pof2 <<= 1; ++log2_comm_size; } /* begin error checking */ MPIU_Assert(pof2 == comm_size); /* FIXME this version only works for power of 2 procs */ /* end error checking */ /* size of a block (count of datatype per block, NOT bytes per block) */ block_size = recvcount; total_count = block_size * comm_size; MPIU_CHKLMEM_MALLOC(tmp_buf0, void *, true_extent * total_count, mpi_errno, "tmp_buf0"); MPIU_CHKLMEM_MALLOC(tmp_buf1, void *, true_extent * total_count, mpi_errno, "tmp_buf1"); /* adjust for potential negative lower bound in datatype */ tmp_buf0 = (void *)((char*)tmp_buf0 - true_lb); tmp_buf1 = (void *)((char*)tmp_buf1 - true_lb); /* Copy our send data to tmp_buf0. We do this one block at a time and permute the blocks as we go according to the mirror permutation. */ for (i = 0; i < comm_size; ++i) { mpi_errno = MPIR_Localcopy((char *)(sendbuf == MPI_IN_PLACE ? recvbuf : sendbuf) + (i * true_extent * block_size), block_size, datatype, (char *)tmp_buf0 + (MPIU_Mirror_permutation(i, log2_comm_size) * true_extent * block_size), block_size, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } buf0_was_inout = 1; send_offset = 0; recv_offset = 0; size = total_count; for (k = 0; k < log2_comm_size; ++k) { /* use a double-buffering scheme to avoid local copies */ char *incoming_data = (buf0_was_inout ? tmp_buf1 : tmp_buf0); char *outgoing_data = (buf0_was_inout ? tmp_buf0 : tmp_buf1); int peer = rank ^ (0x1 << k); size /= 2; if (rank > peer) { /* we have the higher rank: send top half, recv bottom half */ recv_offset += size; } else { /* we have the lower rank: recv top half, send bottom half */ send_offset += size; } mpi_errno = MPIC_Sendrecv_ft(outgoing_data + send_offset*true_extent, size, datatype, peer, MPIR_REDUCE_SCATTER_BLOCK_TAG, incoming_data + recv_offset*true_extent, size, datatype, peer, MPIR_REDUCE_SCATTER_BLOCK_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* always perform the reduction at recv_offset, the data at send_offset is now our peer's responsibility */ if (rank > peer) { /* higher ranked value so need to call op(received_data, my_data) */ mpi_errno = MPIR_Reduce_local_impl( incoming_data + recv_offset*true_extent, outgoing_data + recv_offset*true_extent, size, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); buf0_was_inout = buf0_was_inout; } else { /* lower ranked value so need to call op(my_data, received_data) */ mpi_errno = MPIR_Reduce_local_impl( outgoing_data + recv_offset*true_extent, incoming_data + recv_offset*true_extent, size, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); buf0_was_inout = !buf0_was_inout; } /* the next round of send/recv needs to happen within the block (of size "size") that we just received and reduced */ send_offset = recv_offset; } MPIU_Assert(size == recvcount); /* copy the reduced data to the recvbuf */ result_ptr = (char *)(buf0_was_inout ? tmp_buf0 : tmp_buf1) + recv_offset * true_extent; mpi_errno = MPIR_Localcopy(result_ptr, size, datatype, recvbuf, size, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); fn_exit: MPIU_CHKLMEM_FREEALL(); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); /* --END ERROR HANDLING-- */ return mpi_errno; fn_fail: goto fn_exit; }
MPID_Request * MPIDI_CH3U_Recvq_FDU_or_AEP(int source, int tag, int context_id, MPID_Comm *comm, void *user_buf, int user_count, MPI_Datatype datatype, int * foundp) { MPID_Time_t timer_start; int found; MPID_Request *rreq, *prev_rreq; MPIDI_Message_match match; MPIDI_Message_match mask; MPIDI_STATE_DECL(MPID_STATE_MPIDI_CH3U_RECVQ_FDU_OR_AEP); MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_CH3U_RECVQ_FDU_OR_AEP); MPIU_THREAD_CS_ASSERT_HELD(MSGQUEUE); /* Store how much time is spent traversing the queue */ MPIR_T_START_TIMER(RECVQ_STATISTICS, timer_start); /* Optimize this loop for an empty unexpected receive queue */ rreq = recvq_unexpected_head; if (rreq) { prev_rreq = NULL; match.parts.context_id = context_id; match.parts.tag = tag; match.parts.rank = source; if (tag != MPI_ANY_TAG && source != MPI_ANY_SOURCE) { do { MPIR_T_INC(RECVQ_STATISTICS, unexpected_recvq_match_attempts); if (MATCH_WITH_NO_MASK(rreq->dev.match, match)) { if (prev_rreq != NULL) { prev_rreq->dev.next = rreq->dev.next; } else { recvq_unexpected_head = rreq->dev.next; } if (rreq->dev.next == NULL) { recvq_unexpected_tail = prev_rreq; } MPIR_T_DEC(RECVQ_STATISTICS, unexpected_qlen); if (MPIDI_Request_get_msg_type(rreq) == MPIDI_REQUEST_EAGER_MSG) MPIR_T_SUBTRACT(RECVQ_STATISTICS, MPIDI_CH3I_unexpected_recvq_buffer_size, rreq->dev.tmpbuf_sz); rreq->comm = comm; MPIR_Comm_add_ref(comm); rreq->dev.user_buf = user_buf; rreq->dev.user_count = user_count; rreq->dev.datatype = datatype; found = TRUE; goto lock_exit; } prev_rreq = rreq; rreq = rreq->dev.next; } while (rreq); } else { mask.parts.context_id = mask.parts.rank = mask.parts.tag = ~0; if (tag == MPI_ANY_TAG) match.parts.tag = mask.parts.tag = 0; if (source == MPI_ANY_SOURCE) match.parts.rank = mask.parts.rank = 0; do { MPIR_T_INC(RECVQ_STATISTICS, unexpected_recvq_match_attempts); if (MATCH_WITH_LEFT_MASK(rreq->dev.match, match, mask)) { if (prev_rreq != NULL) { prev_rreq->dev.next = rreq->dev.next; } else { recvq_unexpected_head = rreq->dev.next; } if (rreq->dev.next == NULL) { recvq_unexpected_tail = prev_rreq; } MPIR_T_DEC(RECVQ_STATISTICS, unexpected_qlen); if (MPIDI_Request_get_msg_type(rreq) == MPIDI_REQUEST_EAGER_MSG) MPIR_T_SUBTRACT(RECVQ_STATISTICS, MPIDI_CH3I_unexpected_recvq_buffer_size, rreq->dev.tmpbuf_sz); rreq->comm = comm; MPIR_Comm_add_ref(comm); rreq->dev.user_buf = user_buf; rreq->dev.user_count = user_count; rreq->dev.datatype = datatype; found = TRUE; goto lock_exit; } prev_rreq = rreq; rreq = rreq->dev.next; } while (rreq); } } MPIR_T_END_TIMER(RECVQ_STATISTICS, timer_start, time_matching_unexpectedq); /* A matching request was not found in the unexpected queue, so we need to allocate a new request and add it to the posted queue */ { int mpi_errno = MPI_SUCCESS; found = FALSE; MPIDI_Request_create_rreq( rreq, mpi_errno, goto lock_exit ); rreq->dev.match.parts.tag = tag; rreq->dev.match.parts.rank = source; rreq->dev.match.parts.context_id = context_id; /* Added a mask for faster search on 64-bit capable * platforms */ rreq->dev.mask.parts.context_id = ~0; if (rreq->dev.match.parts.rank == MPI_ANY_SOURCE) rreq->dev.mask.parts.rank = 0; else rreq->dev.mask.parts.rank = ~0; if (rreq->dev.match.parts.tag == MPI_ANY_TAG) rreq->dev.mask.parts.tag = 0; else rreq->dev.mask.parts.tag = ~0; rreq->comm = comm; MPIR_Comm_add_ref(comm); rreq->dev.user_buf = user_buf; rreq->dev.user_count = user_count; rreq->dev.datatype = datatype; /* check whether VC has failed, or this is an ANY_SOURCE in a failed communicator */ if (source != MPI_ANY_SOURCE) { MPIDI_VC_t *vc; MPIDI_Comm_get_vc(comm, source, &vc); if (vc->state == MPIDI_VC_STATE_MORIBUND) { MPIU_ERR_SET1(mpi_errno, MPIX_ERR_PROC_FAIL_STOP, "**comm_fail", "**comm_fail %d", vc->pg_rank); rreq->status.MPI_ERROR = mpi_errno; MPIDI_CH3U_Request_complete(rreq); goto lock_exit; } } else if (!MPIDI_CH3I_Comm_AS_enabled(comm)) { MPIU_ERR_SET(mpi_errno, MPIX_ERR_PROC_FAIL_STOP, "**comm_fail"); rreq->status.MPI_ERROR = mpi_errno; MPIDI_CH3U_Request_complete(rreq); goto lock_exit; } rreq->dev.next = NULL; if (recvq_posted_tail != NULL) { recvq_posted_tail->dev.next = rreq; } else { recvq_posted_head = rreq; } recvq_posted_tail = rreq; MPIR_T_INC(RECVQ_STATISTICS, posted_qlen); MPIDI_POSTED_RECV_ENQUEUE_HOOK(rreq); } lock_exit: *foundp = found; /* If a match was not found, the timer was stopped after the traversal */ if (found) MPIR_T_END_TIMER(RECVQ_STATISTICS, timer_start, time_matching_unexpectedq); MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_CH3U_RECVQ_FDU_OR_AEP); return rreq; }
/*@ MPI_Win_lock - Begin an RMA access epoch at the target process. Input Parameters: + lock_type - Indicates whether other processes may access the target window at the same time (if 'MPI_LOCK_SHARED') or not ('MPI_LOCK_EXCLUSIVE') . rank - rank of locked window (nonnegative integer) . assert - Used to optimize this call; zero may be used as a default. See notes. (integer) - win - window object (handle) Notes: The name of this routine is misleading. In particular, this routine need not block, except when the target process is the calling process. Implementations may restrict the use of RMA communication that is synchronized by lock calls to windows in memory allocated by 'MPI_Alloc_mem'. Locks can be used portably only in such memory. The 'assert' argument is used to indicate special conditions for the fence that an implementation may use to optimize the 'MPI_Win_lock' operation. The value zero is always correct. Other assertion values may be or''ed together. Assertions that are valid for 'MPI_Win_lock' are\: . MPI_MODE_NOCHECK - no other process holds, or will attempt to acquire a conflicting lock, while the caller holds the window lock. This is useful when mutual exclusion is achieved by other means, but the coherence operations that may be attached to the lock and unlock calls are still required. .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS .N MPI_ERR_RANK .N MPI_ERR_WIN .N MPI_ERR_OTHER @*/ int MPI_Win_lock(int lock_type, int rank, int assert, MPI_Win win) { static const char FCNAME[] = "MPI_Win_lock"; int mpi_errno = MPI_SUCCESS; MPID_Win *win_ptr = NULL; MPID_MPI_STATE_DECL(MPID_STATE_MPI_WIN_LOCK); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPIU_THREAD_CS_ENTER(ALLFUNC,); MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_WIN_LOCK); /* Validate parameters, especially handles needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPIR_ERRTEST_WIN(win, mpi_errno); if (mpi_errno != MPI_SUCCESS) goto fn_fail; } MPID_END_ERROR_CHECKS; } # endif /* Convert MPI object handles to object pointers */ MPID_Win_get_ptr( win, win_ptr ); /* Validate parameters and objects (post conversion) */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPID_Comm *comm_ptr; /* Validate win_ptr */ MPID_Win_valid_ptr( win_ptr, mpi_errno ); /* If win_ptr is not value, it will be reset to null */ if (mpi_errno) goto fn_fail; if (assert != 0 && assert != MPI_MODE_NOCHECK) { MPIU_ERR_SET1(mpi_errno,MPI_ERR_ARG, "**lockassertval", "**lockassertval %d", assert ); if (mpi_errno) goto fn_fail; } if (lock_type != MPI_LOCK_SHARED && lock_type != MPI_LOCK_EXCLUSIVE) { MPIU_ERR_SET(mpi_errno,MPI_ERR_OTHER, "**locktype" ); } if (win_ptr->lockRank != -1) { MPIU_ERR_SET1(mpi_errno,MPI_ERR_OTHER, "**lockwhilelocked", "**lockwhilelocked %d", win_ptr->lockRank ); } comm_ptr = win_ptr->comm_ptr; MPIR_ERRTEST_SEND_RANK(comm_ptr, rank, mpi_errno); if (mpi_errno) goto fn_fail; } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ mpi_errno = MPIU_RMA_CALL(win_ptr, Win_lock(lock_type, rank, assert, win_ptr)); if (mpi_errno != MPI_SUCCESS) goto fn_fail; /* If the lock succeeded, remember which one with locked */ win_ptr->lockRank = rank; /* ... end of body of routine ... */ fn_exit: MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_WIN_LOCK); MPIU_THREAD_CS_EXIT(ALLFUNC,); 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_win_lock", "**mpi_win_lock %d %d %A %W", lock_type, rank, assert, win); } # endif mpi_errno = MPIR_Err_return_win( win_ptr, FCNAME, mpi_errno ); goto fn_exit; /* --END ERROR HANDLING-- */ }
int MPIR_Bcast_inter_MV2 ( void *buffer, int count, MPI_Datatype datatype, int root, MPID_Comm *comm_ptr, int *errflag) { /* Intercommunicator broadcast. Root sends to rank 0 in remote group. Remote group does local intracommunicator broadcast. */ int rank, mpi_errno; int mpi_errno_ret = MPI_SUCCESS; MPI_Status status; MPID_Comm *newcomm_ptr = NULL; MPI_Comm comm; MPID_MPI_STATE_DECL(MPID_STATE_MPIR_BCAST_INTER); MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_BCAST_INTER); comm = comm_ptr->handle; if (root == MPI_PROC_NULL) { /* local processes other than root do nothing */ mpi_errno = MPI_SUCCESS; } else if (root == MPI_ROOT) { /* root sends to rank 0 on remote group and returns */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); mpi_errno = MPIC_Send_ft(buffer, count, datatype, 0, MPIR_BCAST_TAG, comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); } else { /* remote group. rank 0 on remote group receives from root */ rank = comm_ptr->rank; if (rank == 0) { mpi_errno = MPIC_Recv_ft(buffer, count, datatype, root, MPIR_BCAST_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* Get the local intracommunicator */ if (!comm_ptr->local_comm) { MPIR_Setup_intercomm_localcomm( comm_ptr ); } newcomm_ptr = comm_ptr->local_comm; /* now do the usual broadcast on this intracommunicator with rank 0 as root. */ mpi_errno = MPIR_Bcast_intra_MV2(buffer, count, datatype, 0, newcomm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_BCAST_INTER); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; }
int MPIR_Barrier_impl(MPID_Comm *comm_ptr, int *errflag) { int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; if (comm_ptr->coll_fns != NULL && comm_ptr->coll_fns->Barrier != NULL) { mpi_errno = comm_ptr->coll_fns->Barrier(comm_ptr, errflag); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } else { if (comm_ptr->comm_kind == MPID_INTRACOMM) { #if defined(USE_SMP_COLLECTIVES) if (MPIR_Comm_is_node_aware(comm_ptr)) { /* do the intranode barrier on all nodes */ if (comm_ptr->node_comm != NULL) { mpi_errno = MPIR_Barrier_or_coll_fn(comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* do the barrier across roots of all nodes */ if (comm_ptr->node_roots_comm != NULL) { mpi_errno = MPIR_Barrier_or_coll_fn(comm_ptr->node_roots_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* release the local processes on each node with a 1-byte broadcast (0-byte broadcast just returns without doing anything) */ if (comm_ptr->node_comm != NULL) { int i=0; mpi_errno = MPIR_Bcast_impl(&i, 1, MPI_BYTE, 0, comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } } else { mpi_errno = MPIR_Barrier_intra( comm_ptr, errflag ); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } #else mpi_errno = MPIR_Barrier_intra( comm_ptr, errflag ); if (mpi_errno) MPIU_ERR_POP(mpi_errno); #endif } else { /* intercommunicator */ mpi_errno = MPIR_Barrier_inter( comm_ptr, errflag ); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } fn_exit: if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Barrier_inter( MPID_Comm *comm_ptr, mpir_errflag_t *errflag ) { int rank, mpi_errno = MPI_SUCCESS, root; int mpi_errno_ret = MPI_SUCCESS; int i = 0; MPID_Comm *newcomm_ptr = NULL; rank = comm_ptr->rank; /* Get the local intracommunicator */ if (!comm_ptr->local_comm) { mpi_errno = MPIR_Setup_intercomm_localcomm( comm_ptr ); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } newcomm_ptr = comm_ptr->local_comm; /* do a barrier on the local intracommunicator */ mpi_errno = MPIR_Barrier_intra(newcomm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* rank 0 on each group does an intercommunicator broadcast to the remote group to indicate that all processes in the local group have reached the barrier. We do a 1-byte bcast because a 0-byte bcast will just return without doing anything. */ /* first broadcast from left to right group, then from right to left group */ if (comm_ptr->is_low_group) { /* bcast to right*/ root = (rank == 0) ? MPI_ROOT : MPI_PROC_NULL; mpi_errno = MPIR_Bcast_inter(&i, 1, MPI_BYTE, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* receive bcast from right */ root = 0; mpi_errno = MPIR_Bcast_inter(&i, 1, MPI_BYTE, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } else { /* receive bcast from left */ root = 0; mpi_errno = MPIR_Bcast_inter(&i, 1, MPI_BYTE, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* bcast to left */ root = (rank == 0) ? MPI_ROOT : MPI_PROC_NULL; mpi_errno = MPIR_Bcast_inter(&i, 1, MPI_BYTE, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = MPIR_ERR_GET_CLASS(mpi_errno); MPIU_ERR_SET(mpi_errno, *errflag, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } fn_exit: if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag != MPIR_ERR_NONE) MPIU_ERR_SET(mpi_errno, *errflag, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPID_Isend(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPID_Comm * comm, int context_offset, MPID_Request ** request) { MPIDI_msg_sz_t data_sz; int dt_contig; MPI_Aint dt_true_lb; MPID_Datatype * dt_ptr; MPID_Request * sreq; MPIDI_VC_t * vc=0; #if defined(MPID_USE_SEQUENCE_NUMBERS) MPID_Seqnum_t seqnum; #endif int eager_threshold = -1; int mpi_errno = MPI_SUCCESS; MPIDI_STATE_DECL(MPID_STATE_MPID_ISEND); MPIDI_FUNC_ENTER(MPID_STATE_MPID_ISEND); MPIU_DBG_MSG_FMT(CH3_OTHER,VERBOSE,(MPIU_DBG_FDEST, "rank=%d, tag=%d, context=%d", rank, tag, comm->context_id + context_offset)); if (rank == comm->rank && comm->comm_kind != MPID_INTERCOMM) { mpi_errno = MPIDI_Isend_self(buf, count, datatype, rank, tag, comm, context_offset, MPIDI_REQUEST_TYPE_SEND, &sreq); goto fn_exit; } if (rank != MPI_PROC_NULL) { MPIDI_Comm_get_vc_set_active(comm, rank, &vc); #ifdef ENABLE_COMM_OVERRIDES /* this needs to come before the sreq is created, since the override * function is responsible for creating its own request */ if (vc->comm_ops && vc->comm_ops->isend) { mpi_errno = vc->comm_ops->isend( vc, buf, count, datatype, rank, tag, comm, context_offset, &sreq); goto fn_exit; } #endif } MPIDI_Request_create_sreq(sreq, mpi_errno, goto fn_exit); MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_SEND); if (rank == MPI_PROC_NULL) { MPIU_Object_set_ref(sreq, 1); MPID_cc_set(&sreq->cc, 0); goto fn_exit; } MPIDI_Datatype_get_info(count, datatype, dt_contig, data_sz, dt_ptr, dt_true_lb); if (data_sz == 0) { MPIDI_CH3_Pkt_t upkt; MPIDI_CH3_Pkt_eager_send_t * const eager_pkt = &upkt.eager_send; MPIDI_Request_set_msg_type(sreq, MPIDI_REQUEST_EAGER_MSG); sreq->dev.OnDataAvail = 0; MPIU_DBG_MSG(CH3_OTHER,VERBOSE,"sending zero length message"); MPIDI_Pkt_init(eager_pkt, MPIDI_CH3_PKT_EAGER_SEND); eager_pkt->match.parts.rank = comm->rank; eager_pkt->match.parts.tag = tag; eager_pkt->match.parts.context_id = comm->context_id + context_offset; eager_pkt->sender_req_id = sreq->handle; eager_pkt->data_sz = 0; MPIDI_VC_FAI_send_seqnum(vc, seqnum); MPIDI_Pkt_set_seqnum(eager_pkt, seqnum); MPIDI_Request_set_seqnum(sreq, seqnum); MPIU_THREAD_CS_ENTER(CH3COMM,vc); mpi_errno = MPIDI_CH3_iSend(vc, sreq, eager_pkt, sizeof(*eager_pkt)); MPIU_THREAD_CS_EXIT(CH3COMM,vc); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno != MPI_SUCCESS) { MPIU_Object_set_ref(sreq, 0); MPIDI_CH3_Request_destroy(sreq); sreq = NULL; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**ch3|eagermsg"); goto fn_exit; } /* --END ERROR HANDLING-- */ goto fn_exit; } MPIDI_CH3_GET_EAGER_THRESHOLD(&eager_threshold, comm, vc); /* FIXME: flow control: limit number of outstanding eager messages containing data and need to be buffered by the receiver */ if (data_sz + sizeof(MPIDI_CH3_Pkt_eager_send_t) <= eager_threshold) { if (dt_contig) { mpi_errno = MPIDI_CH3_EagerContigIsend( &sreq, MPIDI_CH3_PKT_EAGER_SEND, (char*)buf + dt_true_lb, data_sz, rank, tag, comm, context_offset ); } else { mpi_errno = MPIDI_CH3_EagerNoncontigSend( &sreq, MPIDI_CH3_PKT_EAGER_SEND, buf, count, datatype, data_sz, rank, tag, comm, context_offset ); /* If we're not complete, then add a reference to the datatype */ if (sreq && sreq->dev.OnDataAvail) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); } } } else { /* Note that the sreq was created above */ MPIDI_Request_set_msg_type( sreq, MPIDI_REQUEST_RNDV_MSG ); mpi_errno = vc->rndvSend_fn( &sreq, buf, count, datatype, dt_contig, data_sz, dt_true_lb, rank, tag, comm, context_offset ); /* FIXME: fill temporary IOV or pack temporary buffer after send to hide some latency. This requires synchronization because the CTS packet could arrive and be processed before the above iStartmsg completes (depending on the progress engine, threads, etc.). */ if (sreq && dt_ptr != NULL) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); } } fn_exit: *request = sreq; MPIU_DBG_STMT(CH3_OTHER,VERBOSE, { if (sreq != NULL) { MPIU_DBG_MSG_P(CH3_OTHER,VERBOSE,"request allocated, handle=0x%08x", sreq->handle); } } );
int MPIR_Exscan ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, int *errflag ) { MPI_Status status; int rank, comm_size; int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; int mask, dst, is_commutative, flag; MPI_Aint true_extent, true_lb, extent; void *partial_scan, *tmp_buf; MPI_User_function *uop; MPID_Op *op_ptr; MPI_Comm comm; MPIU_CHKLMEM_DECL(2); MPIU_THREADPRIV_DECL; #ifdef HAVE_CXX_BINDING int is_cxx_uop = 0; #endif if (count == 0) return MPI_SUCCESS; MPIU_THREADPRIV_GET; comm = comm_ptr->handle; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; /* set op_errno to 0. stored in perthread structure */ MPIU_THREADPRIV_FIELD(op_errno) = 0; if (HANDLE_GET_KIND(op) == HANDLE_KIND_BUILTIN) { is_commutative = 1; /* get the function by indexing into the op table */ uop = MPIR_Op_table[op%16 - 1]; } else { MPID_Op_get_ptr(op, op_ptr); if (op_ptr->kind == MPID_OP_USER_NONCOMMUTE) is_commutative = 0; else is_commutative = 1; #ifdef HAVE_CXX_BINDING if (op_ptr->language == MPID_LANG_CXX) { uop = (MPI_User_function *) op_ptr->function.c_function; is_cxx_uop = 1; } else #endif if ((op_ptr->language == MPID_LANG_C)) uop = (MPI_User_function *) op_ptr->function.c_function; else uop = (MPI_User_function *) op_ptr->function.f77_function; } /* need to allocate temporary buffer to store partial scan*/ MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); MPID_Datatype_get_extent_macro( datatype, extent ); MPIU_CHKLMEM_MALLOC(partial_scan, void *, (count*(MPIR_MAX(true_extent,extent))), mpi_errno, "partial_scan"); /* adjust for potential negative lower bound in datatype */ partial_scan = (void *)((char*)partial_scan - true_lb); /* need to allocate temporary buffer to store incoming data*/ MPIU_CHKLMEM_MALLOC(tmp_buf, void *, (count*(MPIR_MAX(true_extent,extent))), mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - true_lb); mpi_errno = MPIR_Localcopy((sendbuf == MPI_IN_PLACE ? recvbuf : sendbuf), count, datatype, partial_scan, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); flag = 0; mask = 0x1; while (mask < comm_size) { dst = rank ^ mask; if (dst < comm_size) { /* Send partial_scan to dst. Recv into tmp_buf */ mpi_errno = MPIC_Sendrecv_ft(partial_scan, count, datatype, dst, MPIR_EXSCAN_TAG, tmp_buf, count, datatype, dst, MPIR_EXSCAN_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } if (rank > dst) { call_uop(tmp_buf, partial_scan, count, datatype); /* On rank 0, recvbuf is not defined. For sendbuf==MPI_IN_PLACE recvbuf must not change (per MPI-2.2). On rank 1, recvbuf is to be set equal to the value in sendbuf on rank 0. On others, recvbuf is the scan of values in the sendbufs on lower ranks. */ if (rank != 0) { if (flag == 0) { /* simply copy data recd from rank 0 into recvbuf */ mpi_errno = MPIR_Localcopy(tmp_buf, count, datatype, recvbuf, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); flag = 1; } else { call_uop(tmp_buf, recvbuf, count, datatype); } } } else { if (is_commutative) { call_uop(tmp_buf, partial_scan, count, datatype); } else { call_uop(partial_scan, tmp_buf, count, datatype); mpi_errno = MPIR_Localcopy(tmp_buf, count, datatype, partial_scan, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } } mask <<= 1; } /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); if (MPIU_THREADPRIV_FIELD(op_errno)) mpi_errno = MPIU_THREADPRIV_FIELD(op_errno); fn_exit: MPIU_CHKLMEM_FREEALL(); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Allreduce_intra ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, int *errflag ) { int is_homogeneous; #ifdef MPID_HAS_HETERO int rc; #endif int comm_size, rank, type_size; int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; int mask, dst, is_commutative, pof2, newrank, rem, newdst, i, send_idx, recv_idx, last_idx, send_cnt, recv_cnt, *cnts, *disps; MPI_Aint true_extent, true_lb, extent; void *tmp_buf; MPI_Comm comm; MPIU_CHKLMEM_DECL(3); /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); if (count == 0) goto fn_exit; comm = comm_ptr->handle; is_commutative = MPIR_Op_is_commutative(op); #if defined(USE_SMP_COLLECTIVES) /* is the op commutative? We do SMP optimizations only if it is. */ if (MPIR_Comm_is_node_aware(comm_ptr) && is_commutative) { /* on each node, do a reduce to the local root */ if (comm_ptr->node_comm != NULL) { /* take care of the MPI_IN_PLACE case. For reduce, MPI_IN_PLACE is specified only on the root; for allreduce it is specified on all processes. */ if ((sendbuf == MPI_IN_PLACE) && (comm_ptr->node_comm->rank != 0)) { /* IN_PLACE and not root of reduce. Data supplied to this allreduce is in recvbuf. Pass that as the sendbuf to reduce. */ mpi_errno = MPIR_Reduce_impl(recvbuf, NULL, count, datatype, op, 0, comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } else { mpi_errno = MPIR_Reduce_impl(sendbuf, recvbuf, count, datatype, op, 0, comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } } else { /* only one process on the node. copy sendbuf to recvbuf */ if (sendbuf != MPI_IN_PLACE) { mpi_errno = MPIR_Localcopy(sendbuf, count, datatype, recvbuf, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } /* now do an IN_PLACE allreduce among the local roots of all nodes */ if (comm_ptr->node_roots_comm != NULL) { mpi_errno = allreduce_intra_or_coll_fn(MPI_IN_PLACE, recvbuf, count, datatype, op, comm_ptr->node_roots_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* now broadcast the result among local processes */ if (comm_ptr->node_comm != NULL) { mpi_errno = MPIR_Bcast_impl(recvbuf, count, datatype, 0, comm_ptr->node_comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } goto fn_exit; } #endif is_homogeneous = 1; #ifdef MPID_HAS_HETERO if (comm_ptr->is_hetero) is_homogeneous = 0; #endif #ifdef MPID_HAS_HETERO if (!is_homogeneous) { /* heterogeneous. To get the same result on all processes, we do a reduce to 0 and then broadcast. */ mpi_errno = MPIR_Reduce_impl ( sendbuf, recvbuf, count, datatype, op, 0, comm_ptr, errflag ); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } mpi_errno = MPIR_Bcast_impl( recvbuf, count, datatype, 0, comm_ptr, errflag ); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } else #endif /* MPID_HAS_HETERO */ { /* homogeneous */ comm_size = comm_ptr->local_size; rank = comm_ptr->rank; is_commutative = MPIR_Op_is_commutative(op); /* need to allocate temporary buffer to store incoming data*/ MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); MPID_Datatype_get_extent_macro(datatype, extent); MPID_Ensure_Aint_fits_in_pointer(count * MPIR_MAX(extent, true_extent)); MPIU_CHKLMEM_MALLOC(tmp_buf, void *, count*(MPIR_MAX(extent,true_extent)), mpi_errno, "temporary buffer"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - true_lb); /* copy local data into recvbuf */ if (sendbuf != MPI_IN_PLACE) { mpi_errno = MPIR_Localcopy(sendbuf, count, datatype, recvbuf, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } MPID_Datatype_get_size_macro(datatype, type_size); /* find nearest power-of-two less than or equal to comm_size */ pof2 = 1; while (pof2 <= comm_size) pof2 <<= 1; pof2 >>=1; rem = comm_size - pof2; /* In the non-power-of-two case, all even-numbered processes of rank < 2*rem send their data to (rank+1). These even-numbered processes no longer participate in the algorithm until the very end. The remaining processes form a nice power-of-two. */ if (rank < 2*rem) { if (rank % 2 == 0) { /* even */ mpi_errno = MPIC_Send_ft(recvbuf, count, datatype, rank+1, MPIR_ALLREDUCE_TAG, comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* temporarily set the rank to -1 so that this process does not pariticipate in recursive doubling */ newrank = -1; } else { /* odd */ mpi_errno = MPIC_Recv_ft(tmp_buf, count, datatype, rank-1, MPIR_ALLREDUCE_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* do the reduction on received data. since the ordering is right, it doesn't matter whether the operation is commutative or not. */ mpi_errno = MPIR_Reduce_local_impl(tmp_buf, recvbuf, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* change the rank */ newrank = rank / 2; } } else /* rank >= 2*rem */ newrank = rank - rem; /* If op is user-defined or count is less than pof2, use recursive doubling algorithm. Otherwise do a reduce-scatter followed by allgather. (If op is user-defined, derived datatypes are allowed and the user could pass basic datatypes on one process and derived on another as long as the type maps are the same. Breaking up derived datatypes to do the reduce-scatter is tricky, therefore using recursive doubling in that case.) */ if (newrank != -1) { if ((count*type_size <= MPIR_PARAM_ALLREDUCE_SHORT_MSG_SIZE) || (HANDLE_GET_KIND(op) != HANDLE_KIND_BUILTIN) || (count < pof2)) { /* use recursive doubling */ mask = 0x1; while (mask < pof2) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; /* Send the most current data, which is in recvbuf. Recv into tmp_buf */ mpi_errno = MPIC_Sendrecv_ft(recvbuf, count, datatype, dst, MPIR_ALLREDUCE_TAG, tmp_buf, count, datatype, dst, MPIR_ALLREDUCE_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* tmp_buf contains data received in this step. recvbuf contains data accumulated so far */ if (is_commutative || (dst < rank)) { /* op is commutative OR the order is already right */ mpi_errno = MPIR_Reduce_local_impl(tmp_buf, recvbuf, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } else { /* op is noncommutative and the order is not right */ mpi_errno = MPIR_Reduce_local_impl(recvbuf, tmp_buf, count, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* copy result back into recvbuf */ mpi_errno = MPIR_Localcopy(tmp_buf, count, datatype, recvbuf, count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } mask <<= 1; } } else { /* do a reduce-scatter followed by allgather */ /* for the reduce-scatter, calculate the count that each process receives and the displacement within the buffer */ MPIU_CHKLMEM_MALLOC(cnts, int *, pof2*sizeof(int), mpi_errno, "counts"); MPIU_CHKLMEM_MALLOC(disps, int *, pof2*sizeof(int), mpi_errno, "displacements"); for (i=0; i<(pof2-1); i++) cnts[i] = count/pof2; cnts[pof2-1] = count - (count/pof2)*(pof2-1); disps[0] = 0; for (i=1; i<pof2; i++) disps[i] = disps[i-1] + cnts[i-1]; mask = 0x1; send_idx = recv_idx = 0; last_idx = pof2; while (mask < pof2) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; send_cnt = recv_cnt = 0; if (newrank < newdst) { send_idx = recv_idx + pof2/(mask*2); for (i=send_idx; i<last_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<send_idx; i++) recv_cnt += cnts[i]; } else { recv_idx = send_idx + pof2/(mask*2); for (i=send_idx; i<recv_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<last_idx; i++) recv_cnt += cnts[i]; } /* printf("Rank %d, send_idx %d, recv_idx %d, send_cnt %d, recv_cnt %d, last_idx %d\n", newrank, send_idx, recv_idx, send_cnt, recv_cnt, last_idx); */ /* Send data from recvbuf. Recv into tmp_buf */ mpi_errno = MPIC_Sendrecv_ft((char *) recvbuf + disps[send_idx]*extent, send_cnt, datatype, dst, MPIR_ALLREDUCE_TAG, (char *) tmp_buf + disps[recv_idx]*extent, recv_cnt, datatype, dst, MPIR_ALLREDUCE_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* tmp_buf contains data received in this step. recvbuf contains data accumulated so far */ /* This algorithm is used only for predefined ops and predefined ops are always commutative. */ mpi_errno = MPIR_Reduce_local_impl(((char *) tmp_buf + disps[recv_idx]*extent), ((char *) recvbuf + disps[recv_idx]*extent), recv_cnt, datatype, op); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* update send_idx for next iteration */ send_idx = recv_idx; mask <<= 1; /* update last_idx, but not in last iteration because the value is needed in the allgather step below. */ if (mask < pof2) last_idx = recv_idx + pof2/mask; } /* now do the allgather */ mask >>= 1; while (mask > 0) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; send_cnt = recv_cnt = 0; if (newrank < newdst) { /* update last_idx except on first iteration */ if (mask != pof2/2) last_idx = last_idx + pof2/(mask*2); recv_idx = send_idx + pof2/(mask*2); for (i=send_idx; i<recv_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<last_idx; i++) recv_cnt += cnts[i]; } else { recv_idx = send_idx - pof2/(mask*2); for (i=send_idx; i<last_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<send_idx; i++) recv_cnt += cnts[i]; } mpi_errno = MPIC_Sendrecv_ft((char *) recvbuf + disps[send_idx]*extent, send_cnt, datatype, dst, MPIR_ALLREDUCE_TAG, (char *) recvbuf + disps[recv_idx]*extent, recv_cnt, datatype, dst, MPIR_ALLREDUCE_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } if (newrank > newdst) send_idx = recv_idx; mask >>= 1; } } } /* In the non-power-of-two case, all odd-numbered processes of rank < 2*rem send the result to (rank-1), the ranks who didn't participate above. */ if (rank < 2*rem) { if (rank % 2) /* odd */ mpi_errno = MPIC_Send_ft(recvbuf, count, datatype, rank-1, MPIR_ALLREDUCE_TAG, comm, errflag); else /* even */ mpi_errno = MPIC_Recv_ft(recvbuf, count, datatype, rank+1, MPIR_ALLREDUCE_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } } fn_exit: /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); MPIU_CHKLMEM_FREEALL(); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; return (mpi_errno); fn_fail: goto fn_exit; }
int MPIR_Allreduce_inter ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, int *errflag ) { /* Intercommunicator Allreduce. We first do an intercommunicator reduce to rank 0 on left group, then an intercommunicator reduce to rank 0 on right group, followed by local intracommunicator broadcasts in each group. We don't do local reduces first and then intercommunicator broadcasts because it would require allocation of a temporary buffer. */ int rank, mpi_errno, root; int mpi_errno_ret = MPI_SUCCESS; MPID_Comm *newcomm_ptr = NULL; rank = comm_ptr->rank; /* first do a reduce from right group to rank 0 in left group, then from left group to rank 0 in right group*/ if (comm_ptr->is_low_group) { /* reduce from right group to rank 0*/ root = (rank == 0) ? MPI_ROOT : MPI_PROC_NULL; mpi_errno = MPIR_Reduce_inter(sendbuf, recvbuf, count, datatype, op, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* reduce to rank 0 of right group */ root = 0; mpi_errno = MPIR_Reduce_inter(sendbuf, recvbuf, count, datatype, op, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } else { /* reduce to rank 0 of left group */ root = 0; mpi_errno = MPIR_Reduce_inter(sendbuf, recvbuf, count, datatype, op, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* reduce from right group to rank 0 */ root = (rank == 0) ? MPI_ROOT : MPI_PROC_NULL; mpi_errno = MPIR_Reduce_inter(sendbuf, recvbuf, count, datatype, op, root, comm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* Get the local intracommunicator */ if (!comm_ptr->local_comm) MPIR_Setup_intercomm_localcomm( comm_ptr ); newcomm_ptr = comm_ptr->local_comm; mpi_errno = MPIR_Bcast_impl(recvbuf, count, datatype, 0, newcomm_ptr, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } fn_exit: if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Alltoallv_intra(const void *sendbuf, const int *sendcounts, const int *sdispls, MPI_Datatype sendtype, void *recvbuf, const int *recvcounts, const int *rdispls, MPI_Datatype recvtype, MPID_Comm *comm_ptr, int *errflag) { int comm_size, i, j; MPI_Aint send_extent, recv_extent; int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; MPI_Status *starray; MPI_Status status; MPI_Request *reqarray; int dst, rank, req_cnt; MPI_Comm comm; int ii, ss, bblock; int type_size; MPIU_CHKLMEM_DECL(2); comm = comm_ptr->handle; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; /* Get extent of recv type, but send type is only valid if (sendbuf!=MPI_IN_PLACE) */ MPID_Datatype_get_extent_macro(recvtype, recv_extent); /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); if (sendbuf == MPI_IN_PLACE) { /* We use pair-wise sendrecv_replace in order to conserve memory usage, * which is keeping with the spirit of the MPI-2.2 Standard. But * because of this approach all processes must agree on the global * schedule of sendrecv_replace operations to avoid deadlock. * * Note that this is not an especially efficient algorithm in terms of * time and there will be multiple repeated malloc/free's rather than * maintaining a single buffer across the whole loop. Something like * MADRE is probably the best solution for the MPI_IN_PLACE scenario. */ for (i = 0; i < comm_size; ++i) { /* start inner loop at i to avoid re-exchanging data */ for (j = i; j < comm_size; ++j) { if (rank == i) { /* also covers the (rank == i && rank == j) case */ mpi_errno = MPIC_Sendrecv_replace_ft(((char *)recvbuf + rdispls[j]*recv_extent), recvcounts[j], recvtype, j, MPIR_ALLTOALLV_TAG, j, MPIR_ALLTOALLV_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } else if (rank == j) { /* same as above with i/j args reversed */ mpi_errno = MPIC_Sendrecv_replace_ft(((char *)recvbuf + rdispls[i]*recv_extent), recvcounts[i], recvtype, i, MPIR_ALLTOALLV_TAG, i, MPIR_ALLTOALLV_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } } } } else { bblock = MPIR_PARAM_ALLTOALL_THROTTLE; if (bblock == 0) bblock = comm_size; MPID_Datatype_get_extent_macro(sendtype, send_extent); MPIU_CHKLMEM_MALLOC(starray, MPI_Status*, 2*bblock*sizeof(MPI_Status), mpi_errno, "starray"); MPIU_CHKLMEM_MALLOC(reqarray, MPI_Request*, 2*bblock*sizeof(MPI_Request), mpi_errno, "reqarray"); /* post only bblock isends/irecvs at a time as suggested by Tony Ladd */ for (ii=0; ii<comm_size; ii+=bblock) { req_cnt = 0; ss = comm_size-ii < bblock ? comm_size-ii : bblock; /* do the communication -- post ss sends and receives: */ for ( i=0; i<ss; i++ ) { dst = (rank+i+ii) % comm_size; if (recvcounts[dst]) { MPID_Datatype_get_size_macro(recvtype, type_size); if (type_size) { MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT recvbuf + rdispls[dst]*recv_extent); mpi_errno = MPIC_Irecv_ft((char *)recvbuf+rdispls[dst]*recv_extent, recvcounts[dst], recvtype, dst, MPIR_ALLTOALLV_TAG, comm, &reqarray[req_cnt]); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } req_cnt++; } } } for ( i=0; i<ss; i++ ) { dst = (rank-i-ii+comm_size) % comm_size; if (sendcounts[dst]) { MPID_Datatype_get_size_macro(sendtype, type_size); if (type_size) { MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT sendbuf + sdispls[dst]*send_extent); mpi_errno = MPIC_Isend_ft((char *)sendbuf+sdispls[dst]*send_extent, sendcounts[dst], sendtype, dst, MPIR_ALLTOALLV_TAG, comm, &reqarray[req_cnt], errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } req_cnt++; } } } mpi_errno = MPIC_Waitall_ft(req_cnt, reqarray, starray, errflag); if (mpi_errno && mpi_errno != MPI_ERR_IN_STATUS) MPIU_ERR_POP(mpi_errno); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno == MPI_ERR_IN_STATUS) { for (i=0; i<req_cnt; i++) { if (starray[i].MPI_ERROR != MPI_SUCCESS) { mpi_errno = starray[i].MPI_ERROR; if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } } } /* --END ERROR HANDLING-- */ } } fn_exit: /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_EXIT( comm_ptr ); MPIU_CHKLMEM_FREEALL(); if (mpi_errno_ret) mpi_errno = mpi_errno_ret; else if (*errflag) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**coll_fail"); return mpi_errno; fn_fail: goto fn_exit; }
/*@ MPI_Dist_graph_create_adjacent - returns a handle to a new communicator to which the distributed graph topology information is attached. Input Parameters: + comm_old - input communicator (handle) . indegree - size of sources and sourceweights arrays (non-negative integer) . sources - ranks of processes for which the calling process is a destination (array of non-negative integers) . sourceweights - weights of the edges into the calling process (array of non-negative integers or MPI_UNWEIGHTED) . outdegree - size of destinations and destweights arrays (non-negative integer) . destinations - ranks of processes for which the calling process is a source (array of non-negative integers) . destweights - weights of the edges out of the calling process (array of non-negative integers or MPI_UNWEIGHTED) . info - hints on optimization and interpretation of weights (handle) - reorder - the ranks may be reordered (true) or not (false) (logical) Output Parameters: . comm_dist_graph - communicator with distributed graph topology (handle) .N ThreadSafe .N Fortran .N Errors .N MPI_SUCCESS .N MPI_ERR_ARG .N MPI_ERR_OTHER @*/ int MPI_Dist_graph_create_adjacent(MPI_Comm comm_old, int indegree, const int sources[], const int sourceweights[], int outdegree, const int destinations[], const int destweights[], 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; MPIR_Topology *topo_ptr = NULL; MPIR_Dist_graph_topology *dist_graph_ptr = NULL; MPIU_CHKPMEM_DECL(5); MPID_MPI_STATE_DECL(MPID_STATE_MPI_DIST_GRAPH_CREATE_ADJACENT); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPIU_THREAD_CS_ENTER(ALLFUNC,); MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_DIST_GRAPH_CREATE_ADJACENT); /* 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); } 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, FALSE ); if (mpi_errno != MPI_SUCCESS) goto fn_fail; /* 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(indegree, "indegree", mpi_errno); MPIR_ERRTEST_ARGNEG(outdegree, "outdegree", mpi_errno); if (indegree > 0) { MPIR_ERRTEST_ARGNULL(sources, "sources", mpi_errno); if (sourceweights == MPI_UNWEIGHTED && destweights != MPI_UNWEIGHTED) { MPIU_ERR_SET(mpi_errno, MPI_ERR_TOPOLOGY, "**unweightedboth"); goto fn_fail; } /* TODO check ranges for array elements too (**argarrayneg / **rankarray)*/ } if (outdegree > 0) { MPIR_ERRTEST_ARGNULL(destinations, "destinations", mpi_errno); if (destweights == MPI_UNWEIGHTED && sourceweights != MPI_UNWEIGHTED) { MPIU_ERR_SET(mpi_errno, MPI_ERR_TOPOLOGY, "**unweightedboth"); goto fn_fail; } } MPIR_ERRTEST_ARGNULL(comm_dist_graph, "comm_dist_graph", mpi_errno); } 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; /* 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_ptr->local_size, &comm_dist_graph_ptr); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* 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 = indegree; dist_graph_ptr->in = NULL; dist_graph_ptr->in_weights = NULL; dist_graph_ptr->outdegree = outdegree; dist_graph_ptr->out = NULL; dist_graph_ptr->out_weights = NULL; dist_graph_ptr->is_weighted = (sourceweights != MPI_UNWEIGHTED); MPIU_CHKPMEM_MALLOC(dist_graph_ptr->in, int *, indegree*sizeof(int), mpi_errno, "dist_graph_ptr->in"); MPIU_CHKPMEM_MALLOC(dist_graph_ptr->out, int *, outdegree*sizeof(int), mpi_errno, "dist_graph_ptr->out"); MPIU_Memcpy(dist_graph_ptr->in, sources, indegree*sizeof(int)); MPIU_Memcpy(dist_graph_ptr->out, destinations, outdegree*sizeof(int)); if (dist_graph_ptr->is_weighted) { MPIU_CHKPMEM_MALLOC(dist_graph_ptr->in_weights, int *, indegree*sizeof(int), mpi_errno, "dist_graph_ptr->in_weights"); MPIU_CHKPMEM_MALLOC(dist_graph_ptr->out_weights, int *, outdegree*sizeof(int), mpi_errno, "dist_graph_ptr->out_weights"); MPIU_Memcpy(dist_graph_ptr->in_weights, sourceweights, indegree*sizeof(int)); MPIU_Memcpy(dist_graph_ptr->out_weights, destweights, outdegree*sizeof(int)); }
/* not declared static because a machine-specific function may call this one in some cases */ int MPIR_Reduce_scatter_block_intra ( const void *sendbuf, void *recvbuf, int recvcount, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, int *errflag ) { int rank, comm_size, i; MPI_Aint extent, true_extent, true_lb; int *disps; void *tmp_recvbuf, *tmp_results; int mpi_errno = MPI_SUCCESS; int mpi_errno_ret = MPI_SUCCESS; int type_size, dis[2], blklens[2], total_count, nbytes, src, dst; int mask, dst_tree_root, my_tree_root, j, k; int *newcnts, *newdisps, rem, newdst, send_idx, recv_idx, last_idx, send_cnt, recv_cnt; int pof2, old_i, newrank, received; MPI_Datatype sendtype, recvtype; int nprocs_completed, tmp_mask, tree_root, is_commutative; MPID_Op *op_ptr; MPI_Comm comm; MPIU_THREADPRIV_DECL; MPIU_CHKLMEM_DECL(5); comm = comm_ptr->handle; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; /* set op_errno to 0. stored in perthread structure */ MPIU_THREADPRIV_GET; MPIU_THREADPRIV_FIELD(op_errno) = 0; if (recvcount == 0) { goto fn_exit; } MPID_Datatype_get_extent_macro(datatype, extent); MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); if (HANDLE_GET_KIND(op) == HANDLE_KIND_BUILTIN) { is_commutative = 1; } else { MPID_Op_get_ptr(op, op_ptr); if (op_ptr->kind == MPID_OP_USER_NONCOMMUTE) is_commutative = 0; else is_commutative = 1; } MPIU_CHKLMEM_MALLOC(disps, int *, comm_size * sizeof(int), mpi_errno, "disps"); total_count = comm_size*recvcount; for (i=0; i<comm_size; i++) { disps[i] = i*recvcount; } MPID_Datatype_get_size_macro(datatype, type_size); nbytes = total_count * type_size; /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); /* total_count*extent eventually gets malloced. it isn't added to * a user-passed in buffer */ MPID_Ensure_Aint_fits_in_pointer(total_count * MPIR_MAX(true_extent, extent)); if ((is_commutative) && (nbytes < MPIR_PARAM_REDSCAT_COMMUTATIVE_LONG_MSG_SIZE)) { /* commutative and short. use recursive halving algorithm */ /* allocate temp. buffer to receive incoming data */ MPIU_CHKLMEM_MALLOC(tmp_recvbuf, void *, total_count*(MPIR_MAX(true_extent,extent)), mpi_errno, "tmp_recvbuf"); /* adjust for potential negative lower bound in datatype */ tmp_recvbuf = (void *)((char*)tmp_recvbuf - true_lb); /* need to allocate another temporary buffer to accumulate results because recvbuf may not be big enough */ MPIU_CHKLMEM_MALLOC(tmp_results, void *, total_count*(MPIR_MAX(true_extent,extent)), mpi_errno, "tmp_results"); /* adjust for potential negative lower bound in datatype */ tmp_results = (void *)((char*)tmp_results - true_lb); /* copy sendbuf into tmp_results */ if (sendbuf != MPI_IN_PLACE) mpi_errno = MPIR_Localcopy(sendbuf, total_count, datatype, tmp_results, total_count, datatype); else mpi_errno = MPIR_Localcopy(recvbuf, total_count, datatype, tmp_results, total_count, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); pof2 = 1; while (pof2 <= comm_size) pof2 <<= 1; pof2 >>=1; rem = comm_size - pof2; /* In the non-power-of-two case, all even-numbered processes of rank < 2*rem send their data to (rank+1). These even-numbered processes no longer participate in the algorithm until the very end. The remaining processes form a nice power-of-two. */ if (rank < 2*rem) { if (rank % 2 == 0) { /* even */ mpi_errno = MPIC_Send_ft(tmp_results, total_count, datatype, rank+1, MPIR_REDUCE_SCATTER_BLOCK_TAG, comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* temporarily set the rank to -1 so that this process does not pariticipate in recursive doubling */ newrank = -1; } else { /* odd */ mpi_errno = MPIC_Recv_ft(tmp_recvbuf, total_count, datatype, rank-1, MPIR_REDUCE_SCATTER_BLOCK_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* do the reduction on received data. since the ordering is right, it doesn't matter whether the operation is commutative or not. */ mpi_errno = MPIR_Reduce_local_impl( tmp_recvbuf, tmp_results, total_count, datatype, op); /* change the rank */ newrank = rank / 2; } } else /* rank >= 2*rem */ newrank = rank - rem; if (newrank != -1) { /* recalculate the recvcnts and disps arrays because the even-numbered processes who no longer participate will have their result calculated by the process to their right (rank+1). */ MPIU_CHKLMEM_MALLOC(newcnts, int *, pof2*sizeof(int), mpi_errno, "newcnts"); MPIU_CHKLMEM_MALLOC(newdisps, int *, pof2*sizeof(int), mpi_errno, "newdisps"); for (i=0; i<pof2; i++) { /* what does i map to in the old ranking? */ old_i = (i < rem) ? i*2 + 1 : i + rem; if (old_i < 2*rem) { /* This process has to also do its left neighbor's work */ newcnts[i] = 2 * recvcount; } else newcnts[i] = recvcount; } newdisps[0] = 0; for (i=1; i<pof2; i++) newdisps[i] = newdisps[i-1] + newcnts[i-1]; mask = pof2 >> 1; send_idx = recv_idx = 0; last_idx = pof2; while (mask > 0) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; send_cnt = recv_cnt = 0; if (newrank < newdst) { send_idx = recv_idx + mask; for (i=send_idx; i<last_idx; i++) send_cnt += newcnts[i]; for (i=recv_idx; i<send_idx; i++) recv_cnt += newcnts[i]; } else { recv_idx = send_idx + mask; for (i=send_idx; i<recv_idx; i++) send_cnt += newcnts[i]; for (i=recv_idx; i<last_idx; i++) recv_cnt += newcnts[i]; } /* printf("Rank %d, send_idx %d, recv_idx %d, send_cnt %d, recv_cnt %d, last_idx %d\n", newrank, send_idx, recv_idx, send_cnt, recv_cnt, last_idx); */ /* Send data from tmp_results. Recv into tmp_recvbuf */ if ((send_cnt != 0) && (recv_cnt != 0)) mpi_errno = MPIC_Sendrecv_ft((char *) tmp_results + newdisps[send_idx]*extent, send_cnt, datatype, dst, MPIR_REDUCE_SCATTER_BLOCK_TAG, (char *) tmp_recvbuf + newdisps[recv_idx]*extent, recv_cnt, datatype, dst, MPIR_REDUCE_SCATTER_BLOCK_TAG, comm, MPI_STATUS_IGNORE, errflag); else if ((send_cnt == 0) && (recv_cnt != 0)) mpi_errno = MPIC_Recv_ft((char *) tmp_recvbuf + newdisps[recv_idx]*extent, recv_cnt, datatype, dst, MPIR_REDUCE_SCATTER_BLOCK_TAG, comm, MPI_STATUS_IGNORE, errflag); else if ((recv_cnt == 0) && (send_cnt != 0)) mpi_errno = MPIC_Send_ft((char *) tmp_results + newdisps[send_idx]*extent, send_cnt, datatype, dst, MPIR_REDUCE_SCATTER_BLOCK_TAG, comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } /* tmp_recvbuf contains data received in this step. tmp_results contains data accumulated so far */ if (recv_cnt) { mpi_errno = MPIR_Reduce_local_impl( (char *) tmp_recvbuf + newdisps[recv_idx]*extent, (char *) tmp_results + newdisps[recv_idx]*extent, recv_cnt, datatype, op); } /* update send_idx for next iteration */ send_idx = recv_idx; last_idx = recv_idx + mask; mask >>= 1; } /* copy this process's result from tmp_results to recvbuf */ mpi_errno = MPIR_Localcopy((char *)tmp_results + disps[rank]*extent, recvcount, datatype, recvbuf, recvcount, datatype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); }
/*@ MPI_Recv - Blocking receive for a message Output Parameters: + buf - initial address of receive buffer (choice) - status - status object (Status) Input Parameters: + count - maximum number of elements in receive buffer (integer) . datatype - datatype of each receive buffer element (handle) . source - rank of source (integer) . tag - message tag (integer) - comm - communicator (handle) Notes: The 'count' argument indicates the maximum length of a message; the actual length of the message can be determined with 'MPI_Get_count'. .N ThreadSafe .N Fortran .N FortranStatus .N Errors .N MPI_SUCCESS .N MPI_ERR_COMM .N MPI_ERR_TYPE .N MPI_ERR_COUNT .N MPI_ERR_TAG .N MPI_ERR_RANK @*/ int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) { static const char FCNAME[] = "MPI_Recv"; int mpi_errno = MPI_SUCCESS; MPID_Comm *comm_ptr = NULL; MPID_Request * request_ptr = NULL; MPID_MPI_STATE_DECL(MPID_STATE_MPI_RECV); MPIR_ERRTEST_INITIALIZED_ORDIE(); MPIU_THREAD_CS_ENTER(ALLFUNC,); MPID_MPI_PT2PT_FUNC_ENTER_BACK(MPID_STATE_MPI_RECV); /* Validate handle parameters needing to be converted */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPIR_ERRTEST_COMM(comm, mpi_errno); /* NOTE: MPI_STATUS_IGNORE != NULL */ MPIR_ERRTEST_ARGNULL(status, "status", mpi_errno); } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* Convert MPI object handles to object pointers */ MPID_Comm_get_ptr( comm, comm_ptr ); /* Validate parameters if error checking is enabled */ # ifdef HAVE_ERROR_CHECKING { MPID_BEGIN_ERROR_CHECKS; { MPID_Comm_valid_ptr( comm_ptr, mpi_errno, FALSE ); if (mpi_errno) goto fn_fail; MPIR_ERRTEST_COUNT(count, mpi_errno); MPIR_ERRTEST_RECV_RANK(comm_ptr, source, mpi_errno); MPIR_ERRTEST_RECV_TAG(tag, mpi_errno); /* Validate datatype handle */ MPIR_ERRTEST_DATATYPE(datatype, "datatype", mpi_errno); /* Validate datatype object */ if (HANDLE_GET_KIND(datatype) != HANDLE_KIND_BUILTIN) { MPID_Datatype *datatype_ptr = NULL; MPID_Datatype_get_ptr(datatype, datatype_ptr); MPID_Datatype_valid_ptr(datatype_ptr, mpi_errno); if (mpi_errno) goto fn_fail; MPID_Datatype_committed_ptr(datatype_ptr, mpi_errno); if (mpi_errno) goto fn_fail; } /* Validate buffer */ MPIR_ERRTEST_USERBUFFER(buf,count,datatype,mpi_errno); } MPID_END_ERROR_CHECKS; } # endif /* HAVE_ERROR_CHECKING */ /* ... body of routine ... */ /* MT: Note that MPID_Recv may release the SINGLE_CS if it decides to block internally. MPID_Recv in that case will re-aquire the SINGLE_CS before returnning */ mpi_errno = MPID_Recv(buf, count, datatype, source, tag, comm_ptr, MPID_CONTEXT_INTRA_PT2PT, status, &request_ptr); if (mpi_errno != MPI_SUCCESS) goto fn_fail; if (request_ptr == NULL) { goto fn_exit; } /* If a request was returned, then we need to block until the request is complete */ if (!MPID_Request_is_complete(request_ptr)) { MPID_Progress_state progress_state; MPID_Progress_start(&progress_state); while (!MPID_Request_is_complete(request_ptr)) { /* MT: Progress_wait may release the SINGLE_CS while it waits */ mpi_errno = MPID_Progress_wait(&progress_state); if (mpi_errno != MPI_SUCCESS) { /* --BEGIN ERROR HANDLING-- */ MPID_Progress_end(&progress_state); goto fn_fail; /* --END ERROR HANDLING-- */ } if (unlikely(MPIR_CVAR_ENABLE_FT && !MPID_Request_is_complete(request_ptr) && MPID_Request_is_anysource(request_ptr) && !MPID_Comm_AS_enabled(request_ptr->comm))) { /* --BEGIN ERROR HANDLING-- */ MPID_Cancel_recv(request_ptr); MPIR_STATUS_SET_CANCEL_BIT(request_ptr->status, FALSE); MPIU_ERR_SET(request_ptr->status.MPI_ERROR, MPIX_ERR_PROC_FAILED, "**proc_failed"); mpi_errno = request_ptr->status.MPI_ERROR; goto fn_fail; /* --END ERROR HANDLING-- */ } } MPID_Progress_end(&progress_state); } mpi_errno = request_ptr->status.MPI_ERROR; MPIR_Request_extract_status(request_ptr, status); MPID_Request_release(request_ptr); if (mpi_errno != MPI_SUCCESS) goto fn_fail; /* ... end of body of routine ... */ fn_exit: MPID_MPI_PT2PT_FUNC_EXIT_BACK(MPID_STATE_MPI_RECV); MPIU_THREAD_CS_EXIT(ALLFUNC,); 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_recv", "**mpi_recv %p %d %D %i %t %C %p", buf, count, datatype, source, tag, comm, status); } # endif mpi_errno = MPIR_Err_return_comm( comm_ptr, FCNAME, mpi_errno ); goto fn_exit; /* --END ERROR HANDLING-- */ }
int MPID_Irsend(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPID_Comm * comm, int context_offset, MPID_Request ** request) { MPIDI_CH3_Pkt_t upkt; MPIDI_CH3_Pkt_ready_send_t * const ready_pkt = &upkt.ready_send; MPIDI_msg_sz_t data_sz; int dt_contig; MPI_Aint dt_true_lb; MPID_Datatype * dt_ptr; MPID_Request * sreq; MPIDI_VC_t * vc; #if defined(MPID_USE_SEQUENCE_NUMBERS) MPID_Seqnum_t seqnum; #endif int mpi_errno = MPI_SUCCESS; MPIDI_STATE_DECL(MPID_STATE_MPID_IRSEND); MPIDI_FUNC_ENTER(MPID_STATE_MPID_IRSEND); MPIU_DBG_MSG_FMT(CH3_OTHER,VERBOSE,(MPIU_DBG_FDEST, "rank=%d, tag=%d, context=%d", rank, tag, comm->context_id + context_offset)); if (rank == comm->rank && comm->comm_kind != MPID_INTERCOMM) { mpi_errno = MPIDI_Isend_self(buf, count, datatype, rank, tag, comm, context_offset, MPIDI_REQUEST_TYPE_RSEND, &sreq); goto fn_exit; } MPIDI_Request_create_sreq(sreq, mpi_errno, goto fn_exit); MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_RSEND); MPIDI_Request_set_msg_type(sreq, MPIDI_REQUEST_EAGER_MSG); if (rank == MPI_PROC_NULL) { MPIU_Object_set_ref(sreq, 1); MPID_cc_set(&sreq->cc, 0); goto fn_exit; } MPIDI_Comm_get_vc_set_active(comm, rank, &vc); #ifdef ENABLE_COMM_OVERRIDES if (vc->comm_ops && vc->comm_ops->irsend) { mpi_errno = vc->comm_ops->irsend( vc, buf, count, datatype, rank, tag, comm, context_offset, &sreq); goto fn_exit; } #endif MPIDI_Datatype_get_info(count, datatype, dt_contig, data_sz, dt_ptr, dt_true_lb); MPIDI_Pkt_init(ready_pkt, MPIDI_CH3_PKT_READY_SEND); ready_pkt->match.parts.rank = comm->rank; ready_pkt->match.parts.tag = tag; ready_pkt->match.parts.context_id = comm->context_id + context_offset; ready_pkt->sender_req_id = MPI_REQUEST_NULL; ready_pkt->data_sz = data_sz; if (data_sz == 0) { MPIU_DBG_MSG(CH3_OTHER,VERBOSE,"sending zero length message"); sreq->dev.OnDataAvail = 0; MPIDI_VC_FAI_send_seqnum(vc, seqnum); MPIDI_Pkt_set_seqnum(ready_pkt, seqnum); MPIDI_Request_set_seqnum(sreq, seqnum); MPIU_THREAD_CS_ENTER(CH3COMM,vc); mpi_errno = MPIDI_CH3_iSend(vc, sreq, ready_pkt, sizeof(*ready_pkt)); MPIU_THREAD_CS_EXIT(CH3COMM,vc); /* --BEGIN ERROR HANDLING-- */ if (mpi_errno != MPI_SUCCESS) { MPIU_Object_set_ref(sreq, 0); MPIDI_CH3_Request_destroy(sreq); sreq = NULL; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**ch3|eagermsg"); goto fn_exit; } /* --END ERROR HANDLING-- */ goto fn_exit; } if (vc->ready_eager_max_msg_sz < 0 || data_sz + sizeof(MPIDI_CH3_Pkt_ready_send_t) <= vc->ready_eager_max_msg_sz) { if (dt_contig) { mpi_errno = MPIDI_CH3_EagerContigIsend( &sreq, MPIDI_CH3_PKT_READY_SEND, (char*)buf + dt_true_lb, data_sz, rank, tag, comm, context_offset ); } else { mpi_errno = MPIDI_CH3_EagerNoncontigSend( &sreq, MPIDI_CH3_PKT_READY_SEND, buf, count, datatype, data_sz, rank, tag, comm, context_offset ); /* If we're not complete, then add a reference to the datatype */ if (sreq && sreq->dev.OnDataAvail) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); } } } else { /* Do rendezvous. This will be sent as a regular send not as a ready send, so the receiver won't know to send an error if the receive has not been posted */ MPIDI_Request_set_msg_type( sreq, MPIDI_REQUEST_RNDV_MSG ); mpi_errno = vc->rndvSend_fn( &sreq, buf, count, datatype, dt_contig, data_sz, dt_true_lb, rank, tag, comm, context_offset ); if (sreq && dt_ptr != NULL) { sreq->dev.datatype_ptr = dt_ptr; MPID_Datatype_add_ref(dt_ptr); } } fn_exit: *request = sreq; MPIU_DBG_STMT(CH3_OTHER,VERBOSE,{ if (sreq != NULL) { MPIU_DBG_MSG_P(CH3_OTHER,VERBOSE,"request allocated, handle=0x%08x", sreq->handle); } } );
int MPIR_Alltoall_intra( const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPID_Comm *comm_ptr, int *errflag ) { int comm_size, i, j, pof2; MPI_Aint sendtype_extent, recvtype_extent; MPI_Aint recvtype_true_extent, recvbuf_extent, recvtype_true_lb; int mpi_errno=MPI_SUCCESS, src, dst, rank, nbytes; int mpi_errno_ret = MPI_SUCCESS; MPI_Status status; int sendtype_size, pack_size, block, position, *displs, count; MPI_Datatype newtype = MPI_DATATYPE_NULL; void *tmp_buf; MPI_Comm comm; MPI_Request *reqarray; MPI_Status *starray; MPIU_CHKLMEM_DECL(6); #ifdef MPIR_OLD_SHORT_ALLTOALL_ALG MPI_Aint sendtype_true_extent, sendbuf_extent, sendtype_true_lb; int k, p, curr_cnt, dst_tree_root, my_tree_root; int last_recv_cnt, mask, tmp_mask, tree_root, nprocs_completed; #endif if (recvcount == 0) return MPI_SUCCESS; comm = comm_ptr->handle; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; /* Get extent of send and recv types */ MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); MPID_Datatype_get_extent_macro(sendtype, sendtype_extent); MPID_Datatype_get_size_macro(sendtype, sendtype_size); nbytes = sendtype_size * sendcount; /* check if multiple threads are calling this collective function */ MPIDU_ERR_CHECK_MULTIPLE_THREADS_ENTER( comm_ptr ); if (sendbuf == MPI_IN_PLACE) { /* We use pair-wise sendrecv_replace in order to conserve memory usage, * which is keeping with the spirit of the MPI-2.2 Standard. But * because of this approach all processes must agree on the global * schedule of sendrecv_replace operations to avoid deadlock. * * Note that this is not an especially efficient algorithm in terms of * time and there will be multiple repeated malloc/free's rather than * maintaining a single buffer across the whole loop. Something like * MADRE is probably the best solution for the MPI_IN_PLACE scenario. */ for (i = 0; i < comm_size; ++i) { /* start inner loop at i to avoid re-exchanging data */ for (j = i; j < comm_size; ++j) { if (rank == i) { /* also covers the (rank == i && rank == j) case */ mpi_errno = MPIC_Sendrecv_replace_ft(((char *)recvbuf + j*recvcount*recvtype_extent), recvcount, recvtype, j, MPIR_ALLTOALL_TAG, j, MPIR_ALLTOALL_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } else if (rank == j) { /* same as above with i/j args reversed */ mpi_errno = MPIC_Sendrecv_replace_ft(((char *)recvbuf + i*recvcount*recvtype_extent), recvcount, recvtype, i, MPIR_ALLTOALL_TAG, i, MPIR_ALLTOALL_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } } } } else if ((nbytes <= MPIR_PARAM_ALLTOALL_SHORT_MSG_SIZE) && (comm_size >= 8)) { /* use the indexing algorithm by Jehoshua Bruck et al, * IEEE TPDS, Nov. 97 */ /* allocate temporary buffer */ MPIR_Pack_size_impl(recvcount*comm_size, recvtype, &pack_size); MPIU_CHKLMEM_MALLOC(tmp_buf, void *, pack_size, mpi_errno, "tmp_buf"); /* Do Phase 1 of the algorithim. Shift the data blocks on process i * upwards by a distance of i blocks. Store the result in recvbuf. */ mpi_errno = MPIR_Localcopy((char *) sendbuf + rank*sendcount*sendtype_extent, (comm_size - rank)*sendcount, sendtype, recvbuf, (comm_size - rank)*recvcount, recvtype); if (mpi_errno) { MPIU_ERR_POP(mpi_errno); } mpi_errno = MPIR_Localcopy(sendbuf, rank*sendcount, sendtype, (char *) recvbuf + (comm_size-rank)*recvcount*recvtype_extent, rank*recvcount, recvtype); if (mpi_errno) { MPIU_ERR_POP(mpi_errno); } /* Input data is now stored in recvbuf with datatype recvtype */ /* Now do Phase 2, the communication phase. It takes ceiling(lg p) steps. In each step i, each process sends to rank+2^i and receives from rank-2^i, and exchanges all data blocks whose ith bit is 1. */ /* allocate displacements array for indexed datatype used in communication */ MPIU_CHKLMEM_MALLOC(displs, int *, comm_size * sizeof(int), mpi_errno, "displs"); pof2 = 1; while (pof2 < comm_size) { dst = (rank + pof2) % comm_size; src = (rank - pof2 + comm_size) % comm_size; /* Exchange all data blocks whose ith bit is 1 */ /* Create an indexed datatype for the purpose */ count = 0; for (block=1; block<comm_size; block++) { if (block & pof2) { displs[count] = block * recvcount; count++; } } mpi_errno = MPIR_Type_create_indexed_block_impl(count, recvcount, displs, recvtype, &newtype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPIR_Type_commit_impl(&newtype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); position = 0; mpi_errno = MPIR_Pack_impl(recvbuf, 1, newtype, tmp_buf, pack_size, &position); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPIC_Sendrecv_ft(tmp_buf, position, MPI_PACKED, dst, MPIR_ALLTOALL_TAG, recvbuf, 1, newtype, src, MPIR_ALLTOALL_TAG, comm, MPI_STATUS_IGNORE, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } MPIR_Type_free_impl(&newtype); pof2 *= 2; } /* Rotate blocks in recvbuf upwards by (rank + 1) blocks. Need * a temporary buffer of the same size as recvbuf. */ /* get true extent of recvtype */ MPIR_Type_get_true_extent_impl(recvtype, &recvtype_true_lb, &recvtype_true_extent); recvbuf_extent = recvcount * comm_size * (MPIR_MAX(recvtype_true_extent, recvtype_extent)); MPIU_CHKLMEM_MALLOC(tmp_buf, void *, recvbuf_extent, mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - recvtype_true_lb); mpi_errno = MPIR_Localcopy((char *) recvbuf + (rank+1)*recvcount*recvtype_extent, (comm_size - rank - 1)*recvcount, recvtype, tmp_buf, (comm_size - rank - 1)*recvcount, recvtype); if (mpi_errno) { MPIU_ERR_POP(mpi_errno); } mpi_errno = MPIR_Localcopy(recvbuf, (rank+1)*recvcount, recvtype, (char *) tmp_buf + (comm_size-rank-1)*recvcount*recvtype_extent, (rank+1)*recvcount, recvtype); if (mpi_errno) { MPIU_ERR_POP(mpi_errno); } /* Blocks are in the reverse order now (comm_size-1 to 0). * Reorder them to (0 to comm_size-1) and store them in recvbuf. */ for (i=0; i<comm_size; i++){ mpi_errno = MPIR_Localcopy((char *) tmp_buf + i*recvcount*recvtype_extent, recvcount, recvtype, (char *) recvbuf + (comm_size-i-1)*recvcount*recvtype_extent, recvcount, recvtype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } #ifdef MPIR_OLD_SHORT_ALLTOALL_ALG /* Short message. Use recursive doubling. Each process sends all its data at each step along with all data it received in previous steps. */ /* need to allocate temporary buffer of size sendbuf_extent*comm_size */ /* get true extent of sendtype */ MPIR_Type_get_true_extent_impl(sendtype, &sendtype_true_lb, &sendtype_true_extent); sendbuf_extent = sendcount * comm_size * (MPIR_MAX(sendtype_true_extent, sendtype_extent)); MPIU_CHKLMEM_MALLOC(tmp_buf, void *, sendbuf_extent*comm_size, mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - sendtype_true_lb); /* copy local sendbuf into tmp_buf at location indexed by rank */ curr_cnt = sendcount*comm_size; mpi_errno = MPIR_Localcopy(sendbuf, curr_cnt, sendtype, ((char *)tmp_buf + rank*sendbuf_extent), curr_cnt, sendtype); if (mpi_errno) { MPIU_ERR_POP(mpi_errno);} mask = 0x1; i = 0; while (mask < comm_size) { dst = rank ^ mask; dst_tree_root = dst >> i; dst_tree_root <<= i; my_tree_root = rank >> i; my_tree_root <<= i; if (dst < comm_size) { mpi_errno = MPIC_Sendrecv_ft(((char *)tmp_buf + my_tree_root*sendbuf_extent), curr_cnt, sendtype, dst, MPIR_ALLTOALL_TAG, ((char *)tmp_buf + dst_tree_root*sendbuf_extent), sendbuf_extent*(comm_size-dst_tree_root), sendtype, dst, MPIR_ALLTOALL_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); last_recv_cnt = 0; } else /* in case of non-power-of-two nodes, less data may be received than specified */ MPIR_Get_count_impl(&status, sendtype, &last_recv_cnt); curr_cnt += last_recv_cnt; } /* if some processes in this process's subtree in this step did not have any destination process to communicate with because of non-power-of-two, we need to send them the result. We use a logarithmic recursive-halfing algorithm for this. */ if (dst_tree_root + mask > comm_size) { nprocs_completed = comm_size - my_tree_root - mask; /* nprocs_completed is the number of processes in this subtree that have all the data. Send data to others in a tree fashion. First find root of current tree that is being divided into two. k is the number of least-significant bits in this process's rank that must be zeroed out to find the rank of the root */ j = mask; k = 0; while (j) { j >>= 1; k++; } k--; tmp_mask = mask >> 1; while (tmp_mask) { dst = rank ^ tmp_mask; tree_root = rank >> k; tree_root <<= k; /* send only if this proc has data and destination doesn't have data. at any step, multiple processes can send if they have the data */ if ((dst > rank) && (rank < tree_root + nprocs_completed) && (dst >= tree_root + nprocs_completed)) { /* send the data received in this step above */ mpi_errno = MPIC_Send_ft(((char *)tmp_buf + dst_tree_root*sendbuf_extent), last_recv_cnt, sendtype, dst, MPIR_ALLTOALL_TAG, comm, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); } } /* recv only if this proc. doesn't have data and sender has data */ else if ((dst < rank) && (dst < tree_root + nprocs_completed) && (rank >= tree_root + nprocs_completed)) { mpi_errno = MPIC_Recv_ft(((char *)tmp_buf + dst_tree_root*sendbuf_extent), sendbuf_extent*(comm_size-dst_tree_root), sendtype, dst, MPIR_ALLTOALL_TAG, comm, &status, errflag); if (mpi_errno) { /* for communication errors, just record the error but continue */ *errflag = TRUE; MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**fail"); MPIU_ERR_ADD(mpi_errno_ret, mpi_errno); last_recv_cnt = 0; } else MPIR_Get_count_impl(&status, sendtype, &last_recv_cnt); curr_cnt += last_recv_cnt; } tmp_mask >>= 1; k--; } } mask <<= 1; i++; }
static int MPIDI_CH3i_Progress_wait(MPID_Progress_state * progress_state) { MPIDU_Sock_event_t event; int mpi_errno = MPI_SUCCESS; MPIDI_STATE_DECL(MPID_STATE_MPIDI_CH3I_PROGRESS_WAIT); MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_CH3I_PROGRESS_WAIT); /* * MT: the following code will be needed if progress can occur between * MPIDI_CH3_Progress_start() and * MPIDI_CH3_Progress_wait(), or iterations of MPIDI_CH3_Progress_wait(). * * This is presently not possible, and thus the code is commented out. */ # if 0 /* FIXME: Was (USE_THREAD_IMPL == MPICH_THREAD_IMPL_NOT_IMPLEMENTED), which really meant not-using-global-mutex-thread model . This was true for the single threaded case, but was probably not intended for that case*/ { if (progress_state->ch.completion_count != MPIDI_CH3I_progress_completion_count) { goto fn_exit; } } # endif # ifdef MPICH_IS_THREADED MPIU_THREAD_CHECK_BEGIN { if (MPIDI_CH3I_progress_blocked == TRUE) { /* * Another thread is already blocking in the progress engine. * * MT: Another thread is already blocking in poll. Right now, * calls to MPIDI_CH3_Progress_wait() are effectively * serialized by the device. The only way another thread may * enter this function is if MPIDU_Sock_wait() blocks. If * this changes, a flag other than MPIDI_CH3I_Progress_blocked * may be required to determine if another thread is in * the progress engine. */ MPIDI_CH3I_Progress_delay(MPIDI_CH3I_progress_completion_count); goto fn_exit; } } MPIU_THREAD_CHECK_END # endif do { int made_progress = FALSE; /* make progress on NBC schedules, must come before we block on sock_wait */ mpi_errno = MPIDU_Sched_progress(&made_progress); if (mpi_errno) MPIU_ERR_POP(mpi_errno); if (made_progress) { MPIDI_CH3_Progress_signal_completion(); break; } # ifdef MPICH_IS_THREADED /* The logic for this case is just complicated enough that we write separate code for each possibility */ # ifdef HAVE_RUNTIME_THREADCHECK if (MPIR_ThreadInfo.isThreaded) { MPIDI_CH3I_progress_blocked = TRUE; mpi_errno = MPIDU_Sock_wait(MPIDI_CH3I_sock_set, MPIDU_SOCK_INFINITE_TIME, &event); MPIDI_CH3I_progress_blocked = FALSE; MPIDI_CH3I_progress_wakeup_signalled = FALSE; } else { mpi_errno = MPIDU_Sock_wait(MPIDI_CH3I_sock_set, MPIDU_SOCK_INFINITE_TIME, &event); } # else MPIDI_CH3I_progress_blocked = TRUE; mpi_errno = MPIDU_Sock_wait(MPIDI_CH3I_sock_set, MPIDU_SOCK_INFINITE_TIME, &event); MPIDI_CH3I_progress_blocked = FALSE; MPIDI_CH3I_progress_wakeup_signalled = FALSE; # endif /* HAVE_RUNTIME_THREADCHECK */ # else mpi_errno = MPIDU_Sock_wait(MPIDI_CH3I_sock_set, MPIDU_SOCK_INFINITE_TIME, &event); # endif /* --BEGIN ERROR HANDLING-- */ if (mpi_errno != MPI_SUCCESS) { MPIU_Assert(MPIR_ERR_GET_CLASS(mpi_errno) != MPIDU_SOCK_ERR_TIMEOUT); MPIU_ERR_SET(mpi_errno,MPI_ERR_OTHER,"**progress_sock_wait"); goto fn_fail; } /* --END ERROR HANDLING-- */ mpi_errno = MPIDI_CH3I_Progress_handle_sock_event(&event); if (mpi_errno != MPI_SUCCESS) { MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER, "**ch3|sock|handle_sock_event"); } } while (progress_state->ch.completion_count == MPIDI_CH3I_progress_completion_count); /* * We could continue to call MPIU_Sock_wait in a non-blocking fashion * and process any other events; however, this would not * give the application a chance to post new receives, and thus could * result in an increased number of unexpected messages * that would need to be buffered. */ # if MPICH_IS_THREADED { /* * Awaken any threads which are waiting for the progress that just * occurred */ MPIDI_CH3I_Progress_continue(MPIDI_CH3I_progress_completion_count); } # endif fn_exit: /* * Reset the progress state so it is fresh for the next iteration */ progress_state->ch.completion_count = MPIDI_CH3I_progress_completion_count; MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_CH3I_PROGRESS_WAIT); return mpi_errno; fn_fail: goto fn_exit; }