mirror of
https://github.com/CTCaer/hekate
synced 2024-11-16 00:49:27 +00:00
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:
parent
d1e50c558e
commit
ec10b572d1
5 changed files with 114 additions and 29 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue