From 8dfd996cdf40d3458b169039a4541c41a7b54d1a Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 29 Jul 2025 20:18:02 -0500 Subject: [PATCH] buddy refactor --- src/base/base_buddy.c | 182 ++++++++++++++++++++++++------------------ src/base/base_buddy.h | 34 ++++++-- src/net/net_core.c | 8 +- 3 files changed, 134 insertions(+), 90 deletions(-) diff --git a/src/base/base_buddy.c b/src/base/base_buddy.c index bd866161..8a187a9c 100644 --- a/src/base/base_buddy.c +++ b/src/base/base_buddy.c @@ -1,10 +1,9 @@ /* TODO: Elminiate meta arena. Just store levels in first 4096 bytes of buddy arena, and then zone header data at the beginning of each allocation. */ -/* ========================== * - * Ctx - * ========================== */ +//////////////////////////////// +//~ Buddy ctx -BuddyCtx *buddy_ctx_alloc(u64 reserve) +BuddyCtx *AllocBuddyCtx(u64 reserve) { /* TODO: Determine meta reserve dynamically */ Arena *meta_arena = AllocArena(GIBI(64)); @@ -14,7 +13,8 @@ BuddyCtx *buddy_ctx_alloc(u64 reserve) /* TODO: Minimum block size */ ctx->levels = PushArray(ctx->meta_arena, BuddyLevel, 64); - for (u64 i = 0; i < 64; ++i) { + for (u64 i = 0; i < 64; ++i) + { BuddyLevel *level = &ctx->levels[i]; level->ctx = ctx; level->tier = i; @@ -24,81 +24,151 @@ BuddyCtx *buddy_ctx_alloc(u64 reserve) return ctx; } -void buddy_ctx_release(BuddyCtx *ctx) +void ReleaseBuddyCtx(BuddyCtx *ctx) { ReleaseArena(ctx->data_arena); ReleaseArena(ctx->meta_arena); } -/* ========================== * - * Block - * ========================== */ +//////////////////////////////// +//~ Block alloc / release -INTERNAL BuddyBlock *buddy_block_alloc_internal(BuddyCtx *ctx) +BuddyBlock *AllocBuddyBlock(BuddyCtx *ctx, u64 size) +{ + if (size > 0x00FFFFFFFFFFFFFFULL) + { + /* TODO: Error */ + ASSERT(0); + } + + /* TODO: Minimum block size */ + + /* TODO: Faster MSB calculation */ + + u64 desired_block_size = 1; + u64 desired_level_tier = 0; + while (desired_block_size < size && desired_level_tier < 64) + { + desired_block_size <<= 1; + ++desired_level_tier; + } + + BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]); + + return block; +} + +void ReleaseBuddyBlock(BuddyBlock *block) +{ + block->is_used = 0; + BuddyLevel *level = block->level; + BuddyBlock *parent = block->parent; + BuddyBlock *sibling = block->sibling; + if (!sibling->is_used && parent != 0) + { + /* Merge siblings */ + BuddyCtx *ctx = level->ctx; + PopBuddyBlock(ctx, level, block); + PopBuddyBlock(ctx, level, sibling); + /* Release parent */ + ReleaseBuddyBlock(parent); + } + else + { + if (level->first_unused_block) + { + block->next = level->first_unused_block; + level->first_unused_block->prev = block; + } + level->first_unused_block = block; + } +} + +//////////////////////////////// +//~ Block push / pop + +//- Push +BuddyBlock *PushBuddyBlock(BuddyCtx *ctx) { BuddyBlock *block; - if (ctx->first_free_block) { + if (ctx->first_free_block) + { block = ctx->first_free_block; ctx->first_free_block = block->next; - } else { + } + else + { block = PushStructNoZero(ctx->meta_arena, BuddyBlock); } MEMZERO_STRUCT(block); return block; } -INTERNAL void buddy_block_release_internal(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block) +//- Pop +void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block) { /* Remove from unused list */ { BuddyBlock *prev = block->prev; BuddyBlock *next = block->next; - if (prev) { + if (prev) + { prev->next = next; - } else { + } + else + { level->first_unused_block = next; } - if (next) { + if (next) + { next->prev = prev; } } - block->next = ctx->first_free_block; ctx->first_free_block = block; } -INTERNAL BuddyBlock *buddy_block_get_unused(BuddyCtx *ctx, BuddyLevel *level) +//////////////////////////////// +//~ Get unused block + +BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level) { BuddyBlock *block = 0; /* TODO: Tier oob check */ - if (level->first_unused_block) { + if (level->first_unused_block) + { block = level->first_unused_block; level->first_unused_block = block->next; - if (level->first_unused_block) { + if (level->first_unused_block) + { level->first_unused_block->prev = 0; } block->is_used = 1; block->next = 0; - } else { - if (level->backed) { + } + else + { + if (level->backed) + { BuddyLevel *parent_level = &ctx->levels[level->tier + 1]; - BuddyBlock *parent_block = buddy_block_get_unused(ctx, parent_level); + BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level); /* Create left (used) block from parent block */ - BuddyBlock *left = buddy_block_alloc_internal(ctx); + BuddyBlock *left = PushBuddyBlock(ctx); left->is_used = 1; left->level = level; left->parent = parent_block; left->memory = parent_block->memory; /* Create right (unused) block from parent block */ - BuddyBlock *right = buddy_block_alloc_internal(ctx); + BuddyBlock *right = PushBuddyBlock(ctx); right->is_used = 0; right->level = level; right->parent = parent_block; right->memory = left->memory + level->size; - if (level->first_unused_block) { + if (level->first_unused_block) + { right->next = level->first_unused_block; level->first_unused_block->prev = right; } @@ -107,24 +177,27 @@ INTERNAL BuddyBlock *buddy_block_get_unused(BuddyCtx *ctx, BuddyLevel *level) left->sibling = right; right->sibling = left; block = left; - } else { + } + else + { Arena *arena = ctx->data_arena; /* Grow arena */ i64 level_commit_diff = (level->size * 2) - arena->pos; - if (level_commit_diff > 0) { + if (level_commit_diff > 0) + { PushArrayNoZero(arena, u8, level_commit_diff); ASSERT(arena->pos == (level->size * 2)); } /* Create left (used) block from existing child block memory */ - BuddyBlock *left = buddy_block_alloc_internal(ctx); + BuddyBlock *left = PushBuddyBlock(ctx); left->is_used = 1; left->level = level; left->memory = ArenaBase(arena); /* Create right (unused) block from new arena memory */ - BuddyBlock *right = buddy_block_alloc_internal(ctx); + BuddyBlock *right = PushBuddyBlock(ctx); right->is_used = 0; right->level = level; right->memory = left->memory + level->size; @@ -139,52 +212,3 @@ INTERNAL BuddyBlock *buddy_block_get_unused(BuddyCtx *ctx, BuddyLevel *level) return block; } - -INTERNAL void buddy_block_mark_unused(BuddyBlock *block) -{ - block->is_used = 0; - BuddyLevel *level = block->level; - BuddyBlock *parent = block->parent; - BuddyBlock *sibling = block->sibling; - if (!sibling->is_used && parent != 0) { - /* Merge siblings */ - BuddyCtx *ctx = level->ctx; - buddy_block_release_internal(ctx, level, block); - buddy_block_release_internal(ctx, level, sibling); - buddy_block_mark_unused(parent); - } else { - if (level->first_unused_block) { - block->next = level->first_unused_block; - level->first_unused_block->prev = block; - } - level->first_unused_block = block; - } -} - -BuddyBlock *buddy_alloc(BuddyCtx *ctx, u64 size) -{ - if (size > 0x00FFFFFFFFFFFFFFULL) { - /* TODO: Error */ - ASSERT(0); - } - - /* TODO: Minimum block size */ - - /* TODO: Faster MSB calculation */ - - u64 desired_block_size = 1; - u64 desired_level_tier = 0; - while (desired_block_size < size && desired_level_tier < 64) { - desired_block_size <<= 1; - ++desired_level_tier; - } - - BuddyBlock *block = buddy_block_get_unused(ctx, &ctx->levels[desired_level_tier]); - - return block; -} - -void buddy_release(BuddyBlock *block) -{ - buddy_block_mark_unused(block); -} diff --git a/src/base/base_buddy.h b/src/base/base_buddy.h index a8496dbe..bd7b164b 100644 --- a/src/base/base_buddy.h +++ b/src/base/base_buddy.h @@ -1,4 +1,8 @@ -Struct(BuddyBlock) { +//////////////////////////////// +//~ Buddy types + +Struct(BuddyBlock) +{ b32 is_used; struct BuddyLevel *level; BuddyBlock *parent; @@ -11,7 +15,8 @@ Struct(BuddyBlock) { u8 *memory; }; -Struct(BuddyLevel) { +Struct(BuddyLevel) +{ struct BuddyCtx *ctx; b32 backed; /* Signals whether this level is backed by memory in the ctx arena */ u32 tier; @@ -19,15 +24,30 @@ Struct(BuddyLevel) { BuddyBlock *first_unused_block; }; -Struct(BuddyCtx) { +Struct(BuddyCtx) +{ Arena *meta_arena; Arena *data_arena; BuddyLevel *levels; BuddyBlock *first_free_block; }; -BuddyCtx *buddy_ctx_alloc(u64 reserve); -void buddy_ctx_release(BuddyCtx *ctx); +//////////////////////////////// +//~ Buddy context operations -BuddyBlock *buddy_alloc(BuddyCtx *ctx, u64 size); -void buddy_release(BuddyBlock *block); +BuddyCtx *AllocBuddyCtx(u64 reserve); +void ReleaseBuddyCtx(BuddyCtx *ctx); + +//////////////////////////////// +//~ Buddy block operations + +//- Alloc / release +BuddyBlock *AllocBuddyBlock(BuddyCtx *ctx, u64 size); +void ReleaseBuddyBlock(BuddyBlock *block); + +//- Push / pop +BuddyBlock *PushBuddyBlock(BuddyCtx *ctx); +void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block); + +//- Get unused +BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level); diff --git a/src/net/net_core.c b/src/net/net_core.c index 01e5db55..469f7ef4 100644 --- a/src/net/net_core.c +++ b/src/net/net_core.c @@ -149,7 +149,7 @@ N_Host *host_alloc(u16 listen_port) host->rcv_buffer_write = PushStruct(host->arena, N_RcvBuffer); host->rcv_buffer_read->arena = AllocArena(GIBI(64)); host->rcv_buffer_write->arena = AllocArena(GIBI(64)); - host->buddy = buddy_ctx_alloc(GIBI(64)); + host->buddy = AllocBuddyCtx(GIBI(64)); host->channels = PushDry(host->channel_arena, struct host_channel); @@ -168,7 +168,7 @@ void host_release(N_Host *host) { P_ReleaseSock(host->sock); - buddy_ctx_release(host->buddy); + ReleaseBuddyCtx(host->buddy); ReleaseArena(host->rcv_buffer_write->arena); ReleaseArena(host->rcv_buffer_read->arena); ReleaseArena(host->channel_arena); @@ -368,7 +368,7 @@ INTERNAL struct host_msg_assembler *host_msg_assembler_alloc(struct host_channel /* Allocate msg data using buddy allocator since the assembler has * arbitrary lifetime and data needs to stay contiguous for random * access as packets are received */ - ma->buddy_block = buddy_alloc(host->buddy, chunk_bitmap_size + chunk_data_size); + ma->buddy_block = AllocBuddyBlock(host->buddy, chunk_bitmap_size + chunk_data_size); ma->chunk_bitmap = ma->buddy_block->memory; MEMZERO(ma->chunk_bitmap, chunk_bitmap_size); ma->chunk_data = ma->chunk_bitmap + chunk_bitmap_size; @@ -405,7 +405,7 @@ INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma) { struct host_channel *channel = ma->channel; N_Host *host = channel->host; - buddy_release(ma->buddy_block); + ReleaseBuddyBlock(ma->buddy_block); /* Release from channel list */ {