Added allocator using buddy system

This commit is contained in:
2023-08-29 01:42:11 -05:00
parent 85e660b8db
commit 62612f8348
8 changed files with 329 additions and 6 deletions

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ missing
stamp-h1 stamp-h1
.deps .deps
tests/test_bitmapalloc tests/test_bitmapalloc
tests/test_buddyalloc

View File

@@ -1 +1,2 @@
nobase_include_HEADERS = libmalloc/bitmap_alloc.h libmalloc/memmap.h libmalloc/common.h nobase_include_HEADERS = libmalloc/bitmap_alloc.h libmalloc/buddy_alloc.h \
libmalloc/memmap.h libmalloc/common.h

View File

@@ -1,5 +1,5 @@
#ifndef _LIBMALLOC_BUDDYALLOC_H #ifndef _LIBMALLOC_BITMAPALLOC_H
#define _LIBMALLOC_BUDDYALLOC_H #define _LIBMALLOC_BITMAPALLOC_H
#include "memmap.h" #include "memmap.h"
#include "common.h" #include "common.h"

View File

@@ -0,0 +1,55 @@
#ifndef _LIBMALLOC_BUDDYALLOC_H
#define _LIBMALLOC_BUDDYALLOC_H
#include "memmap.h"
#include "common.h"
typedef struct buddy_block_t
{
struct buddy_block_t *linkb;
struct buddy_block_t *linkf;
unsigned long kval;
unsigned long tag;
} buddy_block_t;
typedef struct buddy_descriptor_t
{
/**
* @brief An array of `buddy_block_t` structs serving as the heads of the
* lists of available blocks. avail[k] serves as the head of the list of
* blocks of size 2^k.
*/
buddy_block_t *avail;
buddy_block_t *block_map;
unsigned long block_map_size;
unsigned long max_kval;
unsigned long block_size;
unsigned long offset;
unsigned long free_block_count;
int (*mmap)(void *location, unsigned long size);
} buddy_descriptor_t;
unsigned long buddy_map_size(const memory_map_t *map, unsigned long block_size);
unsigned long buddy_reserve(buddy_descriptor_t *heap, unsigned long size);
void buddy_free(buddy_descriptor_t *heap, unsigned long location);
void buddy_free_size(buddy_descriptor_t *heap, unsigned long size,
unsigned long location);
int buddy_alloc_init(buddy_descriptor_t *heap, memory_map_t *map);
#endif

View File

@@ -1,4 +1,4 @@
lib_LIBRARIES = libmalloc.a lib_LIBRARIES = libmalloc.a
libmalloc_a_SOURCES = bitmap_alloc.c memmap.c libmalloc_a_SOURCES = buddy_alloc.c bitmap_alloc.c memmap.c
libmalloc_a_CFLAGS = -I$(prefix)/include libmalloc_a_CFLAGS = -I$(prefix)/include

161
src/buddy_alloc.c Normal file
View File

