
constructor and destructor hierarchy. Also changing lam_class_info_t --> lam_class_t for brevity. This commit was SVN r749.
541 строка
16 KiB
C
541 строка
16 KiB
C
/*
|
|
* $HEADER$
|
|
*/
|
|
|
|
#include "lam_config.h"
|
|
#include "lam/mem/free_lists.h"
|
|
#include "lam/runtime/runtime.h"
|
|
#include "lam/util/output.h"
|
|
#include "lam/os/numa.h"
|
|
#include "lam/os/lam_system.h"
|
|
#include "lam/mem/mem_globals.h"
|
|
|
|
#ifndef ROB_HASNT_FINISHED_THIS_YET
|
|
#define ROB_HASNT_FINISHED_THIS_YET 0
|
|
#endif
|
|
|
|
/* private list functions */
|
|
|
|
#if RB_HASNT_FINISHED_THIS_YET
|
|
static lam_list_item_t *lam_free_lists_request_elt(lam_free_lists_t *flist,
|
|
int pool_idx);
|
|
#endif
|
|
|
|
static void lam_free_lists_append(lam_free_lists_t *flist, void *chunk, int pool_idx);
|
|
|
|
static int lam_free_lists_create_more_elts(lam_free_lists_t *flist, int pool_idx);
|
|
|
|
static void *lam_free_lists_get_mem_chunk(lam_free_lists_t *flist, int index, size_t *len, int *err);
|
|
|
|
static int lam_free_lists_mem_pool_construct(lam_free_lists_t *flist, int nlists, long pages_per_list, ssize_t chunk_size,
|
|
size_t page_size, long min_pages_per_list,
|
|
long default_min_pages_per_list, long default_pages_per_list,
|
|
long max_pages_per_list, ssize_t max_mem_in_pool);
|
|
|
|
lam_class_t lam_free_lists_t_class = {
|
|
"lam_free_lists_t",
|
|
OBJ_CLASS(lam_object_t),
|
|
(lam_construct_t) lam_free_lists_construct,
|
|
(lam_destruct_t) lam_free_lists_destruct
|
|
};
|
|
|
|
|
|
void lam_free_lists_construct(lam_free_lists_t *flist)
|
|
{
|
|
lam_mutex_init(&flist->fl_lock);
|
|
flist->fl_pool = NULL;
|
|
flist->fl_elt_cls = NULL;
|
|
flist->fl_description = NULL;
|
|
flist->fl_free_lists = NULL;
|
|
flist->fl_is_shared = 0;
|
|
flist->fl_nlists = 0;
|
|
flist->fl_elt_per_chunk = 0;
|
|
flist->fl_elt_size = 0;
|
|
flist->fl_retry_more_resources = 0;
|
|
flist->fl_enforce_affinity = 0;
|
|
flist->fl_affinity = NULL;
|
|
flist->fl_threshold_grow = 0;
|
|
|
|
#if LAM_ENABLE_MEM_PROFILE
|
|
flist->fl_elt_out = NULL;
|
|
flist->fl_elt_max = NULL;
|
|
flist->fl_elt_sum = NULL;
|
|
flist->fl_nevents = NULL;
|
|
flist->fl_chunks_req = NULL;
|
|
flist->fl_chunks_returned = NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
void lam_free_lists_destruct(lam_free_lists_t *flist)
|
|
{
|
|
int i;
|
|
|
|
OBJ_RELEASE(flist->fl_pool);
|
|
for ( i = 0; i < flist->fl_nlists; i++ )
|
|
OBJ_RELEASE(flist->fl_free_lists[i]);
|
|
|
|
if ( flist->fl_affinity )
|
|
free(flist->fl_affinity);
|
|
|
|
#if LAM_ENABLE_MEM_PROFILE
|
|
if ( flist->fl_elt_out )
|
|
free(flist->fl_elt_out);
|
|
|
|
if ( flist->fl_elt_max )
|
|
free(flist->fl_elt_max);
|
|
|
|
if ( flist->fl_elt_sum )
|
|
free(flist->fl_elt_sum);
|
|
|
|
if ( flist->fl_nevents )
|
|
free(flist->fl_nevents);
|
|
|
|
if ( flist->fl_chunks_req )
|
|
free(flist->fl_chunks_req);
|
|
|
|
if ( flist->fl_chunks_returned )
|
|
free(flist->fl_chunks_returned);
|
|
#endif
|
|
}
|
|
|
|
|
|
int lam_free_lists_construct_with(
|
|
lam_free_lists_t *flist,
|
|
int nlists,
|
|
int pages_per_list,
|
|
size_t chunk_size,
|
|
size_t page_size,
|
|
size_t elt_size,
|
|
int min_pages_per_list,
|
|
int max_pages_per_list,
|
|
int max_consec_req_fail,
|
|
const char *description,
|
|
bool retry_for_more_resources,
|
|
lam_affinity_t *affinity,
|
|
bool enforce_affinity,
|
|
lam_mem_pool_t *mem_pool)
|
|
{
|
|
/* lam_free_lists_construct must have been called prior to calling this function */
|
|
size_t max_mem_in_pool;
|
|
size_t initial_mem_per_list;
|
|
long max_mem_per_list;
|
|
int list, pool;
|
|
int err = LAM_SUCCESS;
|
|
|
|
flist->fl_description = description;
|
|
flist->fl_nlists = nlists;
|
|
|
|
/* set up the memory pool */
|
|
if ( mem_pool )
|
|
{
|
|
flist->fl_pool = mem_pool;
|
|
OBJ_RETAIN(flist->fl_pool);
|
|
}
|
|
else
|
|
{
|
|
/* instantiate memory pool */
|
|
max_mem_in_pool = max_pages_per_list * page_size;
|
|
err = lam_free_lists_mem_pool_construct(
|
|
flist,
|
|
nlists,
|
|
pages_per_list,
|
|
chunk_size,
|
|
page_size,
|
|
min_pages_per_list,
|
|
min_pages_per_list,
|
|
pages_per_list,
|
|
max_pages_per_list,
|
|
max_mem_in_pool);
|
|
if (err != LAM_SUCCESS)
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
|
|
/* reset pool chunk size */
|
|
chunk_size = lam_mp_get_chunk_size(flist->fl_pool);
|
|
|
|
/* Number of elements per chunk */
|
|
flist->fl_elt_per_chunk = chunk_size / elt_size;
|
|
|
|
initial_mem_per_list = min_pages_per_list * page_size;
|
|
|
|
/* adjust initial_mem_per_list to increments of chunk_size */
|
|
if ( initial_mem_per_list < chunk_size )
|
|
{
|
|
min_pages_per_list = (((chunk_size - 1) / page_size) + 1);
|
|
initial_mem_per_list = min_pages_per_list * page_size;
|
|
}
|
|
|
|
/* determine upper limit on number of pages in a given list */
|
|
if ( (max_pages_per_list != -1) && (max_pages_per_list < min_pages_per_list) )
|
|
max_pages_per_list = min_pages_per_list;
|
|
|
|
if (max_pages_per_list == -1)
|
|
max_mem_per_list = -1;
|
|
else
|
|
max_mem_per_list = max_pages_per_list * page_size;
|
|
|
|
/* initialize empty lists of available descriptors */
|
|
flist->fl_free_lists = (lam_seg_list_t **)
|
|
malloc(sizeof(lam_seg_list_t *) *
|
|
flist->fl_nlists);
|
|
if ( !flist->fl_free_lists )
|
|
{
|
|
lam_abort(1, "Error: Out of memory");
|
|
}
|
|
|
|
/* run constructors */
|
|
for (list = 0; list < flist->fl_nlists; list++)
|
|
{
|
|
if ( flist->fl_is_shared )
|
|
{
|
|
/* process shared memory allocation */
|
|
flist->fl_free_lists[list] =
|
|
(lam_seg_list_t *)
|
|
lam_fmp_get_mem_segment(&lam_per_proc_shmem_pools,
|
|
sizeof(lam_seg_list_t), CACHE_ALIGNMENT, list);
|
|
}
|
|
else
|
|
{
|
|
/* process private memory allocation */
|
|
flist->fl_free_lists[list] =
|
|
(lam_seg_list_t *)malloc(sizeof(lam_seg_list_t));
|
|
}
|
|
|
|
if (!flist->fl_free_lists[list]) {
|
|
lam_abort(1, "Error: Out of memory");
|
|
}
|
|
|
|
OBJ_CONSTRUCT(&flist->fl_free_lists[list], lam_seg_list_t);
|
|
|
|
lam_sgl_set_min_bytes_pushed(flist->fl_free_lists[list],
|
|
initial_mem_per_list);
|
|
lam_sgl_set_max_bytes_pushed(flist->fl_free_lists[list],
|
|
max_mem_per_list);
|
|
lam_sgl_set_max_consec_fail(flist->fl_free_lists[list],
|
|
max_consec_req_fail);
|
|
} /* end list loop */
|
|
|
|
flist->fl_retry_more_resources = retry_for_more_resources;
|
|
flist->fl_enforce_affinity = enforce_affinity;
|
|
if ( enforce_affinity )
|
|
{
|
|
flist->fl_affinity = (affinity_t *)malloc(sizeof(affinity_t) *
|
|
flist->fl_nlists);
|
|
if ( !flist->fl_affinity ) {
|
|
lam_abort(1, "Error: Out of memory");
|
|
}
|
|
|
|
/* copy policies in */
|
|
for ( pool = 0; pool < flist->fl_nlists; pool++ )
|
|
{
|
|
flist->fl_affinity[pool] = affinity[pool];
|
|
}
|
|
}
|
|
|
|
|
|
/* initialize locks for memory pool and individual list and link locks */
|
|
for ( pool = 0; pool < flist->fl_nlists; pool++ ) {
|
|
|
|
/* gain exclusive use of list */
|
|
if ( 1 == lam_sgl_lock_list(flist->fl_free_lists[pool]) ) {
|
|
|
|
while ( lam_sgl_get_bytes_pushed(flist->fl_free_lists[pool])
|
|
< lam_sgl_get_min_bytes_pushed(flist->fl_free_lists[pool]) )
|
|
{
|
|
if (lam_free_lists_create_more_elts(flist, pool) != LAM_SUCCESS)
|
|
{
|
|
lam_abort(1, "Error: Setting up initial private "
|
|
"free list for %s.\n", flist->fl_description);
|
|
}
|
|
}
|
|
|
|
lam_sgl_unlock_list(flist->fl_free_lists[pool]);
|
|
}
|
|
else
|
|
{
|
|
/* only 1 process should be initializing the list */
|
|
lam_abort(1, "Error: Setting up initial private free "
|
|
"list %d for %s.\n", pool, flist->fl_description);
|
|
}
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
static int lam_free_lists_mem_pool_construct(lam_free_lists_t *flist,
|
|
int nlists, long pages_per_list, ssize_t chunk_size,
|
|
size_t page_size, long min_pages_per_list,
|
|
long default_min_pages_per_list, long default_pages_per_list,
|
|
long max_pages_per_list, ssize_t max_mem_in_pool)
|
|
{
|
|
int err = LAM_SUCCESS;
|
|
long total_pgs_to_alloc;
|
|
ssize_t mem_in_pool;
|
|
size_t to_alloc;
|
|
|
|
/* set chunksize - multiple of page size */
|
|
chunk_size =
|
|
((((chunk_size - 1) / page_size) + 1) * page_size);
|
|
|
|
/* determine number how much memory to allocate */
|
|
if ( pages_per_list == -1 ) {
|
|
/* minimum size is defaultNPagesPerList*number of local procs */
|
|
total_pgs_to_alloc = default_pages_per_list * nlists;
|
|
} else {
|
|
total_pgs_to_alloc = pages_per_list * nlists;
|
|
}
|
|
|
|
mem_in_pool = total_pgs_to_alloc * page_size;
|
|
|
|
/* Initialize memory pool */
|
|
if ( flist->fl_is_shared ) {
|
|
/* shared memory allocation */
|
|
to_alloc = sizeof(lam_mem_pool_t);
|
|
flist->fl_pool =
|
|
(lam_mem_pool_t *)lam_fmp_get_mem_segment(&lam_shmem_pools,
|
|
to_alloc,
|
|
CACHE_ALIGNMENT, 0);
|
|
if ( flist->fl_pool ) {
|
|
OBJ_CONSTRUCT(&flist->fl_pool, shmem_pool_t);
|
|
}
|
|
} else {
|
|
/* process private memory allocation */
|
|
flist->fl_pool = OBJ_NEW(lam_mem_pool_t);
|
|
}
|
|
|
|
err = lam_mp_construct_with(
|
|
flist->fl_pool,
|
|
mem_in_pool,
|
|
max_mem_in_pool,
|
|
chunk_size,
|
|
page_size);
|
|
return err;
|
|
}
|
|
|
|
|
|
static void *lam_free_lists_get_mem_chunk(lam_free_lists_t *flist, int index, size_t *len, int *err)
|
|
{
|
|
void *chunk = 0;
|
|
uint64_t sz_to_add;
|
|
|
|
/* check to make sure that the amount to add to the list does not
|
|
exceed the amount allowed */
|
|
sz_to_add = lam_mp_get_chunk_size(flist->fl_pool);
|
|
|
|
#if LAM_ENABLE_MEM_PROFILE
|
|
flist->fl_chunks_req[index]++;
|
|
#endif
|
|
|
|
if (index >= flist->fl_nlists)
|
|
{
|
|
lam_output(0, "Error: Array out of bounds");
|
|
return chunk;
|
|
}
|
|
|
|
if ( lam_sgl_get_max_bytes_pushed(flist->fl_free_lists[index]) != -1 )
|
|
{
|
|
if (sz_to_add +
|
|
lam_sgl_get_bytes_pushed(flist->fl_free_lists[index]) >
|
|
lam_sgl_get_max_bytes_pushed(flist->fl_free_lists[index]) )
|
|
{
|
|
lam_sgl_inc_consec_fail(flist->fl_free_lists[index]);
|
|
if ( lam_sgl_get_consec_fail(flist->fl_free_lists[index]) >=
|
|
lam_sgl_get_max_consec_fail(flist->fl_free_lists[index]) )
|
|
{
|
|
*err = LAM_ERR_OUT_OF_RESOURCE;
|
|
lam_output(0, "Error: List out of memory in pool for %s",
|
|
flist->fl_description);
|
|
return chunk;
|
|
} else
|
|
*err = LAM_ERR_TEMP_OUT_OF_RESOURCE;
|
|
|
|
return chunk;
|
|
}
|
|
}
|
|
/* set len */
|
|
*len = sz_to_add;
|
|
|
|
|
|
/* get chunk of memory */
|
|
chunk = lam_mp_request_chunk(flist->fl_pool, index);
|
|
if ( 0 == chunk )
|
|
{
|
|
/* increment failure count */
|
|
lam_sgl_inc_consec_fail(flist->fl_free_lists[index]);
|
|
if ( lam_sgl_get_consec_fail(flist->fl_free_lists[index]) >=
|
|
lam_sgl_get_max_consec_fail(flist->fl_free_lists[index]) )
|
|
{
|
|
*err = LAM_ERR_OUT_OF_RESOURCE;
|
|
lam_output(0, "Error: List out of memory in pool for %s\n",
|
|
flist->fl_description);
|
|
return chunk;
|
|
} else
|
|
*err = LAM_ERR_TEMP_OUT_OF_RESOURCE;
|
|
|
|
return chunk;
|
|
}
|
|
|
|
/* set consecutive failure count to 0 - if we fail, we don't get
|
|
this far in the code. */
|
|
lam_sgl_set_consec_fail(flist->fl_free_lists[index], 0);
|
|
|
|
#if LAM_ENABLE_MEM_PROFILE
|
|
flist->fl_chunks_returned[index]++;
|
|
#endif
|
|
|
|
return chunk;
|
|
}
|
|
|
|
|
|
|
|
#if ROB_HASNT_FINISHED_THIS_YET
|
|
static lam_list_item_t *lam_free_lists_request_elt(lam_free_lists_t *flist, int pool_idx)
|
|
{
|
|
lam_dbl_list_t *seg_list = &(flist->fl_free_lists[pool_idx]->sgl_list);
|
|
volatile lam_list_item_t *elt = lam_dbl_get_last(seg_list);
|
|
|
|
if ( elt )
|
|
lam_sgl_set_consec_fail(seg_list, 0);
|
|
return elt;
|
|
}
|
|
#endif
|
|
|
|
|
|
static void lam_free_lists_append(lam_free_lists_t *flist, void *chunk, int pool_idx)
|
|
{
|
|
/* ASSERT: mp_chunk_sz >= fl_elt_per_chunk * fl_elt_size */
|
|
/* push items onto list */
|
|
lam_sgl_append_elt_chunk(flist->fl_free_lists[pool_idx],
|
|
chunk, lam_mp_get_chunk_size(flist->fl_pool),
|
|
flist->fl_elt_per_chunk, flist->fl_elt_size);
|
|
}
|
|
|
|
|
|
|
|
|
|
static int lam_free_lists_create_more_elts(lam_free_lists_t *flist, int pool_idx)
|
|
{
|
|
int err = LAM_SUCCESS, desc;
|
|
size_t len_added;
|
|
char *current_loc;
|
|
|
|
void *ptr = lam_free_lists_get_mem_chunk(flist, pool_idx, &len_added, &err);
|
|
|
|
if (0 == ptr ) {
|
|
lam_output(0, "Error: Can't get new elements for %s\n",
|
|
flist->fl_description);
|
|
return err;
|
|
}
|
|
|
|
/* attach memory affinity */
|
|
if ( flist->fl_enforce_affinity )
|
|
{
|
|
if (!lam_set_affinity(ptr, len_added,
|
|
flist->fl_affinity[pool_idx]))
|
|
{
|
|
err = LAM_ERROR;
|
|
#ifdef _DEBUGQUEUES
|
|
lam_err(("Error: Can't set memory policy (pool_idx=%d)\n",
|
|
pool_idx));
|
|
return err;
|
|
#endif /* _DEBUGQUEUES */
|
|
}
|
|
}
|
|
|
|
/* Construct new descriptors using placement new */
|
|
current_loc = (char *) ptr;
|
|
for (desc = 0; desc < flist->fl_elt_per_chunk; desc++)
|
|
{
|
|
/* bypass OBJ_CONSTRUCT() in this case (generic types) */
|
|
((lam_object_t *) current_loc)->obj_class = flist->fl_elt_cls;
|
|
((lam_object_t *) current_loc)
|
|
->obj_class->cls_construct((lam_object_t *) current_loc);
|
|
current_loc += flist->fl_elt_size;
|
|
}
|
|
|
|
/* push chunk of memory onto the list */
|
|
lam_free_lists_append(flist, ptr, pool_idx);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
|
|
lam_list_item_t *lam_free_lists_get_elt(lam_free_lists_t *flist, int index, int *error)
|
|
{
|
|
#if ROB_HASNT_FINISHED_THIS_YET
|
|
int error;
|
|
volatile lam_list_item_t *elem = NULL;
|
|
|
|
elem = lam_free_lists_request_elt(flist, index);
|
|
|
|
if ( elem )
|
|
{
|
|
error = LAM_SUCCESS;
|
|
}
|
|
else if ( lam_sgl_get_consec_fail(&(flist->fl_free_lists[index]->sgl_list))
|
|
< flist->fl_threshold_grow )
|
|
{
|
|
error = LAM_ERR_TEMP_OUT_OF_RESOURCE;
|
|
}
|
|
else
|
|
{
|
|
error = LAM_SUCCESS;
|
|
while ( (LAM_SUCCESS) && (0 == elem) &&
|
|
(flist->fl_retry_more_resources) )
|
|
{
|
|
error = lam_free_lists_create_more_elts(flist, index);
|
|
/* get element if managed to add resources to the list */
|
|
if ( LAM_SUCCESS == error )
|
|
{
|
|
elem = lam_free_lists_request_elt(flist, index);
|
|
}
|
|
}
|
|
|
|
if ( (LAM_ERR_OUT_OF_RESOURCE == error)
|
|
|| (LAM_ERR_FATAL == error) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
#if LAM_ENABLE_MEM_PROFILE
|
|
flist->fl_elt_out[index]++;
|
|
flist->fl_elt_sum[index] += flist->fl_elt_out[index];
|
|
flist->fl_nevents[index]++;
|
|
if (flist->fl_elt_max[index] < flist->fl_elt_out[index])
|
|
{
|
|
flist->fl_elt_max[index] = flist->fl_elt_out[index];
|
|
}
|
|
#endif
|
|
|
|
return elem;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
int lam_free_lists_return_elt(lam_free_lists_t *flist, int index, lam_list_item_t *item)
|
|
{
|
|
#if ROB_HASNT_FINISHED_THIS_YET
|
|
mb();
|
|
lam_dbl_append(&(flist->fl_free_lists[index]->sgl_list), item);
|
|
mb();
|
|
|
|
#if LAM_ENABLE_MEM_PROFILE
|
|
flist->fl_elt_out[index]--;
|
|
#endif
|
|
|
|
return LAM_SUCCESS;
|
|
#else
|
|
return LAM_ERROR;
|
|
#endif
|
|
}
|
|
|
|
|