From 8c0a8bf72b60af8baced957809e049a3ee665106 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 1 Jan 2023 10:48:06 +0100 Subject: [PATCH] Working on simplifying the allocation scheme --- base.cpp | 46 ++++++++-------- base_unicode.cpp | 10 ++-- build.bat | 4 +- core_arena.cpp | 138 +++++++++++++++++++++++++++------------------- core_compiler.cpp | 5 +- core_compiler.h | 6 +- core_globals.cpp | 2 +- core_lexing.cpp | 12 ++-- core_main.cpp | 1 + 9 files changed, 126 insertions(+), 98 deletions(-) diff --git a/base.cpp b/base.cpp index c4b4998..a09ff30 100644 --- a/base.cpp +++ b/base.cpp @@ -415,7 +415,7 @@ operator!=(Intern_String a, Intern_String b){ #define allocate_array(a, T, size,...) (T *)allocate_size(a, sizeof(T)*(size),##__VA_ARGS__) #define allocate_struct(a, T, ...) allocate_array(a, T, 1,##__VA_ARGS__) CORE_Static void *allocate_size(Allocator *allocator, size_t size, bool zero_memory = true) { - void *result = allocator->allocate(allocator, size); +void *result = allocator->allocate(allocator, size); if (zero_memory) { memory_zero(result, size); } @@ -517,6 +517,17 @@ arena_init(Arena *a, String debug_name){ a->deallocate = (Allocator::Deallocate *)deallocate_stub; } +CORE_Static Arena +arena_sub(Arena *base, size_t size, String debug_name) { + Arena result = {}; + result.memory.data = (U8 *)arena_push_size(base, size); + result.memory.commit = size; + result.memory.reserve = size; + result.alignment = default_alignment; + result.len = 0; + return result; +} + enum Log_Kind{Log_Kind_Normal_No_NewLine, Log_Kind_Normal, Log_Kind_Error, Log_Kind_Trace}; typedef void Log_Proc(Log_Kind kind, String string, char *file, int line); //----------------------------------------------------------------------------- @@ -652,7 +663,7 @@ struct Array{ cap = size; } - Array copy(Arena *a){ + Array copy(Allocator *a){ Array result = {}; result.len = len; result.cap = len*2; @@ -662,7 +673,7 @@ struct Array{ return result; } - Array tight_copy(Arena *a){ + Array tight_copy(Allocator *a){ Array result = {}; result.len = len; result.cap = len; @@ -952,17 +963,6 @@ test_intern_table(){ assert(intern3.str != intern2.str); } -CORE_Static Arena -arena_sub(Arena *base, size_t size, String debug_name) { - Arena result = {}; - result.memory.data = (U8 *)arena_push_size(base, size); - result.memory.commit = size; - result.memory.reserve = size; - result.alignment = default_alignment; - result.len = 0; - return result; -} - //----------------------------------------------------------------------------- // Array List // @todo(krzosa): If even one item got removed from block @@ -990,21 +990,23 @@ struct List{ }; template -List_Node *list_allocate_node(Arena *arena, int size){ - auto node = (List_Node *)arena_push_size(arena, sizeof(List_Node) + size*sizeof(T)); +List_Node *list_allocate_node(Allocator *arena, int size){ + auto node = (List_Node *)allocate_size(arena, sizeof(List_Node) + size*sizeof(T), false); node->cap = size; node->len = 0; + node->next = 0; + node->prev = 0; return node; } template -void list_allocate_free_node(Arena *arena, List *list, int size){ +void list_allocate_free_node(Allocator *arena, List *list, int size){ List_Node *node = list_allocate_node(arena, size); DLL_STACK_ADD(list->first_free, node); } template -void list_make_sure_there_is_room_for_item_count(Arena *arena, List *list, int item_count){ +void list_make_sure_there_is_room_for_item_count(Allocator *arena, List *list, int item_count){ if(list->last == 0 || list->last->len + item_count > list->last->cap){ // Not enough space we need to get a new block List_Node *node = 0; @@ -1064,13 +1066,13 @@ T get(List *list, int index){ } template -void add(Arena *arena, List *list, T item){ +void add(Allocator *arena, List *list, T item){ list_make_sure_there_is_room_for_item_count(arena, list, 1); list->last->data[list->last->len++] = item; } template -T *add_size(Arena *arena, List *list, int count = 1, int zero_memory = 0){ +T *add_size(Allocator *arena, List *list, int count = 1, int zero_memory = 0){ list_make_sure_there_is_room_for_item_count(arena, list, count); T *result = list->last->data + list->last->len; list->last->len += count; @@ -1183,9 +1185,9 @@ T pop(List *list){ } template -T *merge(Arena *arena, List *list){ +T *merge(Allocator *arena, List *list){ int len = length(list); - T *result = arena_push_array(arena, T, len); + T *result = allocate_size(arena, T, len, false); int i = 0; For_Linked_List(list->first){ diff --git a/base_unicode.cpp b/base_unicode.cpp index 2593ca2..bd30322 100644 --- a/base_unicode.cpp +++ b/base_unicode.cpp @@ -159,7 +159,7 @@ utf16_to_utf32(U16 *c, S32 max_advance) { } CORE_Static String32 -string16_to_string32(Arena *allocator, String16 string){ +string16_to_string32(Allocator *allocator, String16 string){ String32 result = {allocate_array(allocator, U32, string.len+1)}; for(S64 i = 0; i < string.len;){ UTF32_Result decode = utf16_to_utf32(string.str + i, string.len - i); @@ -175,7 +175,7 @@ string16_to_string32(Arena *allocator, String16 string){ } CORE_Static String32 -string8_to_string32(Arena *allocator, String string){ +string8_to_string32(Allocator *allocator, String string){ String32 result = {allocate_array(allocator, U32, string.len+1)}; for(S64 i = 0; i < string.len;){ UTF32_Result decode = utf8_to_utf32(string.str + i, string.len - i); @@ -190,7 +190,7 @@ string8_to_string32(Arena *allocator, String string){ } CORE_Static String16 -string8_to_string16(Arena *allocator, String in){ +string8_to_string16(Allocator *allocator, String in){ String16 result = {allocate_array(allocator, U16, (in.len*2)+1)}; // @Note(Krzosa): Should be more then enough space for(S64 i = 0; i < in.len;){ UTF32_Result decode = utf8_to_utf32(in.str + i, in.len - i); @@ -212,7 +212,7 @@ string8_to_string16(Arena *allocator, String in){ } CORE_Static String -string16_to_string8(Arena *allocator, String16 in){ +string16_to_string8(Allocator *allocator, String16 in){ String result = {allocate_array(allocator, U8, in.len*4+1)}; for(S64 i = 0; i < in.len;){ UTF32_Result decode = utf16_to_utf32(in.str + i, in.len - i); @@ -266,7 +266,7 @@ string16_from_widechar(wchar_t *string){ } CORE_Static String -string16_copy(Arena *a, String string){ +string16_copy(Allocator *a, String string){ U8 *copy = allocate_array(a, U8, string.len+1); memory_copy(copy, string.str, string.len); copy[string.len] = 0; diff --git a/build.bat b/build.bat index 5eeb352..f5bf5eb 100644 --- a/build.bat +++ b/build.bat @@ -4,10 +4,10 @@ set clang-flags=-O0 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-abs pushd %~dp0 rem cl main.cpp -I.. user32.lib -rem clang core_main.cpp %clang-flags% +clang core_main.cpp %clang-flags% rem ubuntu run clang core_main.cpp -O0 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-absolute-paths -g -o core.out -clang core_arena.cpp %clang-flags% +rem clang core_arena.cpp %clang-flags% rem clang test.cpp diff --git a/core_arena.cpp b/core_arena.cpp index a06de78..ac362cf 100644 --- a/core_arena.cpp +++ b/core_arena.cpp @@ -1,67 +1,97 @@ -#include "base.cpp" +constexpr size_t ARENA_BLOCK_SIZE = mib(1); +constexpr size_t ARENA_ALIGNMENT = 8; -struct Arena_Block { - Arena_Block *next; - Arena_Block *prev; - size_t cap; - size_t len; +struct Scratch_Arena : Allocator { + int cap, len; uint8_t memory[]; }; -constexpr size_t default_block_size = mib(1); -struct Arena_Block_Based : Allocator { - Arena_Block *first; - Arena_Block *last; - Arena_Block *first_free; - Allocator *block_allocator; - size_t alignment; +struct Scratch_Scope { + Scratch_Arena *arena; + int pos; + Scratch_Scope(Scratch_Arena *arena) { this->arena = arena; this->pos = arena->len; } + ~Scratch_Scope() { this->arena->len = this->pos; } }; -static void arena_add_block(Arena_Block_Based *arena, size_t min_size) { - Arena_Block *block = 0; - for (Arena_Block *it = arena->first_free; it; it = it->next) { - if (it->cap > min_size) { - block = it; - DLL_STACK_REMOVE(arena->first_free, it); - break; - } +static void *scratch_arena_push_size(Scratch_Arena *arena, size_t size) { + size_t generous_size = size + ARENA_ALIGNMENT; + if (arena->len + generous_size > arena->cap) { + assert(size < arena->cap); + assert_message(0, "Scratch arena is too small, failed to handle a request, capacity: %d, occupied: %d, allocation: %d", generous_size); + return 0; } - if (!block) { - block = (Arena_Block *)allocate_size(arena->block_allocator, sizeof(Arena_Block) + min_size + default_alignment, false); - block->cap = min_size + default_alignment; - } + size_t aligned_fill = align_up((size_t)arena->memory + arena->len, ARENA_ALIGNMENT) - (size_t)arena->memory; + assert(((int64_t)aligned_fill - (int64_t)arena->len) >= 0); + assert(((int64_t)aligned_fill - (int64_t)arena->len) <= ARENA_ALIGNMENT); + arena->len = aligned_fill; - block->len = 0; - block->next = 0; - block->prev = 0; - DLL_QUEUE_ADD(arena->first, arena->last, block); -} - -static void *block_arena_push_size(Arena_Block_Based *arena, size_t size) { - size_t generous_size = size + arena->alignment; - if (!arena->last || (arena->last->len + generous_size > arena->last->cap)) { - assert(arena->block_allocator); - size_t block_size = max(default_block_size, generous_size); - arena_add_block(arena, block_size); - } - - Arena_Block *L = arena->last; - size_t adjusted_len = align_up((size_t)L->memory + L->len, arena->alignment) - (size_t)L->memory; - assert(((int64_t)adjusted_len - (int64_t)L->len) > 0); - assert(((int64_t)adjusted_len - (int64_t)L->len) <= arena->alignment); - L->len = adjusted_len; - - uint8_t *result = L->memory + L->len; - L->len += size; + uint8_t *result = arena->memory + arena->len; + arena->len += size; return (void *)result; } -static Arena_Block_Based make_arena_block_based(Allocator *allocator) { - Arena_Block_Based result = {}; +static Scratch_Arena *allocate_scratch_arena(Allocator *allocator, size_t size_without_members) { + Scratch_Arena *scratch = (Scratch_Arena *)allocate_size(allocator, size_without_members + sizeof(Scratch_Arena), false); + scratch->cap = size_without_members; + scratch->len = 0; + scratch->allocate = (Allocator::Allocate *)scratch_arena_push_size; + scratch->deallocate = deallocate_stub; + return scratch; +} + +struct Push_Arena_Block { + Push_Arena_Block *next; + uint8_t memory[]; +}; + +struct Push_Arena : Allocator { + Allocator *block_allocator; + Push_Arena_Block *blocks; + size_t allocated_block_count; + size_t block_fill; + size_t wasted_memory; +}; + +static void push_arena_add_block(Push_Arena *arena) { + Push_Arena_Block *block = (Push_Arena_Block *)allocate_size(arena->block_allocator, sizeof(Push_Arena_Block) + ARENA_BLOCK_SIZE, false); + memory_zero(block, sizeof(Push_Arena_Block)); + SLL_STACK_ADD(arena->blocks, block); + if (arena->allocated_block_count) arena->wasted_memory += ARENA_BLOCK_SIZE - arena->block_fill; + arena->allocated_block_count += 1; + arena->block_fill = 0; +} + +static void push_arena_deallocate(Push_Arena *arena) { + for(Push_Arena_Block *it = arena->blocks; it; it = it->next) { + deallocate(arena->block_allocator, it); + } + memory_zero(arena, sizeof(*arena)); +} + +static void *push_arena_push_size(Push_Arena *arena, size_t size) { + assert(arena->block_allocator); + assert(size < ARENA_BLOCK_SIZE / 2); + size_t generous_size = size + ARENA_ALIGNMENT; + if (arena->blocks == 0 || (arena->block_fill + generous_size > ARENA_BLOCK_SIZE)) { + push_arena_add_block(arena); + } + + Push_Arena_Block *L = arena->blocks; + size_t aligned_fill = align_up((size_t)L->memory + arena->block_fill, ARENA_ALIGNMENT) - (size_t)L->memory; + assert(((int64_t)aligned_fill - (int64_t)arena->block_fill) >= 0); + assert(((int64_t)aligned_fill - (int64_t)arena->block_fill) <= ARENA_ALIGNMENT); + arena->block_fill = aligned_fill; + + uint8_t *result = L->memory + arena->block_fill; + arena->block_fill += size; + return (void *)result; +} + +static Push_Arena make_push_arena(Allocator *allocator) { + Push_Arena result = {}; result.block_allocator = allocator; - result.alignment = default_alignment; - result.allocate = (Allocator::Allocate *)block_arena_push_size; + result.allocate = (Allocator::Allocate *)push_arena_push_size; result.deallocate = (Allocator::Deallocate *)deallocate_stub; return result; } @@ -75,9 +105,3 @@ static CRT_Heap make_crt_heap() { result.deallocate = crt_deallocate; return result; } - -int main() { - CRT_Heap heap = make_crt_heap(); - Arena_Block_Based arena = make_arena_block_based(&heap); - void *result = allocate_size(&arena, 32); -} \ No newline at end of file diff --git a/core_compiler.cpp b/core_compiler.cpp index f079e52..314c551 100644 --- a/core_compiler.cpp +++ b/core_compiler.cpp @@ -1,8 +1,9 @@ CORE_Static void -core_init_compiler(Parse_Ctx *ctx, Arena *perm, Allocator *heap) { +core_init_compiler(Core_Ctx *ctx, Arena *perm, Allocator *heap) { ctx->init_ctx_time_begin = os_time(); pctx = ctx; + ctx->scratch = allocate_scratch_arena(perm, mib(1)); ctx->perm = perm; ctx->heap = heap; ctx->type_map = map_make(heap, 2048); @@ -95,7 +96,7 @@ core_init_compiler(Parse_Ctx *ctx, Arena *perm, Allocator *heap) { CORE_Static void core_bootstrap_compiler(Allocator *allocator) { - Parse_Ctx *ctx = allocate_struct(allocator, Parse_Ctx); + Core_Ctx *ctx = allocate_struct(allocator, Core_Ctx); assert((uintptr_t)allocator->allocate == (uintptr_t)arena_push_size); core_init_compiler(ctx, (Arena *)allocator, allocator); diff --git a/core_compiler.h b/core_compiler.h index 06259ec..cd15ff4 100644 --- a/core_compiler.h +++ b/core_compiler.h @@ -20,13 +20,13 @@ struct Lex_Stream{ Array indent_stack; }; -struct Parse_Ctx{ +struct Core_Ctx{ Arena *perm; // Stores: AST, tokens, interns Allocator *heap; + Scratch_Arena *scratch; + Arena stage_arena; - Arena _scratch; - Arena *scratch; // Lexer stuff Lex_Stream stream; diff --git a/core_globals.cpp b/core_globals.cpp index bb31b54..a807ff5 100644 --- a/core_globals.cpp +++ b/core_globals.cpp @@ -5,7 +5,7 @@ global B32 single_header_library_mode = false; global String single_header_library_name = ""_s; global bool color_codes_enabled; -thread_local Parse_Ctx *pctx; +thread_local Core_Ctx *pctx; Arena *bigint_allocator; diff --git a/core_lexing.cpp b/core_lexing.cpp index 189ee40..09d6e8d 100644 --- a/core_lexing.cpp +++ b/core_lexing.cpp @@ -56,7 +56,7 @@ lex_set_len(Lex_Stream *s, Token *token){ } CORE_Static void -lex_set_keywords(Parse_Ctx *lexer, Array keywords){ +lex_set_keywords(Core_Ctx *lexer, Array keywords){ Intern_String keyword = {}; For(keywords){ keyword = intern_string(&lexer->interns, it); @@ -79,7 +79,7 @@ token_error(Token *t, String error_val){ } CORE_Static void -lex_parse_u64(Parse_Ctx *lexer, Token *t, S64 base){ +lex_parse_u64(Core_Ctx *lexer, Token *t, S64 base){ Scratch scratch; Set_BigInt_Arena(scratch); @@ -175,7 +175,7 @@ lex_parse_ident(Intern_Table *table, Lex_Stream *s, Token *t){ break CORE_Static Token -token_make(Parse_Ctx *lexer, U8 *str, Intern_String file, int line, U8 *line_begin){ +token_make(Core_Ctx *lexer, U8 *str, Intern_String file, int line, U8 *line_begin){ Token t = {}; t.str = str; t.file = file; @@ -186,7 +186,7 @@ token_make(Parse_Ctx *lexer, U8 *str, Intern_String file, int line, U8 *line_beg } CORE_Static Token -token_make(Parse_Ctx *lexer){ +token_make(Core_Ctx *lexer){ return token_make(lexer, lexcp(&lexer->stream), lexer->stream.file, lexer->stream.line, lexer->stream.line_begin); } @@ -228,7 +228,7 @@ lex_unwind_indent_stack(Token *t, Lex_Stream *s, Array *array){ } CORE_Static void -lex__stream(Parse_Ctx *lexer){ +lex__stream(Core_Ctx *lexer){ Intern_Table *table = &lexer->interns; Array *array = &lexer->tokens; Lex_Stream *s = &lexer->stream; @@ -586,7 +586,7 @@ lex__stream(Parse_Ctx *lexer){ } CORE_Static void -lex_restream(Parse_Ctx *lexer, String istream, String file){ +lex_restream(Core_Ctx *lexer, String istream, String file){ lexer->stream = {}; lexer->stream.stream = istream; lexer->stream.line_begin = istream.str; diff --git a/core_main.cpp b/core_main.cpp index b1e1963..9f74d1a 100644 --- a/core_main.cpp +++ b/core_main.cpp @@ -259,6 +259,7 @@ For modules it's a bit different cause they should be distributed as valid. #include "base.cpp" #include "base_unicode.cpp" +#include "core_arena.cpp" #include "os.h" #if OS_WINDOWS #include "os_windows.cpp"