@@ -0,0 +1,161 @@
#include "libmalloc/buddy_alloc.h"
#include "util.h"
#define BLOCK_RESERVED 0
#define BLOCK_FREE 1
static unsigned long compute_memory_size(const memory_map_t *map)
{
// Find the last available region in the memory map.
int map_index = map->size - 1;
while(map->array[map_index].type != M_AVAILABLE)
{
map_index--;
}
return map->array[map_index].location + map->array[map_index].size;
}
static void insert_block(buddy_descriptor_t *heap, unsigned long index,
unsigned long k)
{
heap->free_block_count += 1UL << k;
while(k < heap->max_kval)
{
unsigned long buddy_index = index ^ (1UL << k);
if(heap->block_map[buddy_index].tag != BLOCK_FREE
|| heap->block_map[buddy_index].kval != k)
{
break;
}
heap->block_map[buddy_index].linkb->linkf = heap->block_map[buddy_index].linkf;
heap->block_map[buddy_index].linkf->linkb = heap->block_map[buddy_index].linkb;
heap->block_map[buddy_index].tag = BLOCK_RESERVED;
k++;
if(buddy_index < index)
{
index = buddy_index;
}
}
heap->block_map[index].tag = BLOCK_FREE;
buddy_block_t *p = heap->avail[k].linkf;
heap->block_map[index].linkf = p;
heap->block_map[index].linkb = &heap->avail[k];
p->linkb = &heap->block_map[index];
heap->avail[k].linkf = &heap->block_map[index];
heap->block_map[index].kval = k;
}
unsigned long buddy_map_size(const memory_map_t *map, unsigned long block_size)
{
unsigned long memory_size = compute_memory_size(map);
return sizeof(buddy_block_t) * memory_size / block_size;
}
unsigned long buddy_reserve(buddy_descriptor_t *heap, unsigned long size)
{
unsigned long k = llog2((size - 1) / heap->block_size + 1);
for(unsigned long j = k; j <= heap->max_kval; j++)
{
if(heap->avail[j].linkf != &heap->avail[j])
{
buddy_block_t *block = heap->avail[j].linkb;
heap->avail[j].linkb = block->linkb;
heap->avail[j].linkb->linkf = &heap->avail[j];
block->tag = BLOCK_RESERVED;
while(j > k)
{
j--;
buddy_block_t *buddy = block + (1UL << j);
buddy->tag = BLOCK_FREE;
buddy->kval = j;
block->kval = j;
buddy->linkb = &heap->avail[j];
buddy->linkf = &heap->avail[j];
heap->avail[j].linkb = buddy;
heap->avail[j].linkf = buddy;
}
unsigned long index = block - heap->block_map;
heap->free_block_count -= 1UL << k;
return (unsigned long)heap->offset + index * heap->block_size;
}
}
return NOMEM;
}
void buddy_free(buddy_descriptor_t *heap, unsigned long location)
{
unsigned long index = (location - (unsigned long)heap->offset) / heap->block_size;
unsigned long k = llog2((heap->block_size * (1UL << heap->block_map[index].kval)) / heap->block_size);
insert_block(heap, index, k);
}
void buddy_free_size(buddy_descriptor_t *heap, unsigned long location,
unsigned long size)
{
unsigned long index = (location - (unsigned long)heap->offset) / heap->block_size;
unsigned long k = llog2(size / heap->block_size);
insert_block(heap, index, k);
}
int buddy_alloc_init(buddy_descriptor_t *heap, memory_map_t *map)
{
heap->block_map_size = buddy_map_size(map, heap->block_size);
heap->max_kval = llog2(heap->block_map_size / sizeof(buddy_block_t));
heap->free_block_count = 0;
for(int i = 0; i <= heap->max_kval; i++)
{
heap->avail[i].linkf = &heap->avail[i];
heap->avail[i].linkb = &heap->avail[i];
}
if(heap->block_map == (buddy_block_t*)0)
{
int map_index = 0;
while(map->array[map_index].type != M_AVAILABLE
|| map->array[map_index].size < heap->block_map_size)
{
map_index++;
if(map_index >= map->size)
{
return -1;
}
}
heap->block_map = (buddy_block_t*)(heap->offset + map->array[map_index].location);
memmap_insert_region(map, map->array[map_index].location, heap->block_map_size, M_UNAVAILABLE);
if(heap->mmap && heap->mmap(heap->block_map, heap->block_map_size))
{
return -1;
}
}
for(int i = 0; i < heap->block_map_size / sizeof(buddy_block_t); i++)
{
heap->block_map[i].tag = BLOCK_RESERVED;
heap->block_map[i].kval = 0;
heap->block_map[i].linkf = 0;
heap->block_map[i].linkb = 0;
}
for(int i = 0; i < map->size; i++)
{
if(map->array[i].type != M_AVAILABLE)
{
continue;
}
unsigned long location = (map->array[i].location + heap->block_size - 1);
location -= location % heap->block_size;
unsigned long region_end = map->array[i].location + map->array[i].size;
while(location + heap->block_size <= region_end)
{
unsigned long index = location / heap->block_size;
unsigned long k = 0;
insert_block(heap, index, k);
location += heap->block_size;
heap->free_block_count++;
}
}
return 0;
}

