📄 mpid_rma_common.c
字号:
/* (C)Copyright IBM Corp. 2007, 2008 *//** * \file src/onesided/mpid_rma_common.c * \brief MPI-DCMF Code and data common to RMA modules */#include "mpid_onesided.h"#if 0char *msgtypes[] = {[MPID_MSGTYPE_NONE] = "MPID_MSGTYPE_NONE",[MPID_MSGTYPE_LOCK] = "MPID_MSGTYPE_LOCK",[MPID_MSGTYPE_UNLOCK] = "MPID_MSGTYPE_UNLOCK",[MPID_MSGTYPE_POST] = "MPID_MSGTYPE_POST",[MPID_MSGTYPE_START] = "MPID_MSGTYPE_START",[MPID_MSGTYPE_COMPLETE] = "MPID_MSGTYPE_COMPLETE",[MPID_MSGTYPE_WAIT] = "MPID_MSGTYPE_WAIT",[MPID_MSGTYPE_FENCE] = "MPID_MSGTYPE_FENCE",[MPID_MSGTYPE_UNFENCE] = "MPID_MSGTYPE_UNFENCE",[MPID_MSGTYPE_PUT] = "MPID_MSGTYPE_PUT",[MPID_MSGTYPE_GET] = "MPID_MSGTYPE_GET",[MPID_MSGTYPE_ACC] = "MPID_MSGTYPE_ACC",[MPID_MSGTYPE_DT_MAP] = "MPID_MSGTYPE_DT_MAP",[MPID_MSGTYPE_DT_IOV] = "MPID_MSGTYPE_DT_IOV",[MPID_MSGTYPE_LOCKACK] = "MPID_MSGTYPE_LOCKACK",[MPID_MSGTYPE_UNLOCKACK] = "MPID_MSGTYPE_UNLOCKACK",};#endif/** \brief DCMF Protocol object for DCMF_Send() calls */DCMF_Protocol_t bg1s_sn_proto;/** \brief DCMF Protocol object for DCMF_Get() calls */DCMF_Protocol_t bg1s_gt_proto;/** \brief DCMF Protocol object for DCMF_Control() calls */DCMF_Protocol_t bg1s_ct_proto;/** * \page msginfo_usage Message info (DCQuad) usage conventions * * First (or only) quad: * - \e w0 = Message type (MPID_MSGTYPE_*) * - \e w1 = (target) window handle * (except Datatype map/iov messages use num elements) * - \e w2 = (originating) rank * - \e w3 = Depends on message type: *<TABLE BORDER=0 CELLPADDING=0> *<TR><TH ALIGN="RIGHT">Epoch End:</TH> * <TD>RMA send count</TD></TR> *<TR><TH ALIGN="RIGHT">Put/Accumulate:</TH> * <TD>target memory address</TD></TR> *<TR><TH ALIGN="RIGHT">Lock:</TH> * <TD>lock type</TD></TR> *<TR><TH ALIGN="RIGHT">Datatype/loop:</TH> * <TD>datatype (handle on origin)</TD></TR> *</TABLE> * * Additional quads are message-specific * * MPID_MSGTYPE_ACC: * - \e w0 = target datatype (handle on origin) * - \e w1 = operand handle (must be builtin) * - \e w2 = length (number of datatype instances) * - \e w3 = 0 * * \note Epoch End includes MPID_MSGTYPE_UNLOCK and MPID_MSGTYPE_COMPLETE * (MPID_Win_fence() uses NMPI_Allreduce()). *//** \brief global for our lpid */unsigned mpid_my_lpid = -1;/** * \brief Build datatype map and iovec * * \param[in] dt Datatype to build map/iov for * \param[out] dti Pointer to datatype info struct */void make_dt_map_vec(MPI_Datatype dt, mpid_dt_info *dti) { int nb, last; MPID_Segment seg; MPID_Type_map *mv; DLOOP_VECTOR *iv; int i; MPI_Datatype eltype; unsigned size; MPID_Datatype *dtp; /* NOTE: we know "dt" is not builtin, else why do this? */ /* Use existing routines to get IOV */ MPID_Datatype_get_ptr(dt, dtp); nb = dtp->n_contig_blocks + 1; MPIDU_MALLOC(mv, MPID_Type_map, nb * sizeof(*mv), last, "MPID_Type_map"); MPID_assert(mv != NULL); iv = (DLOOP_VECTOR *)mv; MPID_Segment_init(NULL, 1, dt, &seg, 0); last = dtp->size; MPID_Segment_pack_vector(&seg, 0, &last, iv, &nb); if (HANDLE_GET_KIND(dtp->eltype) == HANDLE_KIND_BUILTIN) { eltype = dtp->eltype; size = MPID_Datatype_get_basic_size(eltype); } else { eltype = 0; size = 0; /* don't care */ } /* This works because we go backwards, and DLOOP_VECTOR << MPID_Type_map */ for (i = nb; i > 0; ) { --i; mv[i].off = (unsigned)iv[i].DLOOP_VECTOR_BUF; mv[i].len = iv[i].DLOOP_VECTOR_LEN; mv[i].num = (eltype ? mv[i].len / size : 0); mv[i].dt = eltype; } dti->map_len = nb; dti->map = mv; dti->dtp = dtp;}/** * \brief Datatype created to represent the rma_sends element * of the coll_info array of the window structure */MPI_Datatype Coll_info_rma_dt;/** * \brief User defined function created to process the rma_sends * elements of the coll_info array of the window structure */MPI_Op Coll_info_rma_op;/** * \brief Dummy, global, MPID_Progress_state since its not used. */MPID_Progress_state dummy_state;/* * * * * * Generic resource pool management * * * * * *//** * \page rsrc_design Basic resource element design * * Generic resources are managed through a \e mpid_qhead structure * which defines the basic geometry of the allocation blocks and * references the first allocated block. * * Generic resources are allocated in blocks. Each block begins * with a header of \e mpid_resource and is followed by a number * of elements whose size and count are defined for each resource * type. Also, the header size is defined, which may be larger * than the natural size of \e mpid_resource in order to optimize * memory layout (i.e. cache usage). * * Resource blocks are never freed (exception: lock wait queue * resources are freed when the window is freed). * * Specific resources are defined by their elements. Every resource * element must have as its first field the \e next pointer, as * defined by \e mpid_element. Following this is * defined by the needs of the specific resource. * * A newly allocated block is initialized with all elements \e next * chained together and the block's \e next_free pointer set to the * first (free) element. Except for the first allocated block * (the one directly referenced by \e mpid_qhead), the \e next_free * is not used again. This also applies to the \e next_used and * \e last_used pointers. * * A newly allocated secondary block is linked into the \e mpid_qhead * \e next_block chain and \e next_free chain. * * When an element is taken from the free list, it is always taken * from the top of the list, i.e. directly from \e next_free. * When an element is returned to the free list, it is placed * (pushed) on the top. So an element to be allocated is always the * one most-recently freed, i.e. a LIFO queue. * * When an element is added to the used list, it is always added * to the end of the list, i.e. using the \e last_used pointer. * If an arbitrary element is taken from the used list, it is * taken from the top of the list, i.e. using \e next_used. This * effectively forms a FIFO queue. * * Other routines exist that permit the used list to be searched, * and the found element may be removed from the used list * "out of turn". A specific resource implementation decides * how it will use this list. *//** * \brief Allocate a new block of elements. * * Unconditionally allocates a block of resources as described by * 'qhead' and link the block into 'qhead'. The new elements * are added to the 'qhead' free list. The new elements are * uninitialized except for the mpid_element field(s). * * \param[in] qhead Queue Head * \return nothing * * \ref rsrc_design */void MPIDU_alloc_resource(struct mpid_qhead *qhead) { struct mpid_resource *nq; struct mpid_element *ne, *nl; struct mpid_resource *lq; int x, z; z = qhead->hdl + (qhead->num * qhead->len); MPIDU_MALLOC(nq, struct mpid_resource, z, x, "MPIDU_alloc_resource"); MPID_assert(nq != NULL); nq->next_used = NULL; nq->last_used = NULL; nq->next_block = NULL; /* point to last element in block */ ne = (struct mpid_element *)((char *)nq + z - qhead->len); nl = NULL; /* stitch together elements, starting at end */ for (x = 0; x < qhead->num; ++x) { ne->next = nl; nl = ne; ne = (struct mpid_element *)((char *)ne - qhead->len); } nq->next_free = nl; /* Determine how to append new block to block list */ if (qhead->blocks == NULL) { qhead->blocks = nq; } else { /* locate end of block list */ lq = qhead->lastblock; lq->next_block = nq; lq = qhead->blocks; /* reset/rewind */ /* determine how to append new elements to free list */ if (lq->next_free == NULL) { lq->next_free = nq->next_free; } else { /* locate end of free list */ for (ne = lq->next_free; ne->next; ne = ne->next); ne->next = nq->next_free; } } qhead->lastblock = nq;}/** * \brief Unconditionally free all resource blocks * referenced by 'qhead'. * * NOTE: elements such as datatype cache require addition freeing * and so won't work with this. We could add a "free func ptr" to * qhead and call it here - so each element type can free any other * buffers it may have allocated. * * Right now, this is only called by Win_free() on the lock and unlock * wait queues, which do no additional allocation. * * \param[in] qhead Queue Head * \return nothing * * \ref rsrc_design */void MPIDU_free_resource(struct mpid_qhead *qhead) { struct mpid_resource *qp, *np; for (qp = qhead->blocks; qp != NULL; qp = np) { np = qp->next_block; MPIDU_FREE(qp, e, "MPIDU_free_resource"); } qhead->blocks = NULL;}/** * \brief Get a new (unused) resource element. * * Take a resource element off the free list and put it on the * end of used list (bottom of queue). Element is uninitialized * except for mpid_element structure fields. * * \param[in] qhead Queue Head * \return pointer to element. * * \ref rsrc_design */void *MPIDU_get_element(struct mpid_qhead *qhead) { struct mpid_resource *lq = qhead->blocks; struct mpid_element *wp; if (lq == NULL || lq->next_free == NULL) { MPIDU_alloc_resource(qhead); lq = qhead->blocks; MPID_assert_debug(lq != NULL && lq->next_free != NULL); } wp = lq->next_free; lq->next_free = wp->next; if (lq->last_used != NULL) { lq->last_used->next = wp; } wp->next = NULL; lq->last_used = wp; if (lq->next_used == NULL) { lq->next_used = wp; } return wp;}/** * \brief Initialize a new (unused) element. * * Get a new element from free list and initialize its contents * from 'el'. Element is placed at bottom of queue. * 'el' is assumed to be of qhead->len size. * * \param[in] qhead Queue Head * \param[in] el Pointer to new element data * \return pointer to element. * * \ref rsrc_design */void *MPIDU_add_element(struct mpid_qhead *qhead, void *el) { struct mpid_element *wp; wp = MPIDU_get_element(qhead); MPID_assert_debug(wp != NULL); memcpy( (char *)wp + sizeof(struct mpid_element), (char *)el + sizeof(struct mpid_element), qhead->len - sizeof(struct mpid_element)); return wp;}/** * \brief Peek at top element in queue (used list). * * Copy contents of first element in used list (top of queue) * into 'el'. Does not alter qhead (used or free lists). * 'el' is assumed to be of qhead->len size. * * \param[in] qhead Queue Head * \param[out] el Pointer to destination for element data * \return 1 if no elements on queue or * 0 on success with 'el' filled-in. * * \ref rsrc_design */int MPIDU_peek_element(struct mpid_qhead *qhead, void *el) { struct mpid_resource *lq = qhead->blocks; if (lq == NULL || lq->next_used == NULL) { return 1; } if (el != NULL) { memcpy(el, lq->next_used, qhead->len); } return 0;}/** * \brief Free an element. * * Remove element 'el' (parent element 'pe') from used list * and place on free list. Typically, this is only called * after calling MPIDU_find_element() to obtain 'el' and 'pe'.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -