1
1

First commit of the bucket allocator component.

This commit was SVN r1316.
Этот коммит содержится в:
Tim Prins 2004-06-16 15:53:55 +00:00
родитель 1e9468c78c
Коммит 1c5a7ce476
6 изменённых файлов: 675 добавлений и 0 удалений

39
src/mca/allocator/bucket/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,39 @@
# -*- makefile -*-
#
# $HEADER$
#
include $(top_ompi_srcdir)/config/Makefile.options
# According to the MCA spec, we have to make the output library here
# in the top-level directory, and it has to be named
# libompi_ssi_coll_ompi_basic.la
if OMPI_BUILD_allocator_bucket_LOADABLE_MODULE
module_noinst =
module_install = mca_allocator_bucket.la
else
module_noinst = libmca_allocator_bucket.la
module_install =
endif
mcamoduledir = $(libdir)/ompi
mcamodule_LTLIBRARIES = $(module_install)
mca_allocator_bucket_la_SOURCES =
mca_allocator_bucket_la_LIBADD = \
src/libmca_allocator_bucket.la \
$(LIBOMPI_LA)
mca_allocator_bucket_la_LDFLAGS = -module -avoid-version
libmca_allocator_bucket_la_LDFLAGS = -module -avoid-version
AM_CPPFLAGS = \
-I$(top_ompi_builddir)/src/include \
-I$(top_ompi_srcdir)/src \
-I$(top_ompi_srcdir)/src/include
noinst_LTLIBRARIES = libmca_allocator_bucket.la
libmca_allocator_bucket_la_SOURCES = \
allocator_bucket.c \
allocator_bucket_alloc.h \
allocator_bucket_alloc.c

6
src/mca/allocator/bucket/VERSION Обычный файл
Просмотреть файл

@ -0,0 +1,6 @@
major=1
minor=0
release=0
alpha=0
beta=0
svn=1

93
src/mca/allocator/bucket/allocator_bucket.c Обычный файл
Просмотреть файл

@ -0,0 +1,93 @@
#include "mca/allocator/allocator.h"
#include "include/constants.h"
#include "mca/base/mca_base_param.h"
#include "mca/allocator/bucket/allocator_bucket_alloc.h"
struct mca_allocator_t* mca_allocator_bucket_module_init(
bool *allow_multi_user_threads,
mca_allocator_segment_alloc_fn_t segment_alloc,
mca_allocator_segment_free_fn_t segment_free);
int mca_allocator_bucket_module_open(void);
int mca_allocator_bucket_module_close(void);
void * mca_allocator_bucket_alloc_wrapper(struct mca_allocator_t* allocator,
size_t size, size_t align);
struct mca_allocator_t* mca_allocator_bucket_module_init(
bool *allow_multi_user_threads,
mca_allocator_segment_alloc_fn_t segment_alloc,
mca_allocator_segment_free_fn_t segment_free)
{
int num_buckets = 30;
int id;
size_t alloc_size = sizeof(mca_allocator_bucket_t);
mca_allocator_bucket_t * retval;
mca_allocator_bucket_t * allocator = segment_alloc(&alloc_size);
if(NULL == allocator) {
return(NULL);
}
id = mca_base_param_register_int("allocator","bucket","num_buckets",
NULL,num_buckets);
mca_base_param_lookup_int(id,&num_buckets);
retval = mca_allocator_bucket_init((mca_allocator_t *) allocator, num_buckets,
segment_alloc, segment_free);
if(NULL == retval) {
segment_free(allocator);
return(NULL);
}
allocator->super.alc_alloc = mca_allocator_bucket_alloc_wrapper;
allocator->super.alc_realloc = mca_allocator_bucket_realloc;
allocator->super.alc_free = mca_allocator_bucket_free;
allocator->super.alc_finalize = mca_allocator_bucket_cleanup;
return((mca_allocator_t *) allocator);
}
int mca_allocator_bucket_module_open(void) {
return(OMPI_SUCCESS);
}
int mca_allocator_bucket_module_close(void) {
return(OMPI_SUCCESS);
}
void * mca_allocator_bucket_alloc_wrapper(struct mca_allocator_t* allocator,
size_t size, size_t align)
{
if(0 == align){
return(mca_allocator_bucket_alloc(allocator, size));
}
return(mca_allocator_bucket_alloc_align(allocator, size, align));
}
mca_allocator_base_module_t mca_allocator_bucket_module = {
/* First, the mca_base_module_t struct containing meta information
about the module itself */
{
/* Indicate that we are a allocator v1.0.0 module (which also implies a
specific MCA version) */
MCA_ALLOCATOR_BASE_VERSION_1_0_0,
"bucket", /* MCA module name */
1, /* MCA module major version */
0, /* MCA module minor version */
0, /* MCA module release version */
mca_allocator_bucket_module_open, /* module open */
mca_allocator_bucket_module_close /* module close */
},
/* Next the MCA v1.0.0 module meta data */
{
/* Whether the module is checkpointable or not */
false
},
mca_allocator_bucket_module_init
};

