buddy refactor
This commit is contained in:
parent
deaa397709
commit
8dfd996cdf
@ -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. */
|
/* 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 */
|
/* TODO: Determine meta reserve dynamically */
|
||||||
Arena *meta_arena = AllocArena(GIBI(64));
|
Arena *meta_arena = AllocArena(GIBI(64));
|
||||||
@ -14,7 +13,8 @@ BuddyCtx *buddy_ctx_alloc(u64 reserve)
|
|||||||
|
|
||||||
/* TODO: Minimum block size */
|
/* TODO: Minimum block size */
|
||||||
ctx->levels = PushArray(ctx->meta_arena, BuddyLevel, 64);
|
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];
|
BuddyLevel *level = &ctx->levels[i];
|
||||||
level->ctx = ctx;
|
level->ctx = ctx;
|
||||||
level->tier = i;
|
level->tier = i;
|
||||||
@ -24,81 +24,151 @@ BuddyCtx *buddy_ctx_alloc(u64 reserve)
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void buddy_ctx_release(BuddyCtx *ctx)
|
void ReleaseBuddyCtx(BuddyCtx *ctx)
|
||||||
{
|
{
|
||||||
ReleaseArena(ctx->data_arena);
|
ReleaseArena(ctx->data_arena);
|
||||||
ReleaseArena(ctx->meta_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;
|
BuddyBlock *block;
|
||||||
if (ctx->first_free_block) {
|
if (ctx->first_free_block)
|
||||||
|
{
|
||||||
block = ctx->first_free_block;
|
block = ctx->first_free_block;
|
||||||
ctx->first_free_block = block->next;
|
ctx->first_free_block = block->next;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
|
block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(block);
|
MEMZERO_STRUCT(block);
|
||||||
return 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 */
|
/* Remove from unused list */
|
||||||
{
|
{
|
||||||
BuddyBlock *prev = block->prev;
|
BuddyBlock *prev = block->prev;
|
||||||
BuddyBlock *next = block->next;
|
BuddyBlock *next = block->next;
|
||||||
if (prev) {
|
if (prev)
|
||||||
|
{
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
level->first_unused_block = next;
|
level->first_unused_block = next;
|
||||||
}
|
}
|
||||||
if (next) {
|
if (next)
|
||||||
|
{
|
||||||
next->prev = prev;
|
next->prev = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block->next = ctx->first_free_block;
|
block->next = ctx->first_free_block;
|
||||||
ctx->first_free_block = 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;
|
BuddyBlock *block = 0;
|
||||||
|
|
||||||
/* TODO: Tier oob check */
|
/* TODO: Tier oob check */
|
||||||
if (level->first_unused_block) {
|
if (level->first_unused_block)
|
||||||
|
{
|
||||||
block = level->first_unused_block;
|
block = level->first_unused_block;
|
||||||
level->first_unused_block = block->next;
|
level->first_unused_block = block->next;
|
||||||
if (level->first_unused_block) {
|
if (level->first_unused_block)
|
||||||
|
{
|
||||||
level->first_unused_block->prev = 0;
|
level->first_unused_block->prev = 0;
|
||||||
}
|
}
|
||||||
block->is_used = 1;
|
block->is_used = 1;
|
||||||
block->next = 0;
|
block->next = 0;
|
||||||
} else {
|
}
|
||||||
if (level->backed) {
|
else
|
||||||
|
{
|
||||||
|
if (level->backed)
|
||||||
|
{
|
||||||
BuddyLevel *parent_level = &ctx->levels[level->tier + 1];
|
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 */
|
/* Create left (used) block from parent block */
|
||||||
BuddyBlock *left = buddy_block_alloc_internal(ctx);
|
BuddyBlock *left = PushBuddyBlock(ctx);
|
||||||
left->is_used = 1;
|
left->is_used = 1;
|
||||||
left->level = level;
|
left->level = level;
|
||||||
left->parent = parent_block;
|
left->parent = parent_block;
|
||||||
left->memory = parent_block->memory;
|
left->memory = parent_block->memory;
|
||||||
|
|
||||||
/* Create right (unused) block from parent block */
|
/* Create right (unused) block from parent block */
|
||||||
BuddyBlock *right = buddy_block_alloc_internal(ctx);
|
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||||
right->is_used = 0;
|
right->is_used = 0;
|
||||||
right->level = level;
|
right->level = level;
|
||||||
right->parent = parent_block;
|
right->parent = parent_block;
|
||||||
right->memory = left->memory + level->size;
|
right->memory = left->memory + level->size;
|
||||||
if (level->first_unused_block) {
|
if (level->first_unused_block)
|
||||||
|
{
|
||||||
right->next = level->first_unused_block;
|
right->next = level->first_unused_block;
|
||||||
level->first_unused_block->prev = right;
|
level->first_unused_block->prev = right;
|
||||||
}
|
}
|
||||||
@ -107,24 +177,27 @@ INTERNAL BuddyBlock *buddy_block_get_unused(BuddyCtx *ctx, BuddyLevel *level)
|
|||||||
left->sibling = right;
|
left->sibling = right;
|
||||||
right->sibling = left;
|
right->sibling = left;
|
||||||
block = left;
|
block = left;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Arena *arena = ctx->data_arena;
|
Arena *arena = ctx->data_arena;
|
||||||
|
|
||||||
/* Grow arena */
|
/* Grow arena */
|
||||||
i64 level_commit_diff = (level->size * 2) - arena->pos;
|
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);
|
PushArrayNoZero(arena, u8, level_commit_diff);
|
||||||
ASSERT(arena->pos == (level->size * 2));
|
ASSERT(arena->pos == (level->size * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create left (used) block from existing child block memory */
|
/* 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->is_used = 1;
|
||||||
left->level = level;
|
left->level = level;
|
||||||
left->memory = ArenaBase(arena);
|
left->memory = ArenaBase(arena);
|
||||||
|
|
||||||
/* Create right (unused) block from new arena memory */
|
/* Create right (unused) block from new arena memory */
|
||||||
BuddyBlock *right = buddy_block_alloc_internal(ctx);
|
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||||
right->is_used = 0;
|
right->is_used = 0;
|
||||||
right->level = level;
|
right->level = level;
|
||||||
right->memory = left->memory + level->size;
|
right->memory = left->memory + level->size;
|
||||||
@ -139,52 +212,3 @@ INTERNAL BuddyBlock *buddy_block_get_unused(BuddyCtx *ctx, BuddyLevel *level)
|
|||||||
|
|
||||||
return block;
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
Struct(BuddyBlock) {
|
////////////////////////////////
|
||||||
|
//~ Buddy types
|
||||||
|
|
||||||
|
Struct(BuddyBlock)
|
||||||
|
{
|
||||||
b32 is_used;
|
b32 is_used;
|
||||||
struct BuddyLevel *level;
|
struct BuddyLevel *level;
|
||||||
BuddyBlock *parent;
|
BuddyBlock *parent;
|
||||||
@ -11,7 +15,8 @@ Struct(BuddyBlock) {
|
|||||||
u8 *memory;
|
u8 *memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(BuddyLevel) {
|
Struct(BuddyLevel)
|
||||||
|
{
|
||||||
struct BuddyCtx *ctx;
|
struct BuddyCtx *ctx;
|
||||||
b32 backed; /* Signals whether this level is backed by memory in the ctx arena */
|
b32 backed; /* Signals whether this level is backed by memory in the ctx arena */
|
||||||
u32 tier;
|
u32 tier;
|
||||||
@ -19,15 +24,30 @@ Struct(BuddyLevel) {
|
|||||||
BuddyBlock *first_unused_block;
|
BuddyBlock *first_unused_block;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(BuddyCtx) {
|
Struct(BuddyCtx)
|
||||||
|
{
|
||||||
Arena *meta_arena;
|
Arena *meta_arena;
|
||||||
Arena *data_arena;
|
Arena *data_arena;
|
||||||
BuddyLevel *levels;
|
BuddyLevel *levels;
|
||||||
BuddyBlock *first_free_block;
|
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);
|
BuddyCtx *AllocBuddyCtx(u64 reserve);
|
||||||
void buddy_release(BuddyBlock *block);
|
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);
|
||||||
|
|||||||
@ -149,7 +149,7 @@ N_Host *host_alloc(u16 listen_port)
|
|||||||
host->rcv_buffer_write = PushStruct(host->arena, N_RcvBuffer);
|
host->rcv_buffer_write = PushStruct(host->arena, N_RcvBuffer);
|
||||||
host->rcv_buffer_read->arena = AllocArena(GIBI(64));
|
host->rcv_buffer_read->arena = AllocArena(GIBI(64));
|
||||||
host->rcv_buffer_write->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);
|
host->channels = PushDry(host->channel_arena, struct host_channel);
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ void host_release(N_Host *host)
|
|||||||
{
|
{
|
||||||
P_ReleaseSock(host->sock);
|
P_ReleaseSock(host->sock);
|
||||||
|
|
||||||
buddy_ctx_release(host->buddy);
|
ReleaseBuddyCtx(host->buddy);
|
||||||
ReleaseArena(host->rcv_buffer_write->arena);
|
ReleaseArena(host->rcv_buffer_write->arena);
|
||||||
ReleaseArena(host->rcv_buffer_read->arena);
|
ReleaseArena(host->rcv_buffer_read->arena);
|
||||||
ReleaseArena(host->channel_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
|
/* Allocate msg data using buddy allocator since the assembler has
|
||||||
* arbitrary lifetime and data needs to stay contiguous for random
|
* arbitrary lifetime and data needs to stay contiguous for random
|
||||||
* access as packets are received */
|
* 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;
|
ma->chunk_bitmap = ma->buddy_block->memory;
|
||||||
MEMZERO(ma->chunk_bitmap, chunk_bitmap_size);
|
MEMZERO(ma->chunk_bitmap, chunk_bitmap_size);
|
||||||
ma->chunk_data = 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;
|
struct host_channel *channel = ma->channel;
|
||||||
N_Host *host = channel->host;
|
N_Host *host = channel->host;
|
||||||
buddy_release(ma->buddy_block);
|
ReleaseBuddyBlock(ma->buddy_block);
|
||||||
|
|
||||||
/* Release from channel list */
|
/* Release from channel list */
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user