heap: Quality updates to heap management

- Allow reuse of unused sections that fit exactly to selected allocation size. Decreases fragmentation dramatically.
- Always allocate and align mapped memory to selected alignment. Avoids having fragmented unused maps that are not aligned.
- Use a static alignment based on BPMP and generally average cache line size. Boosts performance when MMU is used.
This commit is contained in:
CTCaer 2019-12-04 19:02:28 +02:00
parent d1e50c558e
commit ec10b572d1
5 changed files with 114 additions and 29 deletions

View file

@ -17,7 +17,8 @@
#include <string.h>
#include "heap.h"
#include "../../common/common_heap.h"
#include "../gfx/gfx.h"
#include "../../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start)
{
@ -25,12 +26,13 @@ static void _heap_create(heap_t *heap, u32 start)
heap->first = NULL;
}
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
// Node info is before node address.
static u32 _heap_alloc(heap_t *heap, u32 size)
{
hnode_t *node, *new;
int search = 1;
size = ALIGN(size, alignment);
// Align to cache line size.
size = ALIGN(size, sizeof(hnode_t));
if (!heap->first)
{
@ -45,27 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
}
node = heap->first;
while (search)
while (true)
{
if (!node->used && size + sizeof(hnode_t) < node->size)
if (!node->used && (size <= node->size))
{
u32 new_size = node->size - size;
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
new->size = node->size - sizeof(hnode_t) - size;
// If there's aligned leftover space, create a new node.
if (new_size >= (sizeof(hnode_t) << 2))
{
new->size = new_size - sizeof(hnode_t);
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
}
else
size += new_size;
node->size = size;
node->used = 1;
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
return (u32)node + sizeof(hnode_t);
}
if (node->next)
node = node->next;
else
search = 0;
break;
}
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
@ -108,12 +118,12 @@ void heap_init(u32 base)
void *malloc(u32 size)
{
return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t));
return (void *)_heap_alloc(&_heap, size);
}
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
void *res = (void *)_heap_alloc(&_heap, num * size);
memset(res, 0, num * size);
return res;
}
@ -123,3 +133,30 @@ void free(void *buf)
if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf);
}
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
{
u32 count = 0;
memset(mon, 0, sizeof(heap_monitor));
hnode_t *node = _heap.first;
while (true)
{
if (node->used)
mon->used += node->size + sizeof(hnode_t);
else
mon->total += node->size + sizeof(hnode_t);
if (print_node_stats)
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
count, node->used, (u32)node + sizeof(hnode_t), node->size);
count++;
if (node->next)
node = node->next;
else
break;
}
mon->total += mon->used;
}

View file

@ -18,10 +18,12 @@
#define _HEAP_H_
#include "../utils/types.h"
#include "../../../common/common_heap.h"
void heap_init(u32 base);
void *malloc(u32 size);
void *calloc(u32 num, u32 size);
void free(void *buf);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
#endif

View file

@ -25,6 +25,7 @@ typedef struct _hnode
u32 size;
struct _hnode *prev;
struct _hnode *next;
u32 align[4]; // Align to arch cache line size.
} hnode_t;
typedef struct _heap
@ -32,3 +33,9 @@ typedef struct _heap
u32 start;
hnode_t *first;
} heap_t;
typedef struct
{
u32 total;
u32 used;
} heap_monitor_t;

View file

@ -17,6 +17,7 @@
#include <string.h>
#include "heap.h"
#include "../gfx/gfx.h"
#include "../../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start)
@ -25,12 +26,13 @@ static void _heap_create(heap_t *heap, u32 start)
heap->first = NULL;
}
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
// Node info is before node address.
static u32 _heap_alloc(heap_t *heap, u32 size)
{
hnode_t *node, *new;
int search = 1;
size = ALIGN(size, alignment);
// Align to cache line size.
size = ALIGN(size, sizeof(hnode_t));
if (!heap->first)
{
@ -45,27 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
}
node = heap->first;
while (search)
while (true)
{
if (!node->used && size + sizeof(hnode_t) < node->size)
if (!node->used && (size <= node->size))
{
u32 new_size = node->size - size;
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
new->size = node->size - sizeof(hnode_t) - size;
// If there's aligned leftover space, create a new node.
if (new_size >= (sizeof(hnode_t) << 2))
{
new->size = new_size - sizeof(hnode_t);
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
}
else
size += new_size;
node->size = size;
node->used = 1;
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
return (u32)node + sizeof(hnode_t);
}
if (node->next)
node = node->next;
else
search = 0;
break;
}
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
@ -108,12 +118,12 @@ void heap_init(u32 base)
void *malloc(u32 size)
{
return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t));
return (void *)_heap_alloc(&_heap, size);
}
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
void *res = (void *)_heap_alloc(&_heap, num * size);
memset(res, 0, num * size);
return res;
}
@ -123,3 +133,30 @@ void free(void *buf)
if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf);
}
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
{
u32 count = 0;
memset(mon, 0, sizeof(heap_monitor));
hnode_t *node = _heap.first;
while (true)
{
if (node->used)
mon->used += node->size + sizeof(hnode_t);
else
mon->total += node->size + sizeof(hnode_t);
if (print_node_stats)
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
count, node->used, (u32)node + sizeof(hnode_t), node->size);
count++;
if (node->next)
node = node->next;
else
break;
}
mon->total += mon->used;
}

View file

@ -18,10 +18,12 @@
#define _HEAP_H_
#include "../utils/types.h"
#include "../../../common/common_heap.h"
void heap_init(u32 base);
void *malloc(u32 size);
void *calloc(u32 num, u32 size);
void free(void *buf);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
#endif