Просмотреть файл

@ -0,0 +1,331 @@
/*
* $HEADER$
*/
#include "mca/allocator/bucket/allocator_bucket_alloc.h"
#include <stdio.h>
/**
* The define controls the size in bytes of the 1st bucket and hence every one
* afterwards.
*/
#define MCA_ALLOCATOR_BUCKET_1_SIZE 8
/**
* This is the number of left bit shifts from 1 needed to get to the number of
* bytes in the initial memory buckets
*/
#define MCA_ALLOCATOR_BUCKET_1_BITSHIFTS 3
/*
* Initializes the mca_allocator_bucket_options_t data structure for the passed
* parameters.
*/
mca_allocator_bucket_t * mca_allocator_bucket_init(mca_allocator_t * mem,
int num_buckets,
mca_allocator_segment_alloc_fn_t get_mem_funct,
mca_allocator_segment_free_fn_t free_mem_funct)
{
mca_allocator_bucket_t * mem_options = (mca_allocator_bucket_t *) mem;
int i;
size_t size;
/* if a bad value is used for the number of buckets, default to 30 */
if(i <= 0) {
num_buckets = 30;
}
/* initialize the array of buckets */
size = sizeof(mca_allocator_bucket_bucket_t) * num_buckets;
mem_options->buckets = (mca_allocator_bucket_bucket_t*) get_mem_funct(&size);
if(NULL == mem_options->buckets) {
return(NULL);
}
for(i = 0; i < num_buckets; i++) {
mem_options->buckets[i].free_chunk = NULL;
mem_options->buckets[i].segment_head = NULL;
OBJ_CONSTRUCT(&(mem_options->buckets[i].lock), ompi_mutex_t);
}
mem_options->num_buckets = num_buckets;
mem_options->get_mem_fn = get_mem_funct;
mem_options->free_mem_fn = free_mem_funct;
return(mem_options);
}
/*
* Accepts a request for memory in a specific region defined by the
* mca_allocator_bucket_options_t struct and returns a pointer to memory in that
* region or NULL if there was an error
*
*/
void * mca_allocator_bucket_alloc(mca_allocator_t * mem, size_t size)
{
mca_allocator_bucket_t * mem_options = (mca_allocator_bucket_t *) mem;
int bucket_num = 0;
/* initialize for the later bit shifts */
size_t bucket_size = 1;
size_t allocated_size;
mca_allocator_bucket_chunk_header_t * chunk;
mca_allocator_bucket_chunk_header_t * first_chunk;
mca_allocator_bucket_segment_head_t * segment_header;
/* add the size of the header into the amount we need to request */
size += sizeof(mca_allocator_bucket_chunk_header_t);
/* figure out which bucket it will come from. */
while(size > MCA_ALLOCATOR_BUCKET_1_SIZE) {
size >>= 1;
bucket_num++;
}
/* now that we know what bucket it will come from, we must get the lock */
THREAD_LOCK(&(mem_options->buckets[bucket_num].lock));
/* see if there is already a free chunk */
if(NULL != mem_options->buckets[bucket_num].free_chunk) {
chunk = mem_options->buckets[bucket_num].free_chunk;
mem_options->buckets[bucket_num].free_chunk = chunk->u.next_free;
chunk->u.bucket = bucket_num;
/* go past the header */
chunk += 1;
/*release the lock */
THREAD_UNLOCK(&(mem_options->buckets[bucket_num].lock));
return((void *) chunk);
}
/* figure out the size of bucket we need */
bucket_size <<= (bucket_num + MCA_ALLOCATOR_BUCKET_1_BITSHIFTS);
allocated_size = bucket_size;
/* we have to add in the size of the segment header into the
* amount we need to request */
allocated_size += sizeof(mca_allocator_bucket_segment_head_t);
/* attempt to get the memory */
segment_header = (mca_allocator_bucket_segment_head_t *)
mem_options->get_mem_fn(&allocated_size);
if(NULL == segment_header) {
/* release the lock */
THREAD_UNLOCK(&(mem_options->buckets[bucket_num].lock));
return(NULL);
}
/* if were allocated more memory then we actually need, then we will try to
* break it up into multiple chunks in the current bucket */
allocated_size -= (sizeof(mca_allocator_bucket_segment_head_t) + bucket_size);
chunk = first_chunk = segment_header->first_chunk =
(mca_allocator_bucket_chunk_header_t *) (segment_header + 1);
/* add the segment into the segment list */
segment_header->next_segment = mem_options->buckets[bucket_num].segment_head;
mem_options->buckets[bucket_num].segment_head = segment_header;
if(allocated_size >= bucket_size) {
mem_options->buckets[bucket_num].free_chunk =
(mca_allocator_bucket_chunk_header_t *) ((char *) chunk + bucket_size);
chunk->next_in_segment = (mca_allocator_bucket_chunk_header_t *)
((char *)chunk + bucket_size);
while(allocated_size >= bucket_size) {
chunk = (mca_allocator_bucket_chunk_header_t *) ((char *) chunk + bucket_size);
chunk->u.next_free = (mca_allocator_bucket_chunk_header_t *)
((char *) chunk + bucket_size);
chunk->next_in_segment = chunk->u.next_free;
allocated_size -= bucket_size;
}
chunk->next_in_segment = first_chunk;
chunk->u.next_free = NULL;
} else {
first_chunk->next_in_segment = first_chunk;
}
first_chunk->u.bucket = bucket_num;
THREAD_UNLOCK(&(mem_options->buckets[bucket_num].lock));
/* return the memory moved past the header */
return((void *) (first_chunk + 1));
}
/*
* allocates an aligned region of memory
*/
void * mca_allocator_bucket_alloc_align(mca_allocator_t * mem, size_t size, size_t alignment)
{
/**
* not yet working correctly
**/
mca_allocator_bucket_t * mem_options = (mca_allocator_bucket_t *) mem;
int bucket_num = 1;
void * ptr;
size_t aligned_max_size, bucket_size;
size_t alignment_off, allocated_size;
mca_allocator_bucket_chunk_header_t * chunk;
mca_allocator_bucket_chunk_header_t * first_chunk;
mca_allocator_bucket_segment_head_t * segment_header;
char * aligned_memory;
/* since we do not have a way to get pre aligned memory, we need to request
* a chunk then return an aligned spot in it. In the worst case we need
* the requested size plus the alignment and the header size */
aligned_max_size = size + alignment + sizeof(mca_allocator_bucket_chunk_header_t)
+ sizeof(mca_allocator_bucket_segment_head_t);
bucket_size = size;
allocated_size = aligned_max_size;
/* get some memory */
ptr = mem_options->get_mem_fn(&allocated_size);
if(NULL == ptr) {
return(NULL);
}
/* the first part of the memory is the segment header */
segment_header = (mca_allocator_bucket_segment_head_t *) ptr;
/* we temporarily define the first chunk to be right after the segment_header */
first_chunk = (mca_allocator_bucket_chunk_header_t *) (segment_header + 1);
/* we want to align the memory right after the header, so we go past the header */
aligned_memory = (char *) (first_chunk + 1);
/* figure out how much the alignment is off by */
alignment_off = (unsigned int) aligned_memory % alignment;
printf("%d ", alignment_off);
aligned_memory += alignment_off;
/* we now have an aligned piece of memory. Now we have to put the chunk header
* right before the aligned memory */
first_chunk = (mca_allocator_bucket_chunk_header_t *) aligned_memory - 1;
while(bucket_size > MCA_ALLOCATOR_BUCKET_1_SIZE) {
bucket_size >>= 1;
bucket_num++;
}
bucket_size = 1;
bucket_size <<= MCA_ALLOCATOR_BUCKET_1_BITSHIFTS + bucket_num;
/* if were allocated more memory then we actually need, then we will try to
* break it up into multiple chunks in the current bucket */
allocated_size -= aligned_max_size;
chunk = segment_header->first_chunk = first_chunk;
/* we now need to get a lock on the bucket */
THREAD_LOCK(&(mem_options->buckets[bucket_num].lock));
/* add the segment into the segment list */
segment_header->next_segment = mem_options->buckets[bucket_num].segment_head;
mem_options->buckets[bucket_num].segment_head = segment_header;
printf("break3\n");
fflush(stdout);
if(allocated_size >= bucket_size) {
mem_options->buckets[bucket_num].free_chunk =
(mca_allocator_bucket_chunk_header_t *) ((char *) chunk + bucket_size);
chunk->next_in_segment = (mca_allocator_bucket_chunk_header_t *)
((char *)chunk + bucket_size);
while(allocated_size >= bucket_size) {
chunk = (mca_allocator_bucket_chunk_header_t *) ((char *) chunk + bucket_size);
chunk->u.next_free = (mca_allocator_bucket_chunk_header_t *)
((char *) chunk + bucket_size);
chunk->next_in_segment = chunk->u.next_free;
allocated_size -= bucket_size;
}
chunk->next_in_segment = first_chunk;
chunk->u.next_free = NULL;
} else {
first_chunk->next_in_segment = first_chunk;
}
first_chunk->u.bucket = bucket_num;
THREAD_UNLOCK(&(mem_options->buckets[bucket_num].lock));
/* return the aligned memory */
return((void *) (aligned_memory));
}
/*
* function to reallocate the segment of memory
*/
void * mca_allocator_bucket_realloc(mca_allocator_t * mem, void * ptr,
size_t size)
{
mca_allocator_bucket_t * mem_options = (mca_allocator_bucket_t *) mem;
/* initialize for later bit shifts */
size_t bucket_size = 1;
int bucket_num;
void * ret_ptr;
/* get the header of the chunk */
mca_allocator_bucket_chunk_header_t * chunk = (mca_allocator_bucket_chunk_header_t *) ptr - 1;
bucket_num = chunk->u.bucket;
bucket_size <<= (bucket_num + MCA_ALLOCATOR_BUCKET_1_BITSHIFTS);
/* since the header area is not available to the user, we need to
* subtract off the header size */
bucket_size -= sizeof(mca_allocator_bucket_chunk_header_t);
/* if the requested size is less than or equal to what they ask for,
* just give them back what they passed in */
if(size <= bucket_size) {
return(ptr);
}
/* we need a new space in memory, so let's get it */
ret_ptr = mca_allocator_bucket_alloc((mca_allocator_t *) mem_options, size);
if(NULL == ret_ptr) {
return(NULL);
}
/* copy what they have in memory to the new spot */
memcpy(ret_ptr, ptr, bucket_size);
/* free the old area in memory */
mca_allocator_bucket_free((mca_allocator_t *) mem_options, ptr);
return(ret_ptr);
}
/*
* Frees the passed region of memory
*
*/
void mca_allocator_bucket_free(mca_allocator_t * mem, void * ptr)
{
mca_allocator_bucket_t * mem_options = (mca_allocator_bucket_t *) mem;
mca_allocator_bucket_chunk_header_t * chunk = (mca_allocator_bucket_chunk_header_t *) ptr - 1;
int bucket_num = chunk->u.bucket;
THREAD_LOCK(&(mem_options->buckets[bucket_num].lock));
chunk->u.next_free = mem_options->buckets[bucket_num].free_chunk;
mem_options->buckets[bucket_num].free_chunk = chunk;
THREAD_UNLOCK(&(mem_options->buckets[bucket_num].lock));
}
/*
* Frees all the memory from all the buckets back to the system. Note that
* this function only frees memory that was previously freed with
* mca_allocator_bucket_free().
*
*/
int mca_allocator_bucket_cleanup(mca_allocator_t * mem)
{
mca_allocator_bucket_t * mem_options = (mca_allocator_bucket_t *) mem;
int i;
mca_allocator_bucket_chunk_header_t * next_chunk;
mca_allocator_bucket_chunk_header_t * chunk;
mca_allocator_bucket_chunk_header_t * first_chunk;
mca_allocator_bucket_segment_head_t ** segment_header;
mca_allocator_bucket_segment_head_t * segment;
bool empty = true;
for(i = 0; i < mem_options->num_buckets; i++) {
THREAD_LOCK(&(mem_options->buckets[i].lock));
segment_header = &(mem_options->buckets[i].segment_head);
/* traverse the list of segment headers until we hit NULL */
while(NULL != *segment_header) {
first_chunk = (*segment_header)->first_chunk;
chunk = first_chunk;
/* determine if the segment is free */
do
{
if(chunk->u.bucket == i) {
empty = false;
}
chunk = chunk->next_in_segment;
} while(empty && (chunk != first_chunk));
if(empty) {
chunk = first_chunk;
/* remove the chunks from the free list */
do
{
if(mem_options->buckets[i].free_chunk == chunk) {
mem_options->buckets[i].free_chunk = chunk->u.next_free;
} else {
next_chunk = mem_options->buckets[i].free_chunk;
while(next_chunk->u.next_free != chunk) {
next_chunk = next_chunk->u.next_free;
}
next_chunk->u.next_free = chunk->u.next_free;
}
} while((chunk = chunk->next_in_segment) != first_chunk);
/* set the segment list to point to the next segment */
segment = *segment_header;
*segment_header = segment->next_segment;
/* free the memory */
mem_options->free_mem_fn(segment);
} else {
/* go to next segment */
segment_header = &((*segment_header)->next_segment);
}
empty = true;
}
/* relese the lock on the bucket */
THREAD_UNLOCK(&(mem_options->buckets[i].lock));
}
return(OMPI_SUCCESS);
}