View File

@@ -1,6 +1,9 @@
if BUILD_TESTS if BUILD_TESTS
noinst_PROGRAMS = test_bitmapalloc noinst_PROGRAMS = test_bitmapalloc test_buddyalloc
test_bitmapalloc_SOURCES = test_bitmapalloc.c test_bitmapalloc_SOURCES = test_bitmapalloc.c
test_bitmapalloc_LDADD = ../src/libmalloc.a test_bitmapalloc_LDADD = ../src/libmalloc.a
test_buddyalloc_SOURCES = test_buddyalloc.c
test_buddyalloc_LDADD = ../src/libmalloc.a
endif endif

102
tests/test_buddyalloc.c Normal file
View File

@@ -0,0 +1,102 @@
#include "libmalloc/buddy_alloc.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct memblock_t
{
unsigned long size;
unsigned long location;
} memblock_t;
void print_heap(FILE *file, buddy_descriptor_t *heap)
{
unsigned long count = 1UL << heap->max_kval;
fprintf(file, "heap {\n");
fprintf(file, "\t.block_size = %lu\n", heap->block_size);
fprintf(file, "\t.max_kval = %lu\n", heap->max_kval);
fprintf(file, "\t.offset = %lu\n", heap->offset);
fprintf(file, "\t.block_map = {\n");
for(unsigned int i = 0; i < count; i++)
{
unsigned long linkf_diff = heap->block_map[i].linkf - heap->block_map;
unsigned long linkb_diff = heap->block_map[i].linkb - heap->block_map;
fprintf(file, "\t\t%u: {.tag = %s, .kval = %lu, .linkf = %li, .linkb = %li}\n",
i,
heap->block_map[i].tag ? "BLOCK_FREE" : "BLOCK_RESERVED",
heap->block_map[i].kval,
linkf_diff < count ? linkf_diff : -1,
linkb_diff < count ? linkb_diff : -1);
}
fprintf(file, "\t}\n");
fprintf(file, "\t.avail = {\n");
for(unsigned int i = 0; i <= heap->max_kval; i++)
{
fprintf(file, "\t\t%u: {.linkf = %lu, .linkb = %lu}\n",
i,
heap->avail[i].linkf - heap->block_map,
heap->avail[i].linkb - heap->block_map);
}
fprintf(file, "\t}\n}\n");
}
int main(int argc, char **argv)
{
unsigned long mem_size;
unsigned long block_size;
sscanf(argv[1], "%lu", &mem_size);
sscanf(argv[2], "%lu", &block_size);
FILE *out = fopen("debug_output.txt", "w");
if(out == NULL)
{
fprintf(stderr, "Failed to open debug output.\n");
return 0;
}
memory_map_t memory_map = {
.array = malloc(sizeof(memory_region_t) * 16),
.capacity = 16,
.size = 0
};
buddy_descriptor_t heap = {
.avail = malloc(sizeof(buddy_block_t) * 20),
.block_map = malloc(buddy_map_size(&memory_map, block_size)),
.block_size = block_size,
.mmap = NULL,
.offset = 0
};
memmap_insert_region(&memory_map, 0, mem_size, M_AVAILABLE);
if(buddy_alloc_init(&heap, &memory_map))
{
fprintf(stderr, "Failed to initialize buddy allocator.\n");
return 0;
}
print_heap(out, &heap);
memblock_t *blocks = calloc(mem_size / block_size, sizeof(memblock_t));
for(int i = 0; i < 1024; i++)
{
int index = rand() % (mem_size / block_size);
if(blocks[index].size == 0)
{
blocks[index].size = 1;
blocks[index].location = buddy_reserve(&heap, 1);
fprintf(out, "RESERVED %lu\n", blocks[index].location / heap.block_size);
}
else
{
buddy_free(&heap, blocks[index].location);
blocks[index].size = 0;
fprintf(out, "FREED %lu\n", blocks[index].location / heap.block_size);
}
print_heap(out, &heap);
}
print_heap(out, &heap);
return 0;
}