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 <string.h>
#include "heap.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) 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; 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; 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) if (!heap->first)
{ {
@ -45,27 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
} }
node = heap->first; 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 = (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->size = size;
node->used = 1; 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); return (u32)node + sizeof(hnode_t);
} }
if (node->next) if (node->next)
node = node->next; node = node->next;
else else
search = 0; break;
} }
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
@ -108,12 +118,12 @@ void heap_init(u32 base)
void *malloc(u32 size) 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 *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); memset(res, 0, num * size);
return res; return res;
} }
@ -123,3 +133,30 @@ void free(void *buf)
if ((u32)buf >= _heap.start) if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf); _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_ #define _HEAP_H_
#include "../utils/types.h" #include "../utils/types.h"
#include "../../../common/common_heap.h"
void heap_init(u32 base); void heap_init(u32 base);
void *malloc(u32 size); void *malloc(u32 size);
void *calloc(u32 num, u32 size); void *calloc(u32 num, u32 size);
void free(void *buf); void free(void *buf);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
#endif #endif

View file

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

View file

@ -17,6 +17,7 @@
#include <string.h> #include <string.h>
#include "heap.h" #include "heap.h"
#include "../gfx/gfx.h"
#include "../../../common/common_heap.h" #include "../../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start) 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; 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; 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) if (!heap->first)
{ {
@ -45,27 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
} }
node = heap->first; 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 = (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->size = size;
node->used = 1; 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); return (u32)node + sizeof(hnode_t);
} }
if (node->next) if (node->next)
node = node->next; node = node->next;
else else
search = 0; break;
} }
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
@ -108,12 +118,12 @@ void heap_init(u32 base)
void *malloc(u32 size) 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 *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); memset(res, 0, num * size);
return res; return res;
} }
@ -123,3 +133,30 @@ void free(void *buf)
if ((u32)buf >= _heap.start) if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf); _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_ #define _HEAP_H_
#include "../utils/types.h" #include "../utils/types.h"
#include "../../../common/common_heap.h"
void heap_init(u32 base); void heap_init(u32 base);
void *malloc(u32 size); void *malloc(u32 size);
void *calloc(u32 num, u32 size); void *calloc(u32 num, u32 size);
void free(void *buf); void free(void *buf);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
#endif #endif