Просмотреть файл

@ -0,0 +1,196 @@
/**
* $HEADER$
*/
/** @file
* A generic memory allocator.
*
*
**/
#ifndef ALLOCATOR_BUCKET_ALLOC_H
#define ALLOCATOR_BUCKET_ALLOC_H
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "threads/mutex.h"
#include "class/ompi_object.h"
#include "mca/allocator/allocator.h"
/**
* Typedef so we can add a pointer to mca_allocator_bucket_chunk_header_t in
* mca_allocator_bucket_chunk_header_t
*/
typedef struct mca_allocator_bucket_chunk_header_t * mca_allocator_bucket_chunk_header_ptr_t;
/**
* Structure for the header of each memory chunk
*/
struct mca_allocator_bucket_chunk_header_t {
mca_allocator_bucket_chunk_header_ptr_t next_in_segment; /**< The next chunk in the
memory segment */
/**
* Union which holds either a pointer to the next free chunk
* or the bucket number
*/
union u {
mca_allocator_bucket_chunk_header_ptr_t next_free; /**< if the chunk is free this
will point to the next free
chunk in the bucket */
int bucket; /**< the bucket number it belongs to */
} u; /**< the union */
};
/**
* Typedef so we don't have to use struct
*/
typedef struct mca_allocator_bucket_chunk_header_t mca_allocator_bucket_chunk_header_t;
/**
* Typedef so we can reference a pointer to mca_allocator_bucket_segment_head_t from itself
*/
typedef struct mca_allocator_bucket_segment_head_t * mca_allocator_bucket_segment_head_ptr;
/**
* Structure that heads each segment
*/
struct mca_allocator_bucket_segment_head_t {
mca_allocator_bucket_chunk_header_t * first_chunk; /**< the first chunk of the header */
mca_allocator_bucket_segment_head_ptr next_segment; /**< the next segment in the
bucket */
};
/**
* Typedef so we don't have to use struct
*/
typedef struct mca_allocator_bucket_segment_head_t mca_allocator_bucket_segment_head_t;
/**
* Structure for each bucket
*/
struct mca_allocator_bucket_bucket_t {
mca_allocator_bucket_chunk_header_t * free_chunk; /**< the first free chunk of memory */
ompi_mutex_t lock; /**< the lock on the bucket */
mca_allocator_bucket_segment_head_t * segment_head; /**< the list of segment headers */
};
/**
* Typedef so we don't have to use struct
*/
typedef struct mca_allocator_bucket_bucket_t mca_allocator_bucket_bucket_t;
/**
* Structure that holds the necessary information for each area of memory
*/
struct mca_allocator_bucket_t {
mca_allocator_t super;
mca_allocator_bucket_bucket_t * buckets; /**< the array of buckets */
int num_buckets; /**< the number of buckets */
mca_allocator_segment_alloc_fn_t get_mem_fn; /**< pointer to the function to get
more memory */
mca_allocator_segment_free_fn_t free_mem_fn; /**< pointer to the function to free
memory */
};
/**
* Typedef so we don't have to use struct
*/
typedef struct mca_allocator_bucket_t mca_allocator_bucket_t;
#if defined(c_plusplus) || defined(__cplusplus)
extern "C" {
#endif
/**
* Initializes the mca_allocator_bucket_options_t data structure for the passed
* parameters.
* @param numBuckets The number of buckets the allocator will use
* @param get_mem_funct A pointer to the function that the allocator
* will use to get more memory
* @param free_mem_funct A pointer to the function that the allocator
* will use to free memory
*
* @retval Pointer to the initialized mca_allocator_bucket_options_t structure
* @retval NULL if there was an error
*/
mca_allocator_bucket_t * mca_allocator_bucket_init(mca_allocator_t * mem,
int num_buckets,
mca_allocator_segment_alloc_fn_t get_mem_funct,
mca_allocator_segment_free_fn_t free_mem_funct);
/**
* Accepts a request for memory in a specific region defined by the
* mca_allocator_bucket_options_t struct and returns a pointer to memory in that
* region or NULL if there was an error
*
* @param mem_options A pointer to the appropriate struct for the area of
* memory.
* @param size The size of the requested area of memory
*
* @retval Pointer to the area of memory if the allocation was successful
* @retval NULL if the allocation was unsuccessful
*
*/
void * mca_allocator_bucket_alloc(mca_allocator_t * mem, size_t size);
/**
* Accepts a request for memory in a specific region defined by the
* mca_allocator_bucket_options_t struct and aligned by the specified amount and returns a
* pointer to memory in that region or NULL if there was an error
*
* @param mem_options A pointer to the appropriate struct for the area of
* memory.
* @param size The size of the requested area of memory
* @param alignment The requested alignment of the new area of memory. This
* MUST be a power of 2. If it is 0 then the memory is aligned on a page
* boundry
*
* @retval Pointer to the area of memory if the allocation was successful
* @retval NULL if the allocation was unsuccessful
*
*/
void * mca_allocator_bucket_alloc_align(mca_allocator_t * mem, size_t size,
size_t alignment);
/**
* Attempts to resize the passed region of memory into a larger or a smaller
* region. If it is unsuccessful, it will return NULL and the passed area of
* memory will be untouched.
*
* @param mem_options A pointer to the appropriate struct for the area of
* memory.
* @param size The size of the requested area of memory
* @param ptr A pointer to the region of memory to be resized
*
* @retval Pointer to the area of memory if the reallocation was successful
* @retval NULL if the allocation was unsuccessful
*
*/
void * mca_allocator_bucket_realloc(mca_allocator_t * mem, void * ptr,
size_t size);
/**
* Frees the passed region of memory
*
* @param mem_options A pointer to the appropriate struct for the area of
* memory.
* @param ptr A pointer to the region of memory to be freed
*
* @retval None
*
*/
void mca_allocator_bucket_free(mca_allocator_t * mem, void * ptr);
/**
* Frees all the memory from all the buckets back to the system. Note that
* this function only frees memory that was previously freed with
* mca_allocator_bucket_free().
*
* @param mem_options A pointer to the appropriate struct for the area of
* memory.
*
* @retval None
*
*/
int mca_allocator_bucket_cleanup(mca_allocator_t * mem);
#if defined(c_plusplus) || defined(__cplusplus)
}
#endif
#endif /* ALLOCATOR_BUCKET_ALLOC_H */

10
src/mca/allocator/bucket/configure.params Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
# -*- shell-script -*-
#
# $HEADER$
#
# Specific to this module
PARAM_INIT_FILE=allocator_bucket_alloc.c
PARAM_CONFIG_HEADER_FILE="allocator_bucket_alloc.h"
PARAM_CONFIG_FILES="Makefile"