static int DLOOP_Dataloop_create_flattened_struct(DLOOP_Count count, const int *blklens, const MPI_Aint *disps, const DLOOP_Type *oldtypes, DLOOP_Dataloop **dlp_p, MPI_Aint *dlsz_p, int *dldepth_p, int flag) { /* arbitrary types, convert to bytes and use indexed */ int i, err, nr_blks = 0; DLOOP_Size *tmp_blklens; MPI_Aint *tmp_disps; /* since we're calling another fn that takes this type as an input parameter */ DLOOP_Offset bytes; DLOOP_Segment *segp; int first_ind; DLOOP_Size last_ind; segp = MPIR_Segment_alloc(); /* --BEGIN ERROR HANDLING-- */ if (!segp) { return DLOOP_Dataloop_create_struct_memory_error(); } /* --END ERROR HANDLING-- */ /* use segment code once to count contiguous regions */ for (i=0; i < count; i++) { int is_basic; /* ignore type elements with a zero blklen */ if (blklens[i] == 0) continue; is_basic = (DLOOP_Handle_hasloop_macro(oldtypes[i])) ? 0 : 1; if (is_basic && (oldtypes[i] != MPI_LB && oldtypes[i] != MPI_UB)) { nr_blks++; } else /* derived type; get a count of contig blocks */ { DLOOP_Count tmp_nr_blks, sz; DLOOP_Handle_get_size_macro(oldtypes[i], sz); /* if the derived type has some data to contribute, * add to flattened representation */ if (sz > 0) { err = MPIR_Segment_init(NULL, (DLOOP_Count) blklens[i], oldtypes[i], segp, flag); if (err) return err; bytes = SEGMENT_IGNORE_LAST; MPIR_Segment_count_contig_blocks(segp, 0, &bytes, &tmp_nr_blks); nr_blks += tmp_nr_blks; } } } /* it's possible for us to get to this point only to realize that * there isn't any data in this type. in that case do what we always * do: store a simple contig of zero ints and call it done. */ if (nr_blks == 0) { MPIR_Segment_free(segp); err = MPIR_Dataloop_create_contiguous(0, MPI_INT, dlp_p, dlsz_p, dldepth_p, flag); return err; } nr_blks += 2; /* safety measure */ tmp_blklens = (DLOOP_Size *) DLOOP_Malloc(nr_blks * sizeof(DLOOP_Size), MPL_MEM_DATATYPE); /* --BEGIN ERROR HANDLING-- */ if (!tmp_blklens) { MPIR_Segment_free(segp); return DLOOP_Dataloop_create_struct_memory_error(); } /* --END ERROR HANDLING-- */ tmp_disps = (MPI_Aint *) DLOOP_Malloc(nr_blks * sizeof(MPI_Aint), MPL_MEM_DATATYPE); /* --BEGIN ERROR HANDLING-- */ if (!tmp_disps) { DLOOP_Free(tmp_blklens); MPIR_Segment_free(segp); return DLOOP_Dataloop_create_struct_memory_error(); } /* --END ERROR HANDLING-- */ /* use segment code again to flatten the type */ first_ind = 0; for (i=0; i < count; i++) { int is_basic; DLOOP_Count sz = -1; is_basic = (DLOOP_Handle_hasloop_macro(oldtypes[i])) ? 0 : 1; if (!is_basic) DLOOP_Handle_get_size_macro(oldtypes[i], sz); /* we're going to use the segment code to flatten the type. * we put in our displacement as the buffer location, and use * the blocklength as the count value to get N contiguous copies * of the type. * * Note that we're going to get back values in bytes, so that will * be our new element type. */ if (oldtypes[i] != MPI_UB && oldtypes[i] != MPI_LB && blklens[i] != 0 && (is_basic || sz > 0)) { err = MPIR_Segment_init((char *) DLOOP_OFFSET_CAST_TO_VOID_PTR disps[i], (DLOOP_Count) blklens[i], oldtypes[i], segp, 0 /* homogeneous */); if (err) return err; last_ind = nr_blks - first_ind; bytes = SEGMENT_IGNORE_LAST; MPIR_Segment_mpi_flatten(segp, 0, &bytes, &tmp_blklens[first_ind], &tmp_disps[first_ind], &last_ind); if (err) return err; first_ind += last_ind; } } nr_blks = first_ind; #if 0 if (MPL_DBG_SELECTED(MPIR_DBG_DATATYPE,VERBOSE)) { MPL_DBG_OUT(MPIR_DBG_DATATYPE,"--- start of flattened type ---"); for (i=0; i < nr_blks; i++) { MPL_DBG_OUT_FMT(MPIR_DBG_DATATYPE,(MPL_DBG_FDEST, "a[%d] = (%d, " DLOOP_OFFSET_FMT_DEC_SPEC ")", i, tmp_blklens[i], tmp_disps[i])); } MPL_DBG_OUT(MPIR_DBG_DATATYPE,"--- end of flattened type ---"); } #endif MPIR_Segment_free(segp); err = MPIR_Dataloop_create_indexed(nr_blks, tmp_blklens, tmp_disps, 1, /* disp in bytes */ MPI_BYTE, dlp_p, dlsz_p, dldepth_p, flag); DLOOP_Free(tmp_blklens); DLOOP_Free(tmp_disps); return err; }
int MPIDI_CH3U_Receive_data_found(MPIR_Request *rreq, void *buf, intptr_t *buflen, int *complete) { int dt_contig; MPI_Aint dt_true_lb; intptr_t userbuf_sz; MPIR_Datatype * dt_ptr = NULL; intptr_t data_sz; int mpi_errno = MPI_SUCCESS; MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPIDI_CH3U_RECEIVE_DATA_FOUND); MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPIDI_CH3U_RECEIVE_DATA_FOUND); MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"posted request found"); MPIDI_Datatype_get_info(rreq->dev.user_count, rreq->dev.datatype, dt_contig, userbuf_sz, dt_ptr, dt_true_lb); if (rreq->dev.recv_data_sz <= userbuf_sz) { data_sz = rreq->dev.recv_data_sz; } else { MPL_DBG_MSG_FMT(MPIDI_CH3_DBG_OTHER,VERBOSE,(MPL_DBG_FDEST, "receive buffer too small; message truncated, msg_sz=%" PRIdPTR ", userbuf_sz=%" PRIdPTR, rreq->dev.recv_data_sz, userbuf_sz)); rreq->status.MPI_ERROR = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_TRUNCATE, "**truncate", "**truncate %d %d %d %d", rreq->status.MPI_SOURCE, rreq->status.MPI_TAG, rreq->dev.recv_data_sz, userbuf_sz ); MPIR_STATUS_SET_COUNT(rreq->status, userbuf_sz); data_sz = userbuf_sz; } if (dt_contig && data_sz == rreq->dev.recv_data_sz) { /* user buffer is contiguous and large enough to store the entire message. However, we haven't yet *read* the data (this code describes how to read the data into the destination) */ /* if all of the data has already been received, unpack it now, otherwise build an iov and let the channel unpack */ if (*buflen >= data_sz) { MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"Copying contiguous data to user buffer"); /* copy data out of the receive buffer */ if (rreq->dev.drop_data == FALSE) { MPIR_Memcpy((char*)(rreq->dev.user_buf) + dt_true_lb, buf, data_sz); } *buflen = data_sz; *complete = TRUE; } else { MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"IOV loaded for contiguous read"); rreq->dev.iov[0].MPL_IOV_BUF = (MPL_IOV_BUF_CAST)((char*)(rreq->dev.user_buf) + dt_true_lb); rreq->dev.iov[0].MPL_IOV_LEN = data_sz; rreq->dev.iov_count = 1; *buflen = 0; *complete = FALSE; } /* Trigger OnFinal when receiving the last segment */ rreq->dev.OnDataAvail = rreq->dev.OnFinal; } else { /* user buffer is not contiguous or is too small to hold the entire message */ rreq->dev.segment_ptr = MPIR_Segment_alloc( ); MPIR_ERR_CHKANDJUMP1((rreq->dev.segment_ptr == NULL), mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPIR_Segment_alloc"); MPIR_Segment_init(rreq->dev.user_buf, rreq->dev.user_count, rreq->dev.datatype, rreq->dev.segment_ptr); rreq->dev.segment_first = 0; rreq->dev.segment_size = data_sz; /* if all of the data has already been received, and the message is not truncated, unpack it now, otherwise build an iov and let the channel unpack */ if (data_sz == rreq->dev.recv_data_sz && *buflen >= data_sz) { intptr_t last; MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"Copying noncontiguous data to user buffer"); last = data_sz; MPIR_Segment_unpack(rreq->dev.segment_ptr, rreq->dev.segment_first, &last, buf); /* --BEGIN ERROR HANDLING-- */ if (last != data_sz) { /* If the data can't be unpacked, the we have a mismatch between the datatype and the amount of data received. Throw away received data. */ MPIR_ERR_SET(rreq->status.MPI_ERROR, MPI_ERR_TYPE, "**dtypemismatch"); MPIR_STATUS_SET_COUNT(rreq->status, rreq->dev.segment_first); *buflen = data_sz; *complete = TRUE; /* FIXME: Set OnDataAvail to 0? If not, why not? */ goto fn_exit; } /* --END ERROR HANDLING-- */ *buflen = data_sz; /* Trigger OnFinal when receiving the last segment */ rreq->dev.OnDataAvail = rreq->dev.OnFinal; *complete = TRUE; } else { MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"IOV loaded for non-contiguous read"); mpi_errno = MPIDI_CH3U_Request_load_recv_iov(rreq); if (mpi_errno != MPI_SUCCESS) { MPIR_ERR_SETFATALANDJUMP(mpi_errno,MPI_ERR_OTHER, "**ch3|loadrecviov"); } *buflen = 0; *complete = FALSE; } } fn_exit: MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPIDI_CH3U_RECEIVE_DATA_FOUND); return mpi_errno; fn_fail: goto fn_exit; }
int MPIDI_CH3U_Post_data_receive_found(MPIR_Request * rreq) { int mpi_errno = MPI_SUCCESS; int dt_contig; MPI_Aint dt_true_lb; intptr_t userbuf_sz; MPIR_Datatype * dt_ptr = NULL; intptr_t data_sz; MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPIDI_CH3U_POST_DATA_RECEIVE_FOUND); MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPIDI_CH3U_POST_DATA_RECEIVE_FOUND); MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"posted request found"); MPIDI_Datatype_get_info(rreq->dev.user_count, rreq->dev.datatype, dt_contig, userbuf_sz, dt_ptr, dt_true_lb); if (rreq->dev.recv_data_sz <= userbuf_sz) { data_sz = rreq->dev.recv_data_sz; } else { MPL_DBG_MSG_FMT(MPIDI_CH3_DBG_OTHER,VERBOSE,(MPL_DBG_FDEST, "receive buffer too small; message truncated, msg_sz=%" PRIdPTR ", userbuf_sz=%" PRIdPTR, rreq->dev.recv_data_sz, userbuf_sz)); rreq->status.MPI_ERROR = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_TRUNCATE, "**truncate", "**truncate %d %d %d %d", rreq->status.MPI_SOURCE, rreq->status.MPI_TAG, rreq->dev.recv_data_sz, userbuf_sz ); MPIR_STATUS_SET_COUNT(rreq->status, userbuf_sz); data_sz = userbuf_sz; } if (dt_contig && data_sz == rreq->dev.recv_data_sz) { /* user buffer is contiguous and large enough to store the entire message. However, we haven't yet *read* the data (this code describes how to read the data into the destination) */ MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"IOV loaded for contiguous read"); rreq->dev.iov[0].MPL_IOV_BUF = (MPL_IOV_BUF_CAST)((char*)(rreq->dev.user_buf) + dt_true_lb); rreq->dev.iov[0].MPL_IOV_LEN = data_sz; rreq->dev.iov_count = 1; /* FIXME: We want to set the OnDataAvail to the appropriate function, which depends on whether this is an RMA request or a pt-to-pt request. */ rreq->dev.OnDataAvail = 0; } else { /* user buffer is not contiguous or is too small to hold the entire message */ MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"IOV loaded for non-contiguous read"); rreq->dev.segment_ptr = MPIR_Segment_alloc( ); MPIR_ERR_CHKANDJUMP1((rreq->dev.segment_ptr == NULL), mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPIR_Segment_alloc"); MPIR_Segment_init(rreq->dev.user_buf, rreq->dev.user_count, rreq->dev.datatype, rreq->dev.segment_ptr); rreq->dev.segment_first = 0; rreq->dev.segment_size = data_sz; mpi_errno = MPIDI_CH3U_Request_load_recv_iov(rreq); if (mpi_errno != MPI_SUCCESS) { MPIR_ERR_SETFATALANDJUMP(mpi_errno,MPI_ERR_OTHER, "**ch3|loadrecviov"); } } fn_exit: MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPIDI_CH3U_POST_DATA_RECEIVE_FOUND); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Unpack_impl(const void *inbuf, MPI_Aint insize, MPI_Aint * position, void *outbuf, int outcount, MPI_Datatype datatype) { int mpi_errno = MPI_SUCCESS; MPI_Aint first, last; MPIR_Segment *segp; int contig; MPI_Aint dt_true_lb; MPI_Aint data_sz; if (insize == 0) goto fn_exit; /* Handle contig case quickly */ if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN) { contig = TRUE; dt_true_lb = 0; data_sz = outcount * MPIR_Datatype_get_basic_size(datatype); } else { MPIR_Datatype *dt_ptr; MPIR_Datatype_get_ptr(datatype, dt_ptr); MPIR_Datatype_is_contig(datatype, &contig); dt_true_lb = dt_ptr->true_lb; data_sz = outcount * dt_ptr->size; } if (contig) { MPIR_Memcpy((char *) outbuf + dt_true_lb, (char *) inbuf + *position, data_sz); *position = (int) ((MPI_Aint) * position + data_sz); goto fn_exit; } /* non-contig case */ segp = MPIR_Segment_alloc(); MPIR_ERR_CHKANDJUMP1(segp == NULL, mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPIR_Segment_alloc"); mpi_errno = MPIR_Segment_init(outbuf, outcount, datatype, segp); MPIR_Assert(mpi_errno == MPI_SUCCESS); /* NOTE: the use of buffer values and positions in MPI_Unpack and in * MPIR_Segment_unpack are quite different. See code or docs or something. */ first = 0; last = SEGMENT_IGNORE_LAST; /* Ensure that pointer increment fits in a pointer */ MPIR_Ensure_Aint_fits_in_pointer((MPIR_VOID_PTR_CAST_TO_MPI_AINT inbuf) + (MPI_Aint) * position); MPIR_Segment_unpack(segp, first, &last, (void *) ((char *) inbuf + *position)); /* Ensure that calculation fits into an int datatype. */ MPIR_Ensure_Aint_fits_in_int((MPI_Aint) * position + last); *position = (int) ((MPI_Aint) * position + last); MPIR_Segment_free(segp); fn_exit: return mpi_errno; fn_fail: goto fn_exit; }