/* * Copyright (c) 2013 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file */ #ifndef MCA_MEMHEAP_BASE_H #define MCA_MEMHEAP_BASE_H #include "oshmem_config.h" #include "opal/class/opal_list.h" #include "opal/class/opal_value_array.h" #include "oshmem/mca/mca.h" #include "oshmem/mca/memheap/memheap.h" BEGIN_C_DECLS /* * Global functions for MCA: overall MEMHEAP open and close */ OSHMEM_DECLSPEC int mca_memheap_base_select(void); /* * Globals */ /* only used within base -- no need to DECLSPEC */ #define MEMHEAP_BASE_MIN_ORDER 3 /* forces 64 bit alignment */ #define MEMHEAP_BASE_PAGE_ORDER 21 #define MEMHEAP_BASE_PRIVATE_SIZE (1ULL << MEMHEAP_BASE_PAGE_ORDER) /* should be at least the same as a huge page size */ #define MEMHEAP_BASE_MIN_SIZE (1ULL << MEMHEAP_BASE_PAGE_ORDER) /* must fit into at least one huge page */ extern int mca_memheap_base_already_opened; extern int mca_memheap_base_key_exchange; extern int mca_memheap_num_segments_warn; #define HEAP_SEG_INDEX 0 #define MCA_MEMHEAP_SEG_COUNT 2 #define MEMHEAP_SEG_INVALID 0xFFFF typedef struct mca_memheap_base_config { long device_nic_mem_seg_size; /* Used for SHMEM_HINT_DEVICE_NIC_MEM */ } mca_memheap_base_config_t; typedef struct mca_memheap_map { map_segment_t *mem_segs; int n_segments; int capacity; int num_transports; } mca_memheap_map_t; extern mca_memheap_map_t mca_memheap_base_map; extern mca_memheap_base_config_t mca_memheap_base_config; int mca_memheap_base_alloc_init(mca_memheap_map_t *, size_t, long, char *); void mca_memheap_base_alloc_exit(mca_memheap_map_t *); int mca_memheap_base_static_init(mca_memheap_map_t *); void mca_memheap_base_static_exit(mca_memheap_map_t *); int mca_memheap_base_reg(mca_memheap_map_t *); int mca_memheap_base_dereg(mca_memheap_map_t *); int memheap_oob_init(mca_memheap_map_t *); void memheap_oob_destruct(void); map_segment_t *mca_memheap_base_allocate_segment(mca_memheap_map_t *map); OSHMEM_DECLSPEC int mca_memheap_base_is_symmetric_addr(const void* va); OSHMEM_DECLSPEC sshmem_mkey_t *mca_memheap_base_get_mkey(void* va, int tr_id); OSHMEM_DECLSPEC sshmem_mkey_t * mca_memheap_base_get_cached_mkey_slow(shmem_ctx_t ctx, map_segment_t *s, int pe, void* va, int btl_id, void** rva); OSHMEM_DECLSPEC void mca_memheap_modex_recv_all(void); /* This function is for internal usage only * return value: * 0 - addr is not symmetric address * 1 - addr is part of user memheap * 2 - addr is part of private memheap * 3 - addr is static variable */ typedef enum { ADDR_INVALID = 0, ADDR_USER, ADDR_PRIVATE, ADDR_STATIC, } addr_type_t; OSHMEM_DECLSPEC int mca_memheap_base_detect_addr_type(void* va); static inline unsigned memheap_log2(unsigned long long val) { /* add 1 if val is NOT a power of 2 (to do the ceil) */ unsigned int count = (val & (val - 1) ? 1 : 0); while (val > 0) { val = val >> 1; count++; } return count > 0 ? count - 1 : 0; } static inline void *memheap_down_align_addr(void* addr, unsigned int shift) { return (void*) (((intptr_t) addr) & (~(intptr_t) 0) << shift); } static inline void *memheap_up_align_addr(void*addr, unsigned int shift) { return (void*) ((((intptr_t) addr) | ~((~(intptr_t) 0) << shift))); } static inline unsigned long long memheap_align(unsigned long top) { return ((top + MEMHEAP_BASE_MIN_SIZE - 1) & ~(MEMHEAP_BASE_MIN_SIZE - 1)); } /* * MCA framework */ OSHMEM_DECLSPEC extern mca_base_framework_t oshmem_memheap_base_framework; /* ******************************************************************** */ #ifdef __BASE_FILE__ #define __SPML_FILE__ __BASE_FILE__ #else #define __SPML_FILE__ __FILE__ #endif #ifdef OPAL_ENABLE_DEBUG #define MEMHEAP_VERBOSE(level, ...) \ oshmem_output_verbose(level, oshmem_memheap_base_framework.framework_output, \ "%s:%d - %s()", __SPML_FILE__, __LINE__, __func__, __VA_ARGS__) #else #define MEMHEAP_VERBOSE(level, ...) #endif #define MEMHEAP_ERROR(...) \ oshmem_output(oshmem_memheap_base_framework.framework_output, \ "Error %s:%d - %s()", __SPML_FILE__, __LINE__, __func__, __VA_ARGS__) #define MEMHEAP_WARN(...) \ oshmem_output_verbose(0, oshmem_memheap_base_framework.framework_output, \ "Warning %s:%d - %s()", __SPML_FILE__, __LINE__, __func__, __VA_ARGS__) extern int mca_memheap_seg_cmp(const void *k, const void *v); /* Turn ON/OFF debug output from build (default 0) */ #ifndef MEMHEAP_BASE_DEBUG #define MEMHEAP_BASE_DEBUG 0 #endif #define MEMHEAP_VERBOSE_FASTPATH(...) extern mca_memheap_map_t* memheap_map; static inline int map_segment_is_va_in(map_base_segment_t *s, void *va) { return (va >= s->va_base && va < s->va_end); } static inline map_segment_t *memheap_find_seg(int segno) { return &mca_memheap_base_map.mem_segs[segno]; } static inline int memheap_is_va_in_segment(void *va, int segno) { return map_segment_is_va_in(&memheap_find_seg(segno)->super, va); } static inline int memheap_find_segnum(void *va, int pe) { int i; int my_pe = oshmem_my_proc_id(); if (pe == my_pe) { /* Find segment number for local segment using va_base * TODO: Merge local and remote segment information in mkeys_cache */ for (i = 0; i < mca_memheap_base_map.n_segments; i++) { if (memheap_is_va_in_segment(va, i)) { return i; } } } else { /* Find segment number for remote segments using va_base */ for (i = 0; i < mca_memheap_base_map.n_segments; i++) { map_segment_t *seg = memheap_find_seg(i); if (seg) { sshmem_mkey_t **mkeys_cache = seg->mkeys_cache; if (mkeys_cache) { if (mkeys_cache[pe]) { if ((va >= mkeys_cache[pe]->va_base) && ((char*)va < (char*)mkeys_cache[pe]->va_base + mkeys_cache[pe]->len)) { return i; } } } } } } return MEMHEAP_SEG_INVALID; } static inline void* memheap_va2rva(void* va, void* local_base, void* remote_base) { return (void*) (remote_base > local_base ? (uintptr_t)va + ((uintptr_t)remote_base - (uintptr_t)local_base) : (uintptr_t)va - ((uintptr_t)local_base - (uintptr_t)remote_base)); } static inline void *map_segment_va2rva(mkey_segment_t *seg, void *va) { return memheap_va2rva(va, seg->super.va_base, seg->rva_base); } void mkey_segment_init(mkey_segment_t *seg, sshmem_mkey_t *mkey, uint32_t segno); static inline map_segment_t *memheap_find_va(void* va) { map_segment_t *s = NULL; int i; for (i = 0; i < memheap_map->n_segments; i++) { if (memheap_is_va_in_segment(va, i)) { s = &memheap_map->mem_segs[i]; break; } } #if MEMHEAP_BASE_DEBUG == 1 if (s) { MEMHEAP_VERBOSE(5, "match seg#%02ld: 0x%llX - 0x%llX %llu bytes va=%p", s - memheap_map->mem_segs, (long long)s->super.va_base, (long long)s->super.va_end, (long long)(s->super.va_end - s->super.va_base), (void *)va); } #endif return s; } static inline sshmem_mkey_t *mca_memheap_base_get_cached_mkey(shmem_ctx_t ctx, int pe, void* va, int btl_id, void** rva) { map_segment_t *s; sshmem_mkey_t *mkey; MEMHEAP_VERBOSE_FASTPATH(10, "rkey: pe=%d va=%p", pe, va); s = memheap_find_va(va); if (OPAL_UNLIKELY(NULL == s)) return NULL ; if (OPAL_UNLIKELY(!MAP_SEGMENT_IS_VALID(s))) return NULL ; if (OPAL_UNLIKELY(pe == oshmem_my_proc_id())) { *rva = va; MEMHEAP_VERBOSE_FASTPATH(10, "rkey: pe=%d va=%p -> (local) %lx %p", pe, va, s->mkeys[btl_id].u.key, *rva); return &s->mkeys[btl_id]; } if (OPAL_LIKELY(s->mkeys_cache[pe])) { mkey = &s->mkeys_cache[pe][btl_id]; *rva = memheap_va2rva(va, s->super.va_base, mkey->va_base); MEMHEAP_VERBOSE_FASTPATH(10, "rkey: pe=%d va=%p -> (cached) %lx %p", pe, (void *)va, mkey->u.key, (void *)*rva); return mkey; } return mca_memheap_base_get_cached_mkey_slow(ctx, s, pe, va, btl_id, rva); } static inline int mca_memheap_base_num_transports(void) { return memheap_map->num_transports; } static inline void* mca_memheap_seg2base_va(int seg) { return memheap_map->mem_segs[seg].super.va_base; } END_C_DECLS #endif /* MCA_MEMHEAP_BASE_H */