/* make global btl list&map */ static int create_btl_list(void) { int btl_type; char *btl_name; int size; opal_list_item_t *item; mca_btl_base_selected_module_t *btl_sm; int i; size = opal_list_get_size(&mca_btl_base_modules_initialized); if (0 >= size) { SPML_ERROR("no btl(s) available"); return OSHMEM_ERROR; } SPML_VERBOSE(50, "found %d capable btls", size); mca_spml_yoda.btl_type_map = (struct yoda_btl *) calloc(size, sizeof(struct yoda_btl)); if (!mca_spml_yoda.btl_type_map) return OSHMEM_ERROR; mca_spml_yoda.n_btls = 0; for (i = 0, item = opal_list_get_first(&mca_btl_base_modules_initialized); item != opal_list_get_end(&mca_btl_base_modules_initialized); item = opal_list_get_next(item), i++) { btl_sm = (mca_btl_base_selected_module_t *) item; btl_name = btl_sm->btl_component->btl_version.mca_component_name; btl_type = btl_name_to_id(btl_name); SPML_VERBOSE(50, "found btl (%s) btl_type=%s", btl_name, btl_type2str(btl_type)); /* Note: we setup bml_btl in create_btl_idx() */ mca_spml_yoda.btl_type_map[mca_spml_yoda.n_btls].bml_btl = NULL; mca_spml_yoda.btl_type_map[mca_spml_yoda.n_btls].btl = btl_sm->btl_module; mca_spml_yoda.btl_type_map[mca_spml_yoda.n_btls].btl_type = btl_type; mca_spml_yoda.n_btls++; } if (0 == mca_spml_yoda.n_btls) { SPML_ERROR("can not find any suitable btl"); return OSHMEM_ERROR; } return OSHMEM_SUCCESS; }
/** * shmem_get reads data from a remote address * in the symmetric heap via RDMA READ. * Get operation: * 1. Get the rkey to the remote address. * 2. Allocate a get request. * 3. Allocated a temporary pre-registered buffer * to copy the data to. * 4. Init the request descriptor with remote side * data and local side data. * 5. Read the remote buffer to a pre-registered * buffer on the local PE using RDMA READ. * 6. Copy the received data to dst_addr if an * intermediate pre-register buffer was used. * 7. Clear the request and return. * * src_addr - address on remote pe. * size - the amount on bytes to be read. * dst_addr - address on the local pe. * src - the pe of remote process. */ int mca_spml_yoda_get(void* src_addr, size_t size, void* dst_addr, int src) { int rc = OSHMEM_SUCCESS; sshmem_mkey_t *r_mkey, *l_mkey; void* rva; unsigned ncopied = 0; unsigned int frag_size = 0; char *p_src, *p_dst; int i; int nfrags; mca_bml_base_btl_t* bml_btl = NULL; mca_btl_base_segment_t* segment; mca_btl_base_descriptor_t* des = NULL; mca_spml_yoda_rdma_frag_t* frag = NULL; struct mca_spml_yoda_getreq_parent get_holder; struct yoda_btl *ybtl; int btl_id = 0; int get_via_send; mca_btl_base_registration_handle_t *local_handle, *remote_handle = NULL; mca_spml_yoda_get_request_t* getreq = NULL; /*If nothing to get its OK.*/ if (0 >= size) { return rc; } /* Find bml_btl and its global btl_id */ bml_btl = get_next_btl(src, &btl_id); if (!bml_btl) { SPML_ERROR("cannot reach %d pe: no appropriate btl found", oshmem_my_proc_id()); rc = OSHMEM_ERR_FATAL; goto exit_fatal; } /* Check if btl has GET method. If it doesn't - use SEND*/ get_via_send = ! ( (bml_btl->btl->btl_flags & (MCA_BTL_FLAGS_GET)) && (bml_btl->btl->btl_flags & (MCA_BTL_FLAGS_PUT)) ); /* Get rkey of remote PE (src proc) which must be on memheap*/ r_mkey = mca_memheap_base_get_cached_mkey(src, src_addr, btl_id, &rva); if (!r_mkey) { SPML_ERROR("pe=%d: %p is not address of shared variable", src, src_addr); rc = OSHMEM_ERR_FATAL; goto exit_fatal; } #if SPML_YODA_DEBUG == 1 SPML_VERBOSE(100, "get: pe:%d src=%p -> dst: %p sz=%d. src_rva=%p, %s", src, src_addr, dst_addr, (int)size, (void *)rva, mca_spml_base_mkey2str(r_mkey)); #endif ybtl = &mca_spml_yoda.btl_type_map[btl_id]; if (ybtl->btl->btl_register_mem) { assert(ybtl->btl->btl_registration_handle_size == r_mkey->len); remote_handle = (mca_btl_base_registration_handle_t *) r_mkey->u.data; } nfrags = 1; /* check if we doing get into shm attached segment and if so * just do memcpy */ if ((YODA_BTL_SM == ybtl->btl_type || YODA_BTL_VADER == ybtl->btl_type) && mca_memheap_base_can_local_copy(r_mkey, src_addr)) { memcpy(dst_addr, (void *) rva, size); /* must call progress here to avoid deadlock. Scenarion: * pe1 pols pe2 via shm get. pe2 tries to get static variable from node one, which goes to sm btl * In this case pe2 is stuck forever because pe1 never calls opal_progress. * May be we do not need to call progress on every get() here but rather once in a while. */ opal_progress(); return OSHMEM_SUCCESS; } l_mkey = mca_memheap.memheap_get_local_mkey(dst_addr, btl_id); /* * Need a copy if local memory has not been registered or * we make GET via SEND */ frag_size = ncopied; if ((NULL == l_mkey) || get_via_send) { calc_nfrags_get (bml_btl, size, &frag_size, &nfrags, get_via_send); } p_src = (char*) (unsigned long) rva; p_dst = (char*) dst_addr; get_holder.active_count = 0; for (i = 0; i < nfrags; i++) { /** * Allocating a get request from a pre-allocated * and pre-registered free list. */ getreq = mca_spml_yoda_getreq_alloc(src); assert(getreq); getreq->p_dst = NULL; frag = &getreq->get_frag; getreq->parent = &get_holder; ncopied = i < nfrags - 1 ? frag_size :(unsigned) ((char *) dst_addr + size - p_dst); frag->allocated = 0; /* Prepare destination descriptor*/ memcpy(&frag->rdma_segs[0].base_seg, r_mkey->u.data, r_mkey->len); frag->rdma_segs[0].base_seg.seg_len = (get_via_send ? ncopied + SPML_YODA_SEND_CONTEXT_SIZE : ncopied); if (get_via_send) { frag->use_send = 1; frag->allocated = 1; /** * Allocate a temporary buffer on the local PE. * The local buffer will store the data read * from the remote address. */ mca_spml_yoda_bml_alloc(bml_btl, &des, MCA_BTL_NO_ORDER, (int)frag_size, MCA_BTL_DES_SEND_ALWAYS_CALLBACK, get_via_send); if (OPAL_UNLIKELY(!des || !des->des_segments)) { SPML_ERROR("shmem OOM error need %d bytes", ncopied); SPML_ERROR("src=%p nfrags = %d frag_size=%d", src_addr, nfrags, frag_size); rc = OSHMEM_ERR_FATAL; goto exit_fatal; } segment = des->des_segments; spml_yoda_prepare_for_get((void*)segment->seg_addr.pval, ncopied, (void*)p_src, oshmem_my_proc_id(), (void*)p_dst, (void*) getreq); des->des_cbfunc = mca_spml_yoda_get_response_completion; des->des_cbdata = frag; OPAL_THREAD_ADD32(&mca_spml_yoda.n_active_gets, 1); } else { /* * Register src memory if do GET via GET */ if (NULL == l_mkey && ybtl->btl->btl_register_mem) { local_handle = ybtl->btl->btl_register_mem (ybtl->btl, bml_btl->btl_endpoint, p_dst, ncopied, MCA_BTL_REG_FLAG_LOCAL_WRITE); if (NULL == local_handle) { SPML_ERROR("%s: failed to register destination memory %p.", btl_type2str(ybtl->btl_type), p_dst); } frag->local_handle = local_handle; } else { local_handle = ((mca_spml_yoda_context_t*)l_mkey->spml_context)->registration; frag->local_handle = NULL; } frag->rdma_segs[0].base_seg.seg_addr.lval = (uintptr_t) p_src; getreq->p_dst = (uint64_t*) p_dst; frag->size = ncopied; OPAL_THREAD_ADD32(&mca_spml_yoda.n_active_gets, 1); } /** * Initialize the remote data fragment * with remote address data required for * executing RDMA READ from a remote buffer. */ frag->rdma_req = getreq; /** * Do GET operation */ if (get_via_send) { rc = mca_bml_base_send(bml_btl, des, MCA_SPML_YODA_GET); if (1 == rc) rc = OSHMEM_SUCCESS; } else { rc = mca_bml_base_get(bml_btl, p_dst, (uint64_t) (intptr_t) p_src, local_handle, remote_handle, ncopied, 0, 0, mca_spml_yoda_get_completion, frag); } if (OPAL_UNLIKELY(OSHMEM_SUCCESS != rc)) { if (OSHMEM_ERR_OUT_OF_RESOURCE == rc) { /* No free resources, Block on completion here */ oshmem_request_wait_completion(&getreq->req_get.req_base.req_oshmem); return OSHMEM_SUCCESS; } else { SPML_ERROR("oshmem_get: error %d", rc); goto exit_fatal; } } p_dst += ncopied; p_src += ncopied; OPAL_THREAD_ADD32(&get_holder.active_count, 1); } /* revisit if we really need this for self and sm */ /* if (YODA_BTL_SELF == ybtl->btl_type) */ opal_progress(); /* Wait for completion on request */ while (get_holder.active_count > 0) oshmem_request_wait_completion(&getreq->req_get.req_base.req_oshmem); return rc; exit_fatal: if (OSHMEM_SUCCESS != rc) { oshmem_shmem_abort(rc); } return rc; }
sshmem_mkey_t *mca_spml_yoda_register(void* addr, size_t size, uint64_t shmid, int *count) { int i; sshmem_mkey_t *mkeys; struct yoda_btl *ybtl; mca_spml_yoda_context_t* yoda_context; SPML_VERBOSE(10, "address %p len %llu", addr, (unsigned long long)size); *count = 0; /* make sure everything is initialized to 0 */ mkeys = (sshmem_mkey_t *) calloc(1, mca_spml_yoda.n_btls * sizeof(*mkeys)); if (!mkeys) { return NULL ; } mca_bml.bml_register( MCA_SPML_YODA_PUT, mca_yoda_put_callback, NULL ); mca_bml.bml_register( MCA_SPML_YODA_GET, mca_yoda_get_callback, NULL ); mca_bml.bml_register( MCA_SPML_YODA_GET_RESPONSE, mca_yoda_get_response_callback, NULL ); /* Register proc memory in every rdma BTL. */ for (i = 0; i < mca_spml_yoda.n_btls; i++) { ybtl = &mca_spml_yoda.btl_type_map[i]; mkeys[i].va_base = addr; mkeys[i].u.key = MAP_SEGMENT_SHM_INVALID; if (!ybtl->use_cnt) { SPML_VERBOSE(10, "%s: present but not in use. SKIP registration", btl_type2str(ybtl->btl_type)); continue; } /* If we have shared memory just save its id */ if ((YODA_BTL_SM == ybtl->btl_type || YODA_BTL_VADER == ybtl->btl_type) && MAP_SEGMENT_SHM_INVALID != (int)shmid) { mkeys[i].u.key = shmid; mkeys[i].va_base = 0; continue; } yoda_context = calloc(1, sizeof(*yoda_context)); mkeys[i].spml_context = yoda_context; yoda_context->registration = NULL; if (ybtl->btl->btl_flags & MCA_BTL_FLAGS_RDMA) { if (NULL != ybtl->btl->btl_register_mem) { yoda_context->registration = ybtl->btl->btl_register_mem (ybtl->btl, MCA_BTL_ENDPOINT_ANY, addr, size, MCA_BTL_REG_FLAG_ACCESS_ANY); if (NULL == yoda_context->registration) { SPML_ERROR("%s: failed to register source memory: addr: %p, size: %u", btl_type2str(ybtl->btl_type), addr, size); /* FIXME some cleanup might be needed here * yoda_context->btl_src_descriptor = NULL; * *count = ???; * free(spml_context); */ free(mkeys); return NULL; } } yoda_context->btl_src_descriptor = NULL; mkeys[i].u.data = yoda_context->registration; mkeys[i].len = yoda_context->registration ? ybtl->btl->btl_registration_handle_size : 0; } SPML_VERBOSE(5, "rank %d btl %s va_base: 0x%p len: %d key %llx size %llu", oshmem_proc_pe(oshmem_proc_local()), btl_type2str(ybtl->btl_type), mkeys[i].va_base, mkeys[i].len, (unsigned long long)mkeys[i].u.key, (unsigned long long)size); } *count = mca_spml_yoda.n_btls; return mkeys; }
mca_spml_mkey_t *mca_spml_yoda_register(void* addr, size_t size, uint64_t shmid, int *count) { int i; mca_btl_base_descriptor_t* des = NULL; const opal_datatype_t *datatype = &opal_datatype_wchar; opal_convertor_t convertor; mca_spml_mkey_t *mkeys; struct yoda_btl *ybtl; oshmem_proc_t *proc_self; mca_spml_yoda_context_t* yoda_context; struct iovec iov; uint32_t iov_count = 1; SPML_VERBOSE(10, "address %p len %llu", addr, (unsigned long long)size); *count = 0; /* make sure everything is initialized to 0 */ mkeys = (mca_spml_mkey_t *) calloc(1, mca_spml_yoda.n_btls * sizeof(*mkeys)); if (!mkeys) { return NULL ; } proc_self = oshmem_proc_group_find(oshmem_group_all, oshmem_my_proc_id()); /* create convertor */ OBJ_CONSTRUCT(&convertor, opal_convertor_t); mca_bml.bml_register( MCA_SPML_YODA_PUT, mca_yoda_put_callback, NULL ); mca_bml.bml_register( MCA_SPML_YODA_GET, mca_yoda_get_callback, NULL ); mca_bml.bml_register( MCA_SPML_YODA_GET_RESPONSE, mca_yoda_get_response_callback, NULL ); /* Register proc memory in every rdma BTL. */ for (i = 0; i < mca_spml_yoda.n_btls; i++) { ybtl = &mca_spml_yoda.btl_type_map[i]; mkeys[i].va_base = addr; if (!ybtl->use_cnt) { SPML_VERBOSE(10, "%s: present but not in use. SKIP registration", btl_type2str(ybtl->btl_type)); continue; } /* If we have shared memory just save its id*/ if (YODA_BTL_SM == ybtl->btl_type && MEMHEAP_SHM_INVALID != (int) MEMHEAP_SHM_GET_ID(shmid)) { mkeys[i].u.key = shmid; mkeys[i].va_base = 0; continue; } yoda_context = calloc(1, sizeof(*yoda_context)); mkeys[i].spml_context = yoda_context; yoda_context->registration = NULL; if (NULL != ybtl->btl->btl_prepare_src) { /* initialize convertor for source descriptor*/ opal_convertor_copy_and_prepare_for_recv(proc_self->proc_convertor, datatype, size, addr, 0, &convertor); if (NULL != ybtl->btl->btl_mpool && NULL != ybtl->btl->btl_mpool->mpool_register) { iov.iov_len = size; iov.iov_base = NULL; opal_convertor_pack(&convertor, &iov, &iov_count, &size); ybtl->btl->btl_mpool->mpool_register(ybtl->btl->btl_mpool, iov.iov_base, size, 0, &yoda_context->registration); } /* initialize convertor for source descriptor*/ opal_convertor_copy_and_prepare_for_recv(proc_self->proc_convertor, datatype, size, addr, 0, &convertor); /* register source memory */ des = ybtl->btl->btl_prepare_src(ybtl->btl, 0, yoda_context->registration, &convertor, MCA_BTL_NO_ORDER, 0, &size, 0); if (NULL == des) { SPML_ERROR("%s: failed to register source memory. ", btl_type2str(ybtl->btl_type)); } yoda_context->btl_src_descriptor = des; mkeys[i].u.data = des->des_src; mkeys[i].len = ybtl->btl->btl_seg_size; } SPML_VERBOSE(5, "rank %d btl %s address 0x%p len %llu shmid 0x%X|0x%X", oshmem_proc_local_proc->proc_name.vpid, btl_type2str(ybtl->btl_type), mkeys[i].va_base, (unsigned long long)size, MEMHEAP_SHM_GET_TYPE(shmid), MEMHEAP_SHM_GET_ID(shmid)); } OBJ_DESTRUCT(&convertor); *count = mca_spml_yoda.n_btls; return mkeys; }