Made heap a vector of pages
Instead of using a linked list, which is incredibly fragmented, a vector keeps all pointers together. Keeps all our stuff together and in theory we should have less cache misses when deleting pages. It does introduce the issue of fragmenting, where if we allocate and then delete many times a lot of the heap vector will be empty so traversal will be over a ton of useless stuff.
This commit is contained in:
69
lib/heap.c
69
lib/heap.c
@@ -12,17 +12,19 @@
|
||||
|
||||
#include "./heap.h"
|
||||
|
||||
#include <lib/darr.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
page_t *page_create(size_t max, page_t *next)
|
||||
page_t *page_create(size_t max)
|
||||
{
|
||||
if (max == 0)
|
||||
max = PAGE_DEFAULT_SIZE;
|
||||
|
||||
page_t *page = calloc(1, sizeof(*page) + max);
|
||||
page->available = max;
|
||||
page->next = next;
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -38,13 +40,8 @@ void heap_create(heap_t *heap)
|
||||
|
||||
page_t *heap_allocate(heap_t *heap, size_t requested)
|
||||
{
|
||||
page_t *cur = page_create(requested, NULL);
|
||||
if (heap->end)
|
||||
heap->end->next = cur;
|
||||
else
|
||||
heap->beg = cur;
|
||||
heap->end = cur;
|
||||
heap->pages++;
|
||||
page_t *cur = page_create(requested);
|
||||
darr_append_bytes(&heap->page_vec, (byte_t *)cur, sizeof(cur));
|
||||
return cur;
|
||||
}
|
||||
|
||||
@@ -53,52 +50,30 @@ bool heap_free(heap_t *heap, page_t *page)
|
||||
if (!page || !heap)
|
||||
return false;
|
||||
|
||||
if (page == heap->beg)
|
||||
for (size_t i = 0; i < (heap->page_vec.used / sizeof(page)); ++i)
|
||||
{
|
||||
heap->beg = heap->beg->next;
|
||||
page_delete(page);
|
||||
--heap->pages;
|
||||
if (heap->pages == 0)
|
||||
heap->end = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
page_t *prev = NULL, *next = NULL, *cur = NULL;
|
||||
for (cur = heap->beg; cur; cur = cur->next)
|
||||
{
|
||||
next = cur->next;
|
||||
page_t *cur = DARR_AT(page_t *, heap->page_vec.data, i);
|
||||
if (cur == page)
|
||||
break;
|
||||
prev = cur;
|
||||
{
|
||||
page_delete(cur);
|
||||
// TODO: When does this fragmentation become a performance
|
||||
// issue?
|
||||
DARR_AT(page_t *, heap->page_vec.data, i) = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cur)
|
||||
// Couldn't find the page
|
||||
return false;
|
||||
// Page was found
|
||||
prev->next = next;
|
||||
if (!next)
|
||||
// This means page == heap->end
|
||||
heap->end = prev;
|
||||
page_delete(page);
|
||||
--heap->pages;
|
||||
if (heap->pages == 0)
|
||||
heap->beg = NULL;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void heap_stop(heap_t *heap)
|
||||
{
|
||||
page_t *ptr = heap->beg;
|
||||
for (size_t i = 0; i < heap->pages; ++i)
|
||||
for (size_t i = 0; i < (heap->page_vec.used / sizeof(page_t *)); i++)
|
||||
{
|
||||
page_t *cur = ptr;
|
||||
page_t *next = ptr->next;
|
||||
page_delete(cur);
|
||||
ptr = next;
|
||||
page_t *ptr = DARR_AT(page_t *, heap->page_vec.data, i);
|
||||
if (ptr)
|
||||
page_delete(ptr);
|
||||
}
|
||||
heap->beg = NULL;
|
||||
heap->end = NULL;
|
||||
heap->pages = 0;
|
||||
free(heap->page_vec.data);
|
||||
heap->page_vec = (darr_t){0};
|
||||
}
|
||||
|
||||
29
lib/heap.h
29
lib/heap.h
@@ -14,19 +14,17 @@
|
||||
#define HEAP_H
|
||||
|
||||
#include "./base.h"
|
||||
#include "./darr.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PAGE_DEFAULT_SIZE 256
|
||||
|
||||
/**
|
||||
@brief Some fixed portion of bytes allocated on the heap in a
|
||||
linked list.
|
||||
@brief Some fixed portion of bytes allocated on the heap.
|
||||
|
||||
@details A fixed allocation of bytes, with size and a link to the
|
||||
next page. Cannot be resized nor can it be stack allocated the
|
||||
usual way due to flexible array attached.
|
||||
@details A fixed allocation of bytes. Cannot be resized nor can it
|
||||
be stack allocated (the usual way) due to flexible array attached.
|
||||
|
||||
@prop[next] Next page in the linked list
|
||||
@prop[available] Available number of bytes in page
|
||||
@@ -34,7 +32,6 @@
|
||||
*/
|
||||
typedef struct Page
|
||||
{
|
||||
struct Page *next;
|
||||
size_t available;
|
||||
byte_t data[];
|
||||
} page_t;
|
||||
@@ -47,16 +44,15 @@ typedef struct Page
|
||||
default.
|
||||
|
||||
@param[max] Maximum available memory in page
|
||||
@param[next] Next page to link this page to
|
||||
*/
|
||||
page_t *page_create(size_t max, page_t *next);
|
||||
page_t *page_create(size_t max);
|
||||
|
||||
/**
|
||||
@brief Delete a page, freeing its memory
|
||||
|
||||
@details Free's the memory associated with the page via free().
|
||||
NOTE: any pointer's to the page's memory are considered invalid
|
||||
once this is called.
|
||||
NOTE: any pointers to the page's memory are considered invalid once
|
||||
this is called.
|
||||
|
||||
@param[page] Page to delete
|
||||
*/
|
||||
@@ -66,17 +62,14 @@ void page_delete(page_t *page);
|
||||
@brief A collection of pages through which generic allocations can
|
||||
occur.
|
||||
|
||||
@details Structure which maintains a linked list of pages (with a
|
||||
reference to the beginning and end of it).
|
||||
@details Collection of pages maintained through a vector of
|
||||
pointers to pages.
|
||||
|
||||
@prop[beg] Beginning of linked list of pages
|
||||
@prop[end] End of linked list of pages
|
||||
@prop[pages] Number of pages allocated in heap
|
||||
@prop[page_vec] Vector of pages
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
page_t *beg, *end;
|
||||
size_t pages;
|
||||
darr_t page_vec;
|
||||
} heap_t;
|
||||
|
||||
/**
|
||||
|
||||
13
vm/struct.c
13
vm/struct.c
@@ -14,6 +14,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./struct.h"
|
||||
#include "lib/darr.h"
|
||||
|
||||
void vm_load_stack(vm_t *vm, byte_t *bytes, size_t size)
|
||||
{
|
||||
@@ -180,17 +181,18 @@ void vm_print_program(vm_t *vm, FILE *fp)
|
||||
|
||||
void vm_print_heap(vm_t *vm, FILE *fp)
|
||||
{
|
||||
heap_t heap = vm->heap;
|
||||
fprintf(fp, "Heap.pages = %lu\nHeap.data = [", heap.pages);
|
||||
if (heap.pages == 0)
|
||||
heap_t heap = vm->heap;
|
||||
const size_t heap_pages = heap.page_vec.used / sizeof(page_t *);
|
||||
fprintf(fp, "Heap.pages = %lu\nHeap.data = [", heap_pages);
|
||||
if (heap_pages == 0)
|
||||
{
|
||||
fprintf(fp, "]\n");
|
||||
return;
|
||||
}
|
||||
page_t *cur = heap.beg;
|
||||
fprintf(fp, "\n");
|
||||
for (size_t i = 0; i < heap.pages; ++i)
|
||||
for (size_t i = 0; i < heap_pages; ++i)
|
||||
{
|
||||
page_t *cur = DARR_AT(page_t *, heap.page_vec.data, i);
|
||||
fprintf(fp, "\t[%lu]@%p: ", i, (void *)cur);
|
||||
if (!cur)
|
||||
fprintf(fp, "<NIL>\n");
|
||||
@@ -206,7 +208,6 @@ void vm_print_heap(vm_t *vm, FILE *fp)
|
||||
fprintf(fp, ",\t");
|
||||
}
|
||||
fprintf(fp, "\n\t}\n");
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
fprintf(fp, "]\n");
|
||||
|
||||
Reference in New Issue
Block a user