027e7deb7f
This commit was SVN r29164.
718 строки
20 KiB
C
718 строки
20 KiB
C
/* Copyright (c) 2013 Mellanox Technologies, Inc.
|
|
* All rights reserved.
|
|
* $COPYRIGHT$
|
|
*
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*/
|
|
|
|
#include "oshmem_config.h"
|
|
#include "oshmem/proc/proc.h"
|
|
#include "oshmem/mca/spml/spml.h"
|
|
#include "oshmem/mca/memheap/memheap.h"
|
|
#include "oshmem/mca/memheap/buddy/memheap_buddy.h"
|
|
#include "oshmem/mca/memheap/buddy/memheap_buddy_component.h"
|
|
#include "oshmem/mca/memheap/base/base.h"
|
|
#include "orte/mca/grpcomm/grpcomm.h"
|
|
#include "opal/class/opal_hash_table.h"
|
|
#include "opal/class/opal_object.h"
|
|
#include "orte/util/name_fns.h"
|
|
|
|
static int buddy_init(mca_memheap_buddy_module_t* buddy);
|
|
|
|
mca_memheap_buddy_module_t memheap_buddy = {
|
|
{
|
|
&mca_memheap_buddy_component,
|
|
mca_memheap_buddy_finalize,
|
|
mca_memheap_buddy_alloc,
|
|
mca_memheap_buddy_align,
|
|
mca_memheap_buddy_realloc,
|
|
mca_memheap_buddy_free,
|
|
|
|
mca_memheap_buddy_private_alloc,
|
|
mca_memheap_buddy_private_free,
|
|
|
|
mca_memheap_base_get_cached_mkey,
|
|
mca_memheap_base_get_mkey,
|
|
mca_memheap_base_find_offset,
|
|
mca_memheap_base_is_symmetric_addr,
|
|
mca_memheap_modex_recv_all,
|
|
|
|
0
|
|
},
|
|
1 /* priority */
|
|
};
|
|
|
|
/* Memory Heap Buddy Implementation */
|
|
|
|
/* Static inline functions */
|
|
static inline unsigned int bits_per_long(void)
|
|
{
|
|
return BITS_PER_BYTE * sizeof(unsigned long);
|
|
}
|
|
|
|
static inline void bitmap_zero(unsigned long *dst, unsigned long nbits)
|
|
{
|
|
unsigned long len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
|
|
memset(dst, 0, len);
|
|
}
|
|
|
|
/*
|
|
* WARNING: Non atomic version.
|
|
*/
|
|
static inline void __clear_bit(unsigned long nr, volatile void * addr)
|
|
{
|
|
int *m = ((int *) addr) + (nr >> 5);
|
|
*m &= ~(1 << (nr & 31));
|
|
}
|
|
|
|
/*
|
|
* WARNING: non atomic version.
|
|
*/
|
|
static inline void __set_bit(unsigned long nr, volatile void * addr)
|
|
{
|
|
int *m = ((int *) addr) + (nr >> 5);
|
|
*m |= 1 << (nr & 31);
|
|
}
|
|
|
|
static inline int test_bit(int nr, const volatile void * addr)
|
|
{
|
|
return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL;
|
|
}
|
|
|
|
/*
|
|
* __ffs - find first bit in word.
|
|
* @word: The word to search
|
|
*
|
|
* Undefined if no bit exists, so code should check against 0 first.
|
|
*/
|
|
static inline __opal_attribute_always_inline__ unsigned long __ffs(unsigned long word)
|
|
{
|
|
int num = 0;
|
|
#if __SIZEOF_LONG__ == 8
|
|
if ((word & 0xffffffff) == 0) {
|
|
num += 32;
|
|
word >>= 32;
|
|
}
|
|
#endif
|
|
|
|
if ((word & 0xffff) == 0) {
|
|
num += 16;
|
|
word >>= 16;
|
|
}
|
|
if ((word & 0xff) == 0) {
|
|
num += 8;
|
|
word >>= 8;
|
|
}
|
|
if ((word & 0xf) == 0) {
|
|
num += 4;
|
|
word >>= 4;
|
|
}
|
|
if ((word & 0x3) == 0) {
|
|
num += 2;
|
|
word >>= 2;
|
|
}
|
|
if ((word & 0x1) == 0)
|
|
num += 1;
|
|
return num;
|
|
}
|
|
|
|
/* round up to next power of two */
|
|
static inline unsigned memheap_buddy_find_order(unsigned long size)
|
|
{
|
|
unsigned order;
|
|
|
|
if (size & (size - 1))
|
|
order = 1;
|
|
else
|
|
order = 0;
|
|
|
|
while (size >>= 1) {
|
|
order++;
|
|
}
|
|
return order;
|
|
}
|
|
|
|
/*
|
|
* find the first set bit in a memory region
|
|
* @addr: The address to base the search on
|
|
* @offset: The bitnumber to start searching at
|
|
* @size: The maximum size to search
|
|
*/
|
|
|
|
static inline unsigned long find_next_bit(const unsigned long *addr,
|
|
unsigned long size,
|
|
unsigned long offset)
|
|
{
|
|
const unsigned long *p = addr + BITOP_WORD(offset);
|
|
unsigned long result = offset & ~(bits_per_long() - 1);
|
|
unsigned long tmp;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
size -= result;
|
|
offset %= bits_per_long();
|
|
if (offset) {
|
|
tmp = *(p++);
|
|
tmp &= (~0UL << offset);
|
|
if (size < bits_per_long())
|
|
goto found_first;
|
|
if (tmp)
|
|
goto found_middle;
|
|
size -= bits_per_long();
|
|
result += bits_per_long();
|
|
}
|
|
while (size & ~(bits_per_long() - 1)) {
|
|
if ((tmp = *(p++)))
|
|
goto found_middle;
|
|
result += bits_per_long();
|
|
size -= bits_per_long();
|
|
}
|
|
if (!size)
|
|
return result;
|
|
tmp = *p;
|
|
|
|
found_first: tmp &= (~0UL >> (bits_per_long() - size));
|
|
if (tmp == 0UL) /* Are any bits set? */
|
|
return result + size; /* Nope. */
|
|
found_middle: return result + __ffs(tmp);
|
|
}
|
|
|
|
/**
|
|
* Initialize the Memory Heap
|
|
*/
|
|
int mca_memheap_buddy_module_init(memheap_context_t *context)
|
|
{
|
|
if (!context || !context->user_size || !context->private_size) {
|
|
return OSHMEM_ERR_BAD_PARAM;
|
|
}
|
|
|
|
/* Construct a mutex object */
|
|
OBJ_CONSTRUCT(&memheap_buddy.lock, opal_mutex_t);
|
|
|
|
memheap_buddy.heap.max_order = memheap_log2(context->user_size);
|
|
memheap_buddy.heap.min_order = MEMHEAP_BASE_MIN_ORDER;
|
|
memheap_buddy.private_heap.max_order = memheap_log2(context->private_size);
|
|
memheap_buddy.private_heap.min_order = MEMHEAP_BASE_MIN_ORDER;
|
|
|
|
if (context->user_size != (1ULL << memheap_buddy.heap.max_order)) {
|
|
MEMHEAP_VERBOSE(1,
|
|
"Memheap rounded to the nearest power of two: requested %llu bytes, allocated %llu bytes",
|
|
(unsigned long long)context->user_size, 1ULL << memheap_buddy.heap.max_order);
|
|
}
|
|
|
|
assert(context->private_size == (1ULL << memheap_buddy.private_heap.max_order));
|
|
|
|
memheap_buddy.heap.symmetric_heap = context->user_base_addr;
|
|
memheap_buddy.private_heap.symmetric_heap = context->private_base_addr;
|
|
|
|
memheap_buddy.super.memheap_size = (1ULL << memheap_buddy.heap.max_order);
|
|
|
|
MEMHEAP_VERBOSE(1,
|
|
"symmetric heap memory (user+private): %llu bytes",
|
|
(unsigned long long)(context->user_size + context->private_size));
|
|
|
|
/* Initialize buddy allocator */
|
|
if (OSHMEM_SUCCESS != buddy_init(&memheap_buddy)) {
|
|
MEMHEAP_ERROR("Failed to setup MEMHEAP buddy allocator");
|
|
goto err;
|
|
}
|
|
|
|
return OSHMEM_SUCCESS;
|
|
|
|
err: mca_memheap_buddy_finalize();
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
static int buddy_init(mca_memheap_buddy_module_t* buddy)
|
|
{
|
|
unsigned long long total_size;
|
|
unsigned i;
|
|
unsigned long long s;
|
|
|
|
/* Allocate and init Hashtable */
|
|
memheap_buddy.heap.symmetric_heap_hashtable = OBJ_NEW(opal_hash_table_t);
|
|
if (NULL == memheap_buddy.heap.symmetric_heap_hashtable) {
|
|
MEMHEAP_ERROR("Opal failed to allocate hashtable object");
|
|
goto err;
|
|
}
|
|
memheap_buddy.private_heap.symmetric_heap_hashtable =
|
|
OBJ_NEW(opal_hash_table_t);
|
|
if (NULL == memheap_buddy.private_heap.symmetric_heap_hashtable) {
|
|
MEMHEAP_ERROR("Opal failed to allocate hashtable object");
|
|
goto err;
|
|
}
|
|
|
|
opal_hash_table_init(memheap_buddy.heap.symmetric_heap_hashtable,
|
|
DEFAULT_HASHTABLE_SIZE);
|
|
opal_hash_table_init(memheap_buddy.private_heap.symmetric_heap_hashtable,
|
|
DEFAULT_HASHTABLE_SIZE);
|
|
/* Init Buddy Allocator */
|
|
buddy->heap.bits = (unsigned long**) calloc((buddy->heap.max_order + 1),
|
|
sizeof(unsigned long *));
|
|
buddy->private_heap.bits =
|
|
(unsigned long**) calloc((buddy->private_heap.max_order + 1),
|
|
sizeof(unsigned long *));
|
|
buddy->heap.num_free = (unsigned int*) calloc((buddy->heap.max_order + 1),
|
|
sizeof(unsigned int));
|
|
buddy->private_heap.num_free =
|
|
(unsigned int*) calloc((buddy->private_heap.max_order + 1),
|
|
sizeof(unsigned int));
|
|
if ((NULL == buddy->heap.bits) || (NULL == buddy->heap.num_free)
|
|
|| (NULL == buddy->private_heap.bits)
|
|
|| (NULL == buddy->private_heap.num_free)) {
|
|
|
|
MEMHEAP_ERROR("Failed to allocate buddy allocator");
|
|
goto err;
|
|
}
|
|
|
|
total_size = 0;
|
|
for (i = buddy->heap.min_order; i <= buddy->heap.max_order; ++i) {
|
|
s = BITS_TO_LONGS(1UL << (buddy->heap.max_order - i));
|
|
MEMHEAP_VERBOSE(20,
|
|
"%d: (order=%d) allocating %llu longs (sizeof long = %d)",
|
|
i, buddy->heap.max_order, s, (int)sizeof(unsigned long));
|
|
total_size += s * sizeof(unsigned long);
|
|
buddy->heap.bits[i] = (unsigned long*) malloc(s
|
|
* sizeof(unsigned long));
|
|
if (NULL == buddy->heap.bits[i]) {
|
|
MEMHEAP_ERROR("Failed to allocate buddy->allocator");
|
|
goto err;
|
|
}
|
|
bitmap_zero(buddy->heap.bits[i], 1UL << (buddy->heap.max_order - i));
|
|
}
|
|
MEMHEAP_VERBOSE(5, "MEMHEAP metadata size = %llu bytes", total_size);
|
|
|
|
total_size = 0;
|
|
for (i = buddy->private_heap.min_order; i <= buddy->private_heap.max_order;
|
|
++i) {
|
|
s = BITS_TO_LONGS(1UL << (buddy->private_heap.max_order - i));
|
|
MEMHEAP_VERBOSE(20,
|
|
"%d: (order=%d) allocating %llu longs (sizeof long = %d)",
|
|
i, buddy->private_heap.max_order, s, (int)sizeof(unsigned long));
|
|
total_size += s * sizeof(unsigned long);
|
|
buddy->private_heap.bits[i] = (unsigned long*) malloc(s
|
|
* sizeof(unsigned long));
|
|
if (NULL == buddy->private_heap.bits[i]) {
|
|
MEMHEAP_ERROR("Failed to allocate buddy->allocator");
|
|
goto err;
|
|
}
|
|
bitmap_zero(buddy->private_heap.bits[i],
|
|
1UL << (buddy->private_heap.max_order - i));
|
|
}
|
|
MEMHEAP_VERBOSE(5,
|
|
"private MEMHEAP metadata size = %llu bytes",
|
|
total_size);
|
|
|
|
set_bit(0, buddy->heap.bits[buddy->heap.max_order]);
|
|
set_bit(0, buddy->private_heap.bits[buddy->private_heap.max_order]);
|
|
buddy->heap.num_free[buddy->heap.max_order] = 1;
|
|
buddy->private_heap.num_free[buddy->private_heap.max_order] = 1;
|
|
|
|
return OSHMEM_SUCCESS;
|
|
|
|
err: return OSHMEM_ERROR;
|
|
}
|
|
|
|
static int buddy_cleanup(mca_memheap_buddy_module_t* buddy)
|
|
{
|
|
unsigned int i;
|
|
|
|
MEMHEAP_VERBOSE(5, "buddy cleanup");
|
|
if (NULL == buddy) {
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
for (i = 0; i <= buddy->heap.max_order; ++i) {
|
|
if (NULL != buddy->heap.bits && NULL != buddy->heap.bits[i]) {
|
|
free(buddy->heap.bits[i]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i <= buddy->private_heap.max_order; ++i) {
|
|
if (NULL != buddy->private_heap.bits
|
|
&& NULL != buddy->private_heap.bits[i]) {
|
|
free(buddy->private_heap.bits[i]);
|
|
}
|
|
}
|
|
|
|
if (NULL != buddy->heap.bits) {
|
|
free(buddy->heap.bits);
|
|
}
|
|
if (NULL != buddy->heap.num_free) {
|
|
free(buddy->heap.num_free);
|
|
}
|
|
|
|
if (NULL != buddy->private_heap.bits) {
|
|
free(buddy->private_heap.bits);
|
|
}
|
|
if (NULL != buddy->private_heap.num_free) {
|
|
free(buddy->private_heap.num_free);
|
|
}
|
|
|
|
OBJ_DESTRUCT(&buddy->lock);
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
static int _buddy_alloc(unsigned order,
|
|
uint32_t* seg,
|
|
mca_memheap_buddy_heap_t *heap)
|
|
{
|
|
uint32_t o;
|
|
uint32_t m;
|
|
|
|
MEMHEAP_VERBOSE(20, "order=%d size=%d", order, 1<<order);
|
|
OPAL_THREAD_LOCK(&memheap_buddy.lock);
|
|
for (o = order; o <= heap->max_order; ++o) {
|
|
if (heap->num_free[o]) {
|
|
m = 1 << (heap->max_order - o);
|
|
*seg = find_first_bit(heap->bits[o], m);
|
|
MEMHEAP_VERBOSE(20,
|
|
"found free bit: order=%d, bits=0x%lx m=%d, *seg=%d",
|
|
o, heap->bits[o][0], m, *seg);
|
|
if (*seg < m)
|
|
goto found;
|
|
}
|
|
}
|
|
|
|
OPAL_THREAD_UNLOCK(&memheap_buddy.lock);
|
|
return OSHMEM_ERROR;
|
|
|
|
found:
|
|
clear_bit(*seg, heap->bits[o]);
|
|
--(heap->num_free[o]);
|
|
|
|
while (o > order) {
|
|
--o;
|
|
*seg <<= 1;
|
|
set_bit(*seg ^ 1, heap->bits[o]);
|
|
++(heap->num_free[o]);
|
|
}
|
|
|
|
OPAL_THREAD_UNLOCK(&memheap_buddy.lock);
|
|
*seg <<= order;
|
|
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
static int _buddy_free(mca_memheap_buddy_module_t* buddy,
|
|
uint32_t seg,
|
|
unsigned order,
|
|
mca_memheap_buddy_heap_t *heap)
|
|
{
|
|
MEMHEAP_VERBOSE(20, "order=%d size=%d seg=%d", order, 1<<order, seg);
|
|
seg >>= order;
|
|
OPAL_THREAD_LOCK(&buddy->lock);
|
|
|
|
while (test_bit(seg ^ 1, heap->bits[order])) {
|
|
clear_bit(seg ^ 1, heap->bits[order]);
|
|
--(heap->num_free[order]);
|
|
seg >>= 1;
|
|
++order;
|
|
}
|
|
|
|
set_bit(seg, heap->bits[order]);
|
|
++(heap->num_free[order]);
|
|
OPAL_THREAD_UNLOCK(&buddy->lock);
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
static int buddy_free(mca_memheap_buddy_module_t* buddy,
|
|
uint32_t seg,
|
|
unsigned order)
|
|
{
|
|
return _buddy_free(buddy, seg, order, &buddy->heap);
|
|
}
|
|
|
|
static int buddy_private_free(mca_memheap_buddy_module_t* buddy,
|
|
uint32_t seg,
|
|
unsigned order)
|
|
{
|
|
return _buddy_free(buddy, seg, order, &buddy->private_heap);
|
|
}
|
|
|
|
static int _do_alloc(uint32_t order,
|
|
void **p_buff,
|
|
mca_memheap_buddy_heap_t *heap)
|
|
{
|
|
int rc;
|
|
unsigned long base;
|
|
uint32_t offset;
|
|
unsigned long addr;
|
|
|
|
if (order < heap->min_order)
|
|
order = heap->min_order;
|
|
|
|
*p_buff = 0;
|
|
if (order > heap->max_order) {
|
|
/* Test allocated size overflow */
|
|
MEMHEAP_VERBOSE(5, "Allocation overflow of symmetric heap size");
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
base = (unsigned long) heap->symmetric_heap;
|
|
|
|
if (OSHMEM_SUCCESS != _buddy_alloc(order, &offset, heap)) {
|
|
MEMHEAP_VERBOSE(5, "Buddy Allocator failed to return a base address");
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
/* Save the order of the allocated variable */
|
|
addr = base + offset;
|
|
|
|
rc = opal_hash_table_set_value_uint64(heap->symmetric_heap_hashtable,
|
|
addr,
|
|
(void *) (unsigned long) order);
|
|
|
|
if (OPAL_SUCCESS != rc) {
|
|
MEMHEAP_VERBOSE(5, "Failed to insert order to hashtable");
|
|
goto alloc_error;
|
|
}
|
|
|
|
*p_buff = (void*) addr;
|
|
/* no barrier because it is not required by spec! */
|
|
return OSHMEM_SUCCESS;
|
|
|
|
alloc_error: _buddy_free(&memheap_buddy, offset, order, heap);
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
static int do_alloc(uint32_t order, void **p_buff)
|
|
{
|
|
return _do_alloc(order, p_buff, &(memheap_buddy.heap));
|
|
}
|
|
|
|
static int do_private_alloc(uint32_t order, void **p_buff)
|
|
{
|
|
return _do_alloc(order, p_buff, &(memheap_buddy.private_heap));
|
|
}
|
|
|
|
/**
|
|
* Allocate size bytes on the symmetric heap.
|
|
* The allocated variable is aligned to its size.
|
|
*/
|
|
int mca_memheap_buddy_alloc(size_t size, void** p_buff)
|
|
{
|
|
|
|
uint32_t order;
|
|
|
|
order = memheap_buddy_find_order(size);
|
|
|
|
return do_alloc(order, p_buff);
|
|
}
|
|
|
|
int mca_memheap_buddy_private_alloc(size_t size, void** p_buff)
|
|
{
|
|
uint32_t order;
|
|
int status = 0;
|
|
order = memheap_buddy_find_order(size);
|
|
|
|
status = do_private_alloc(order, p_buff);
|
|
|
|
MEMHEAP_VERBOSE(20, "private alloc addr: %p", *p_buff);
|
|
|
|
return status;
|
|
}
|
|
|
|
int mca_memheap_buddy_private_free(void* ptr)
|
|
{
|
|
int rc;
|
|
uint32_t offset;
|
|
unsigned long addr;
|
|
unsigned long base;
|
|
void *order;
|
|
|
|
if (0 == ptr) {
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
base = (unsigned long) memheap_buddy.private_heap.symmetric_heap;
|
|
addr = (unsigned long) ptr;
|
|
offset = addr - base;
|
|
|
|
rc =
|
|
opal_hash_table_get_value_uint64(memheap_buddy.private_heap.symmetric_heap_hashtable,
|
|
addr,
|
|
&order);
|
|
if (OPAL_SUCCESS != rc) {
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
buddy_private_free(&memheap_buddy,
|
|
offset,
|
|
(unsigned) (unsigned long) order);
|
|
opal_hash_table_remove_value_uint64(memheap_buddy.private_heap.symmetric_heap_hashtable,
|
|
addr);
|
|
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
int mca_memheap_buddy_align(size_t align, size_t size, void **p_buff)
|
|
{
|
|
uint32_t order;
|
|
|
|
if (align == 0) {
|
|
*p_buff = 0;
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
/* check that align is power of 2 */
|
|
if (align & (align - 1)) {
|
|
*p_buff = 0;
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
order = memheap_buddy_find_order(size);
|
|
if ((unsigned long) align > (1UL << order))
|
|
order = memheap_buddy_find_order(align);
|
|
|
|
return do_alloc(order, p_buff);
|
|
}
|
|
|
|
int mca_memheap_buddy_realloc(size_t new_size, void *p_buff, void **p_new_buff)
|
|
{
|
|
int rc;
|
|
unsigned long addr;
|
|
void *order;
|
|
size_t old_size;
|
|
char *tmp_buf;
|
|
|
|
/* equiv to alloc if old ptr is null */
|
|
if (NULL == p_buff)
|
|
return mca_memheap_buddy_alloc(new_size, p_new_buff);
|
|
|
|
addr = (unsigned long) p_buff;
|
|
|
|
rc =
|
|
opal_hash_table_get_value_uint64(memheap_buddy.heap.symmetric_heap_hashtable,
|
|
addr,
|
|
&order);
|
|
if (OPAL_SUCCESS != rc) {
|
|
*p_new_buff = NULL;
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
/* equiv to free if new_size is 0 */
|
|
if (0 == new_size) {
|
|
*p_new_buff = NULL;
|
|
return mca_memheap_buddy_free(p_buff);
|
|
}
|
|
|
|
old_size = 1UL << (unsigned long) order;
|
|
|
|
/* do nothing if new size is less then current size */
|
|
if (new_size <= old_size) {
|
|
*p_new_buff = p_buff;
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
if (new_size > (1UL << memheap_buddy.heap.max_order)) {
|
|
*p_new_buff = NULL;
|
|
return OSHMEM_ERR_OUT_OF_RESOURCE;
|
|
}
|
|
|
|
if (old_size + new_size >= (1UL << memheap_buddy.heap.max_order)) {
|
|
/* copy via temporary buffer */
|
|
|
|
tmp_buf = (char *) malloc(old_size);
|
|
if (!tmp_buf)
|
|
return OSHMEM_ERR_OUT_OF_RESOURCE;
|
|
memcpy(tmp_buf, p_buff, old_size);
|
|
mca_memheap_buddy_free(p_buff);
|
|
} else
|
|
tmp_buf = p_buff;
|
|
|
|
/* alloc and copy data to new buffer, free old one */
|
|
rc = mca_memheap_buddy_alloc(new_size, p_new_buff);
|
|
if (OSHMEM_SUCCESS != rc) {
|
|
*p_new_buff = NULL;
|
|
if (old_size + new_size >= (1UL << memheap_buddy.heap.max_order)
|
|
&& tmp_buf) {
|
|
free(tmp_buf);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
memcpy(*p_new_buff, tmp_buf, old_size);
|
|
|
|
if (old_size + new_size < (1UL << memheap_buddy.heap.max_order))
|
|
mca_memheap_buddy_free(p_buff);
|
|
else if (tmp_buf)
|
|
free(tmp_buf);
|
|
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Free a variable allocated on the
|
|
* symmetric heap.
|
|
*/
|
|
int mca_memheap_buddy_free(void* ptr)
|
|
{
|
|
int rc;
|
|
uint32_t offset;
|
|
unsigned long addr;
|
|
unsigned long base;
|
|
void *order;
|
|
|
|
base = (unsigned long) memheap_buddy.heap.symmetric_heap;
|
|
addr = (unsigned long) ptr;
|
|
offset = addr - base;
|
|
|
|
rc =
|
|
opal_hash_table_get_value_uint64(memheap_buddy.heap.symmetric_heap_hashtable,
|
|
addr,
|
|
&order);
|
|
if (OPAL_SUCCESS != rc) {
|
|
return OSHMEM_ERROR;
|
|
}
|
|
|
|
buddy_free(&memheap_buddy, offset, (unsigned) (unsigned long) order);
|
|
opal_hash_table_remove_value_uint64(memheap_buddy.heap.symmetric_heap_hashtable,
|
|
addr);
|
|
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
int mca_memheap_buddy_finalize()
|
|
{
|
|
MEMHEAP_VERBOSE(5, "deregistering symmetric heap");
|
|
|
|
/* was not initialized - do nothing */
|
|
if (memheap_buddy.heap.max_order == 0)
|
|
return OSHMEM_SUCCESS;
|
|
|
|
/* Destruct hashtable supporting shfree of symmetric heap variables */
|
|
if (memheap_buddy.heap.symmetric_heap_hashtable) {
|
|
OBJ_RELEASE(memheap_buddy.heap.symmetric_heap_hashtable);
|
|
}
|
|
if (memheap_buddy.private_heap.symmetric_heap_hashtable) {
|
|
OBJ_RELEASE(memheap_buddy.private_heap.symmetric_heap_hashtable);
|
|
}
|
|
|
|
buddy_cleanup(&memheap_buddy);
|
|
|
|
return OSHMEM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Return the base address of the symmetric heap.
|
|
*/
|
|
|
|
static inline void* mca_memheap_buddy_get_symmetric_heap_base_addr(void)
|
|
{
|
|
return memheap_buddy.heap.symmetric_heap;
|
|
}
|
|
|
|
/**
|
|
* Return the last address in the symmetric heap.
|
|
*/
|
|
static inline void* mca_memheap_buddy_get_symmetric_heap_last_addr(void)
|
|
{
|
|
return (void*) ((unsigned char*) (memheap_buddy.heap.symmetric_heap)
|
|
+ (1ULL << memheap_buddy.heap.max_order)
|
|
+ (1ULL << memheap_buddy.private_heap.max_order));
|
|
}
|
|
|