From ec10b572d11120414d250c8089045bcad8a7eb1b Mon Sep 17 00:00:00 2001 From: CTCaer Date: Wed, 4 Dec 2019 19:02:28 +0200 Subject: [PATCH] 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. --- bootloader/mem/heap.c | 67 ++++++++++++++++++++++++++++++++---------- bootloader/mem/heap.h | 2 ++ common/common_heap.h | 7 +++++ nyx/nyx_gui/mem/heap.c | 65 +++++++++++++++++++++++++++++++--------- nyx/nyx_gui/mem/heap.h | 2 ++ 5 files changed, 114 insertions(+), 29 deletions(-) diff --git a/bootloader/mem/heap.c b/bootloader/mem/heap.c index fd46c16..f4892eb 100644 --- a/bootloader/mem/heap.c +++ b/bootloader/mem/heap.c @@ -17,7 +17,8 @@ #include #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; +} diff --git a/bootloader/mem/heap.h b/bootloader/mem/heap.h index 24cb64e..02d40be 100644 --- a/bootloader/mem/heap.h +++ b/bootloader/mem/heap.h @@ -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 diff --git a/common/common_heap.h b/common/common_heap.h index d7f7868..110f013 100644 --- a/common/common_heap.h +++ b/common/common_heap.h @@ -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; diff --git a/nyx/nyx_gui/mem/heap.c b/nyx/nyx_gui/mem/heap.c index 0c49de3..f4892eb 100644 --- a/nyx/nyx_gui/mem/heap.c +++ b/nyx/nyx_gui/mem/heap.c @@ -17,6 +17,7 @@ #include #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; +} diff --git a/nyx/nyx_gui/mem/heap.h b/nyx/nyx_gui/mem/heap.h index 24cb64e..02d40be 100644 --- a/nyx/nyx_gui/mem/heap.h +++ b/nyx/nyx_gui/mem/heap.h @@ -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