Remove linear search for blocks when allocating
This commit is contained in:
@@ -166,16 +166,14 @@
|
|||||||
#define MIN_BLOCK_SIZE BUDDY_ALLOC_MIN_BLOCK_SIZE
|
#define MIN_BLOCK_SIZE BUDDY_ALLOC_MIN_BLOCK_SIZE
|
||||||
#define MAX_BLOCK_ALIGN_MASK (MAX_BLOCK_SIZE - 1)
|
#define MAX_BLOCK_ALIGN_MASK (MAX_BLOCK_SIZE - 1)
|
||||||
|
|
||||||
struct page { struct page *next; };
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets the address of the i-th page of the memory pool.
|
* Gets the address of the i-th page of the memory pool.
|
||||||
* In this context, a page is a block of size MAX_BLOCK_SIZE.
|
* In this context, a page is a block of size MAX_BLOCK_SIZE.
|
||||||
*/
|
*/
|
||||||
static struct page*
|
static struct buddy_page*
|
||||||
page_index_to_ptr(char *base, int i)
|
page_index_to_ptr(char *base, int i)
|
||||||
{
|
{
|
||||||
return (struct page*) (base + (i << MAX_BLOCK_LOG2));
|
return (struct buddy_page*) (base + (i << MAX_BLOCK_LOG2));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buddy_alloc startup_empty()
|
static struct buddy_alloc startup_empty()
|
||||||
@@ -231,15 +229,23 @@ struct buddy_alloc buddy_startup(char *base, size_t size,
|
|||||||
/*
|
/*
|
||||||
* Make the linked list of pages
|
* Make the linked list of pages
|
||||||
*/
|
*/
|
||||||
struct page *head = NULL;
|
struct buddy_page *head = NULL;
|
||||||
struct page **tail = &head;
|
struct buddy_page *tail = NULL;
|
||||||
int num_pages = size >> MAX_BLOCK_LOG2;
|
int num_pages = size >> MAX_BLOCK_LOG2;
|
||||||
for (int i = 0; i < num_pages; i++) {
|
for (int i = 0; i < num_pages; i++) {
|
||||||
struct page *p = page_index_to_ptr(base, i);
|
|
||||||
*tail = p;
|
struct buddy_page *p = page_index_to_ptr(base, i);
|
||||||
tail = &p->next;
|
|
||||||
|
if (head) {
|
||||||
|
tail->next = p;
|
||||||
|
p->prev = tail;
|
||||||
|
} else {
|
||||||
|
head = p;
|
||||||
|
p->prev = NULL;
|
||||||
|
}
|
||||||
|
tail = p;
|
||||||
|
p->next = NULL;
|
||||||
}
|
}
|
||||||
*tail = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the page info. The page_info bits are 0 when
|
* Initialize the page info. The page_info bits are 0 when
|
||||||
@@ -512,17 +518,15 @@ remove_sibling_from_list(struct buddy_alloc *alloc,
|
|||||||
int i, void *ptr)
|
int i, void *ptr)
|
||||||
{
|
{
|
||||||
size_t len = 1U << (i + MIN_BLOCK_LOG2);
|
size_t len = 1U << (i + MIN_BLOCK_LOG2);
|
||||||
struct page *sibling = (struct page*) sibling_of(ptr, len);
|
struct buddy_page *sibling = (struct buddy_page*) sibling_of(ptr, len);
|
||||||
struct page *curs = (struct page*) alloc->lists[i];
|
|
||||||
struct page **prev = (struct page**) &alloc->lists[i];
|
if (sibling->prev)
|
||||||
while (curs != (struct page*) sibling) {
|
sibling->prev->next = sibling->next;
|
||||||
assert(curs);
|
else
|
||||||
prev = &curs->next;
|
alloc->lists[i] = sibling->next;
|
||||||
curs = curs->next;
|
|
||||||
assert(curs);
|
if (sibling->next)
|
||||||
}
|
sibling->next->prev = sibling->prev;
|
||||||
assert(sibling == curs);
|
|
||||||
*prev = sibling->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -537,21 +541,29 @@ static void append(struct buddy_alloc *alloc,
|
|||||||
{
|
{
|
||||||
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
||||||
|
|
||||||
struct page *pag = ptr;
|
struct buddy_page *page = ptr;
|
||||||
|
|
||||||
pag->next = alloc->lists[i];
|
if (alloc->lists[i])
|
||||||
alloc->lists[i] = pag;
|
alloc->lists[i]->prev = page;
|
||||||
|
|
||||||
|
page->prev = NULL;
|
||||||
|
page->next = alloc->lists[i];
|
||||||
|
|
||||||
|
alloc->lists[i] = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *pop(struct buddy_alloc *alloc, int i)
|
static char *pop(struct buddy_alloc *alloc, int i)
|
||||||
{
|
{
|
||||||
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
||||||
|
|
||||||
char *ptr = alloc->lists[i];
|
|
||||||
assert(ptr);
|
|
||||||
|
|
||||||
alloc->lists[i] = ((struct page*) ptr)->next;
|
struct buddy_page *page = alloc->lists[i];
|
||||||
return ptr;
|
assert(page);
|
||||||
|
|
||||||
|
alloc->lists[i] = page->next;
|
||||||
|
if (alloc->lists[i])
|
||||||
|
alloc->lists[i]->prev = NULL;
|
||||||
|
|
||||||
|
return (char*) page;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *buddy_malloc(struct buddy_alloc *alloc, size_t len)
|
void *buddy_malloc(struct buddy_alloc *alloc, size_t len)
|
||||||
|
|||||||
@@ -29,20 +29,20 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the minimum and maximum block size. The allocator uses free
|
* This is the minimum and maximum block size. The allocator uses doubly
|
||||||
* lists to keep track of unused blocks, so a block must be at least
|
* linked free lists to keep track of unused blocks, so a block must be
|
||||||
* the size of a pointer. We assume a pointer is 8 bytes long, so the
|
* at least the size of two pointers. We assume a pointer is 8 bytes long,
|
||||||
* minimum value must be greater or equal to 3 (log2(8) = 3).
|
* so the minimum value must be greater or equal to 4 (log2(2*8) = 4).
|
||||||
*
|
*
|
||||||
* For the maximum value there is really no downside in making it big,
|
* For the maximum value there is really no downside in making it big,
|
||||||
* except for the fact that the pool provided by the user should at
|
* except for the fact that the pool provided by the user should at
|
||||||
* least be that big.
|
* least be that big.
|
||||||
*/
|
*/
|
||||||
#define BUDDY_ALLOC_MAX_BLOCK_LOG2 13
|
#define BUDDY_ALLOC_MAX_BLOCK_LOG2 13
|
||||||
#define BUDDY_ALLOC_MIN_BLOCK_LOG2 3
|
#define BUDDY_ALLOC_MIN_BLOCK_LOG2 4
|
||||||
|
|
||||||
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 <= BUDDY_ALLOC_MAX_BLOCK_LOG2);
|
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 <= BUDDY_ALLOC_MAX_BLOCK_LOG2);
|
||||||
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 > 2);
|
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 > 3);
|
||||||
|
|
||||||
#define BUDDY_ALLOC_NUM_LISTS (BUDDY_ALLOC_MAX_BLOCK_LOG2 - BUDDY_ALLOC_MIN_BLOCK_LOG2 + 1)
|
#define BUDDY_ALLOC_NUM_LISTS (BUDDY_ALLOC_MAX_BLOCK_LOG2 - BUDDY_ALLOC_MIN_BLOCK_LOG2 + 1)
|
||||||
#define BUDDY_ALLOC_MAX_BLOCK_SIZE (1U << BUDDY_ALLOC_MAX_BLOCK_LOG2)
|
#define BUDDY_ALLOC_MAX_BLOCK_SIZE (1U << BUDDY_ALLOC_MAX_BLOCK_LOG2)
|
||||||
@@ -67,10 +67,15 @@ struct page_info {
|
|||||||
uint32_t bits[BUDDY_ALLOC_WORDS_PER_PAGE];
|
uint32_t bits[BUDDY_ALLOC_WORDS_PER_PAGE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct buddy_page {
|
||||||
|
struct buddy_page *prev;
|
||||||
|
struct buddy_page *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct buddy_alloc {
|
struct buddy_alloc {
|
||||||
void *base;
|
void *base;
|
||||||
size_t size;
|
size_t size;
|
||||||
void *lists[BUDDY_ALLOC_NUM_LISTS];
|
struct buddy_page *lists[BUDDY_ALLOC_NUM_LISTS];
|
||||||
struct page_info *info;
|
struct page_info *info;
|
||||||
int num_info;
|
int num_info;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user