⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpid_rma_common.c

📁 fortran并行计算包
💻 C
📖 第 1 页 / 共 5 页
字号:
 * * (See MPIDU_free_resource()) This does not take into account * any additional allocations done by the element type. Whether * any such buffers need to be freed depends on how the element- * type re-uses elements (when taken off the free list). * * \param[in] qhead	Queue Head * \param[in] el	Element object * \param[in] pe	Parent element object, or NULL if 'el' *		is at top of queue. * \return nothing * * \ref rsrc_design */void MPIDU_free_element(struct mpid_qhead *qhead,                                        void *el, void *pe) {        struct mpid_resource *lq = qhead->blocks;        struct mpid_element *wp = el;        struct mpid_element *pp = pe;        MPID_assert_debug(lq != NULL && wp != NULL);        /*         * sanity check - 'pp' must be parent of 'wp'         * or 'wp' must be at qhead->next_used.         */        MPID_assert_debug(pp == NULL || pp->next == wp);        MPID_assert_debug(pp != NULL || lq->next_used == wp);        if (lq->last_used == wp) {                lq->last_used = pp;        }        if (pp) {                pp->next = wp->next;        } else {                lq->next_used = wp->next;        }        wp->next = lq->next_free;        lq->next_free = wp;}/** * \brief Pop first element off used list (top of queue). * * Element contents is copied into 'el', if not NULL. * Popped element is placed on free list. * Returns 0 (success) if element was popped, or 1 if list empty. * * \param[in] qhead	Queue Head * \param[out] el	Element contents buffer * \return 1 if no elements on queue or *	0 on success with 'el' filled-in. * * \ref rsrc_design */int MPIDU_pop_element(struct mpid_qhead *qhead, void *el) {        struct mpid_element *wp;        struct mpid_resource *lq = qhead->blocks;        if (lq == NULL || lq->next_used == NULL) {                return 1;        }        wp = lq->next_used;        if (el != NULL) {                memcpy(el, wp, qhead->len);        }        /* we know there was no parent... */        MPIDU_free_element(qhead, wp, NULL);        return 0;}/** * \brief Find specific element in queue. * * Find element in used list that "matches" according to * 'func'('el', ...). 'func' is called with arbitrary parameter 'el' * and pointer to element under test. Only one element is found, * always the first "match". 'func' returns 0 for match (success). * * Returns NULL if no match found. * If 'parent' is not NULL, returns pointer to parent element there. * Note, '*parent' == NULL means element is first in list. * * \param[in] qhead	Queue Head * \param[in] func	Function to use to test for desired element * \param[in] v3	void arg passed to \e func in 3rd arg * \param[in] el	Static first parameter for 'func' * \param[in,out] parent	Pointer to parent element to start search from; *		Pointer to parent element of match found, *		or NULL if 'el' is at top of queue. * \return Pointer to element found with 'parent' set, *	or NULL if not found. * * \ref rsrc_design */void *MPIDU_find_element(struct mpid_qhead *qhead,                int (*func)(void *, void *, void *), void *v3, void *el,                struct mpid_element **parent) {        struct mpid_element *wp, *pp = NULL;        if (qhead->blocks == NULL) {                return NULL;        }        wp = (parent && *parent ? (*parent)->next : qhead->blocks->next_used);        if (wp) {                if (!func(el, wp, v3)) {                        // we don't remove it here...                        //qhead->blocks->next_used = wp->next;                } else {                        for (pp = wp; pp->next && func(el, pp->next, v3);                                                pp = pp->next);                        wp = pp->next;                }        }        if (parent) {                *parent = pp;        }        return wp;}/* * * * * * Remote (origin, foreign) Datatype cache * * * * * *//** * \page dtcache_design Datatype Cache Design * * The datatype cache element stores the rank, datatype handle * and the localized datatype object (map and iovec). Builtin * datatypes are not cached (and not sent). * * This cache is used in a split fashion, where "cloned" * cache entries exist on the origin side to tell the origin * when it can skip (re-)sending the datatype.  On the target * side the datatype will be fully allocated for each origin. * Because a node may be both an origin at one time and * a target at another, cache entries must be separated since * the handles in the two cases might match but do not indicate * the same datatype. Entries that are origin side dataypes have * the (target) rank with the high bit set.  This prevents a * collision between local datatypes we send to that target * and foreign datatypes sent to us from that target. * * Datatype transfers are done in two sends. * * - The first send * consists of the \e MPID_Type_map structure, as generated on * the origin node. * - The second send is the datatype's \e DLOOP_VECTOR, which * defines the contiguous, type-less, regions. * * The actual (original) map and iovec are created/stored in a cache entry * under the origin node. Since the origin node never talks to itself, * this cache entry will never conflict with any remote datatype caching. * * Before any sends are done on the origin node, an attempt is made * to create a new cache entry for this datatype/target rank pair. * If this succeeds, then the datatype has not been sent to the * target before and so will be sent now.  Otherwise the entire * transfer of the datatype will be skipped. * * When the target node receives the first send, the callback * attempts to create a datatype cache entry for the datatype/origin * pair. Then a handle-object is created and a receive is setup * into the handle-object map buffer. * * When the target node receives the second send, the callback * allocates a buffer for the iovec.  It then sets up to * receive into the dataloop buffer. * * In order to facilitate/optimize cache flushing, a remote (target) * node always receives a datatype that is sent, even if it already * has a cache entry (i.e. it overwrites any existing cache data). * This means that the origin node must only flush its own, local, cache * when a datatype goes away, and if/when a new datatype uses the * same handle then the target side will get a new copy and replace * the old one. *//** \brief Number of Datatype Cache elements per allocation block */#define MPIDU_NUM_DTC_ENTRIES	7/** * \brief Datatype Cache Element */struct mpid_dtc_entry {        struct mpid_dtc_entry *next;	/**< next used or next free */        int lpid;		/**< origin lpid, or target lpid | MSB */        MPI_Datatype dt;	/**< datatype handle on origin */        int _pad;		/**< pad to power of two size */        mpid_dt_info dti;	/**< extracted info from datatype */};/** \brief Padding for Datatype Cache Element resource block header */#define MPIDU_PAD_DTC_ENTRIES	0/** \brief Queue Head for Datatype Cache */static struct mpid_qhead dtc =        MPIDU_INIT_QHEAD_DECL(MPIDU_NUM_DTC_ENTRIES,                sizeof(struct mpid_dtc_entry), MPIDU_PAD_DTC_ENTRIES);/* * The following are used on the ranks passed to MPIDU_locate_dt() * (et al.), specifically in the rank embedded in the element used to * create, and search for, elements in the datatype cache. *//** \brief OR'ed with rank in datatype cache in DT receives */#define MPIDU_ORIGIN_FLAG	0/** \brief OR'ed with rank in datatype cache in DT sends */#define MPIDU_TARGET_FLAG	INT_MSB/** \brief test whether a datatype cache rank is target (origin-side entry) */#define MPIDU_IS_TARGET(r)	(((r) & MPIDU_TARGET_FLAG) == MPIDU_TARGET_FLAG)/** \brief extract a datatype cache rank realm (TARGET or ORIGIN) */#define MPIDU_DT_REALM(r)	((r) & INT_MSB)/** \brief extract a datatype cache rank */#define MPIDU_DT_LPID(r)	((r) & ~INT_MSB)/** * \brief Callback function to match datatype cache entry * * 'v1' is a struct mpid_dtc_entry with lpid and dt filled in with *      desired origin lpid and foreign datatype handle. * 'v2' is the (currrent) struct mpid_dtc_entry being examined as *      a potential match. * 'v3' optional pointer to element pointer, which will be filled *	with the element that contains the already-built datatype *	map and iovec, if it exists.  This element is the one that *	has the local node's lpid. * * \param[in] v1	Desired datatype cache pseudo-element * \param[in] v2	Datatype cache element to compare with 'v1' * \param[in] v3	Pointer to Datatype cache element pointer *			where same datatype but different target *			will be saved, if v3 not NULL * \return boolean indicating if 'v2' does not matche 'v1'. * * \ref dtcache_design */static int mpid_match_dt(void *v1, void *v2, void *v3) {        struct mpid_dtc_entry *w1 = (struct mpid_dtc_entry *)v1;        struct mpid_dtc_entry *w2 = (struct mpid_dtc_entry *)v2;        if (w1->dt != w2->dt) {                /* couldn't possibly match */                return 1;        }        if (w1->lpid == w2->lpid) {                /* exact match */                return 0;        }        if (v3 && MPIDU_DT_LPID(w2->lpid) == mpid_my_lpid) {                *((struct mpid_dtc_entry **)v3) = w2;        }        return 1;}/** * \brief Locate a cached foreign datatype. * * Internal use only - within datatype cache routines. * Locate a foreign (remote, origin) datatype cache object in * local cache. Returns pointer to datatype cache object. * Uses origin lpid and (foreign) datatype to match. * Flag/pointer 'new' indicates whether the object must not already exist. * If 'new' is not NULL and object exists, sets *new to "0"; or if does *	not exist then create new object and set *new to "1". * If 'new' is NULL and object does not exist, returns NULL. * * \param[in] lpid	Rank of origin (locker) * \param[in] dt	Datatype handle to search for * \param[in] new	Pointer to boolean for flag indicating *			new element was created.  If this is not NULL, *			then a new element will be created if none exists. * \param[in] src	Pointer to datatype cache element pointer *			used to save "closest match" element. * \return If 'new' is false, returns pointer to *	datatype cache element found, or NULL if none found. *	In the case of 'new' being true, returns NULL if *	datatype already exists, or a pointer to a newly-created *	cache element otherwise. * * \ref dtcache_design */static struct mpid_dtc_entry *MPIDU_locate_dt(int lpid,                                MPI_Datatype dt, int *new,                                struct mpid_dtc_entry **src) {        struct mpid_dtc_entry el, *ep;        el.lpid = lpid;        el.dt = dt;        ep = MPIDU_find_element(&dtc, mpid_match_dt, src, &el, NULL);        if (new) {                if (ep == NULL) {                        /* el was untouched by (failed) MPIDU_find_element() */                        memset(&el.dti, 0, sizeof(el.dti));                        ep = MPIDU_add_element(&dtc, &el);                        *new = 1;                } else {                        *new = 0;                }        }        return ep;}/** * \brief Callback function to match datatype cache entry for all lpids * * 'v1' is a struct mpid_dtc_entry with dt filled in with *      desired origin foreign datatype handle. * 'v2' is the (currrent) struct mpid_dtc_entry being examined as *      a potential match. * * \param[in] v1	Desired datatype cache pseudo-element * \param[in] v2	Datatype cache element to compare with 'v1' * \param[in] v3	Not used. * \return boolean indicating if 'v2' does not match 'v1', match *			on origin-side cache entry with same handle. * * \ref dtcache_design */static int mpid_flush_dt(void *v1, void *v2, void *v3) {        struct mpid_dtc_entry *w1 = (struct mpid_dtc_entry *)v1;        struct mpid_dtc_entry *w2 = (struct mpid_dtc_entry *)v2;        return (!MPIDU_IS_TARGET(w2->lpid) || w1->dt != w2->dt);}/** * \brief Function to remove all datatype cache entries for specific datatype * * Should be called whenever a datatype is freed/destroyed. Alternatively, * could be called whenever a datatype is detected as having changed * (i.e. handle gets re-used). * * \param[in] dtp	MPID_Datatype object to be flushed * \return	number of entries flushed */static int MPIDU_flush_dt(MPID_Datatype *dtp) {        struct mpid_dtc_entry el, *ep;        struct mpid_element *pp = NULL;        int n = 0;        el.dt = dtp->handle;        while ((ep = MPIDU_find_element(&dtc, mpid_flush_dt, NULL, &el, &pp)) != NULL) {                if (MPIDU_DT_LPID(ep->lpid) == mpid_my_lpid) {                        if (ep->dti.map)                                MPIDU_FREE(ep->dti.map, mpi_errno, "MPIDU_flush_dt");                        if (ep->dti.dtp && !ep->dti.dtp->handle)                                MPIDU_FREE(ep->dti.dtp, mpi_errno, "MPIDU_flush_dt");                }                MPIDU_free_element(&dtc, ep, pp);                ++n;        }        return n;}void MPIDU_dtc_free(MPID_Datatype *dtp) {        (void)MPIDU_flush_dt(dtp);}#ifdef NOT_USED/** * \brief Get Datatype info for a foreign datatype

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -