reserve-commit-chain arenas

This commit is contained in:
Allen Webster
2021-09-17 18:07:38 -07:00
parent cbd755852d
commit 0a07520fac
11 changed files with 181 additions and 72 deletions
@@ -36,7 +36,7 @@ static void CleanUp(void); // Runs at the end of generation.
int main(int argument_count, char **arguments) int main(int argument_count, char **arguments)
{ {
// setup the global arena // setup the global arena
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
// parse all files passed to the command line // parse all files passed to the command line
MD_b32 failed_parse = 0; MD_b32 failed_parse = 0;
+1 -1
View File
@@ -14,7 +14,7 @@ static MD_Arena *arena = 0;
int int
main(int argc, char **argv){ main(int argc, char **argv){
// setup the global arena // setup the global arena
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
// parse a string // parse a string
MD_String8 name = MD_S8Lit("<name>"); MD_String8 name = MD_S8Lit("<name>");
+1 -3
View File
@@ -22,9 +22,7 @@ static MD_Arena *arena = 0;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
// setup the global arena // setup the global arena
// @notes This code makes an arena with a 1 terabyte reserve which works as arena = MD_ArenaAlloc();
// long as we only have one or a few arenas.
arena = MD_ArenaAlloc(1ull << 40);
// parse all files passed to the command line // parse all files passed to the command line
MD_Node *list = MD_MakeList(arena); MD_Node *list = MD_MakeList(arena);
+1 -1
View File
@@ -57,7 +57,7 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
// setup the global arena // setup the global arena
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
// parse all files passed to the command line // parse all files passed to the command line
MD_Node *list = MD_MakeList(arena); MD_Node *list = MD_MakeList(arena);
+1 -1
View File
@@ -20,7 +20,7 @@ static MD_Arena *arena = 0;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
// setup the global arena // setup the global arena
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
// parse all files passed to the command line // parse all files passed to the command line
MD_Node *list = MD_MakeList(arena); MD_Node *list = MD_MakeList(arena);
+164 -57
View File
@@ -181,9 +181,10 @@ MD_WIN32_Reserve(MD_u64 size){
return(result); return(result);
} }
static void static MD_b32
MD_WIN32_Commit(void *ptr, MD_u64 size){ MD_WIN32_Commit(void *ptr, MD_u64 size){
VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE); MD_b32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0);
return(result);
} }
static void static void
@@ -309,9 +310,10 @@ MD_LINUX_Reserve(MD_u64 size){
return(result); return(result);
} }
static void static MD_b32
MD_LINUX_Commit(void *ptr, MD_u64 size){ MD_LINUX_Commit(void *ptr, MD_u64 size){
mprotect(ptr, size, PROT_READ|PROT_WRITE); MD_b32 result = (mprotect(ptr, size, PROT_READ|PROT_WRITE) == 0);
return(result);
} }
static void static void
@@ -333,6 +335,15 @@ MD_LINUX_Release(void *ptr, MD_u64 size){
#if MD_DEFAULT_ARENA #if MD_DEFAULT_ARENA
#if !defined(MD_DEFAULT_ARENA_RES_SIZE)
# define MD_DEFAULT_ARENA_RES_SIZE (64 << 20)
#endif
#if !defined(MD_DEFAULT_ARENA_CMT_SIZE)
# define MD_DEFAULT_ARENA_CMT_SIZE (64 << 10)
#endif
#define MD_DEFAULT_ARENA_VERY_BIG (MD_DEFAULT_ARENA_RES_SIZE - MD_IMPL_ArenaHeaderSize)/2
//- "low level memory" implementation check //- "low level memory" implementation check
#if !defined(MD_IMPL_Reserve) #if !defined(MD_IMPL_Reserve)
# error Missing implementation for MD_IMPL_Reserve # error Missing implementation for MD_IMPL_Reserve
@@ -348,66 +359,165 @@ MD_LINUX_Release(void *ptr, MD_u64 size){
#endif #endif
#define MD_IMPL_ArenaHeaderSize 64 #define MD_IMPL_ArenaHeaderSize 64
#define MD_ArenaDefault_CommitSize (1 << 20)
MD_StaticAssert(sizeof(MD_ArenaDefault) <= MD_IMPL_ArenaHeaderSize, arena_def_size_check); MD_StaticAssert(sizeof(MD_ArenaDefault) <= MD_IMPL_ArenaHeaderSize, arena_def_size_check);
#define MD_IMPL_ArenaAlloc MD_ArenaDefaultAlloc #define MD_IMPL_ArenaAlloc MD_ArenaDefaultAlloc
#define MD_IMPL_ArenaRelease MD_ArenaDefaultRelease #define MD_IMPL_ArenaRelease MD_ArenaDefaultRelease
#define MD_IMPL_ArenaGetPos(a) ((a)->pos) #define MD_IMPL_ArenaGetPos MD_ArenaDefaultGetPos
#define MD_IMPL_ArenaPush MD_ArenaDefaultPush #define MD_IMPL_ArenaPush MD_ArenaDefaultPush
#define MD_IMPL_ArenaPopTo MD_ArenaDefaultPopTo #define MD_IMPL_ArenaPopTo MD_ArenaDefaultPopTo
#define MD_IMPL_ArenaSetAutoAlign(a,b) ((a)->align = (b)) #define MD_IMPL_ArenaSetAutoAlign MD_ArenaDefaultSetAutoAlign
static MD_Arena* static MD_ArenaDefault*
MD_ArenaDefaultAlloc(MD_u64 cap){ MD_ArenaDefaultAlloc__Size(MD_u64 cmt, MD_u64 res)
void *mem = MD_IMPL_Reserve(cap); {
MD_u64 cmt = MD_ClampTop(cap, MD_ArenaDefault_CommitSize); MD_Assert(MD_IMPL_ArenaHeaderSize < cmt && cmt <= res);
MD_IMPL_Commit(mem, cmt); MD_u64 cmt_clamped = MD_ClampTop(cmt, res);
MD_ArenaDefault *result = 0;
MD_ArenaDefault *arena = (MD_ArenaDefault*)mem; void *mem = MD_IMPL_Reserve(res);
arena->pos = MD_IMPL_ArenaHeaderSize; if (MD_IMPL_Commit(mem, cmt_clamped))
arena->cmt = cmt; {
arena->cap = cap; result = (MD_ArenaDefault*)mem;
arena->align = sizeof(void*); result->prev = 0;
return((MD_Arena*)arena); result->current = result;
} result->base_pos = 0;
result->pos = MD_IMPL_ArenaHeaderSize;
static void result->cmt = cmt_clamped;
MD_ArenaDefaultRelease(MD_Arena *arena_opq){ result->cap = res;
MD_ArenaDefault *arena = (MD_ArenaDefault*)arena_opq; result->align = 8;
MD_u64 cap = arena->cap;
MD_IMPL_Release(arena, cap);
}
static void*
MD_ArenaDefaultPush(MD_ArenaDefault *arena, MD_u64 size){
void *result = 0;
MD_u8 *buf = (MD_u8*)arena;
if (arena->pos + size <= arena->cap){
MD_u64 pos = arena->pos;
MD_u64 pos_clamped = MD_ClampBot(MD_IMPL_ArenaHeaderSize, pos);
MD_u64 new_pos = pos_clamped + size;
MD_u64 align_m1 = arena->align - 1;
MD_u64 new_pos_aligned = (new_pos + align_m1)&(~align_m1);
MD_u64 new_pos_clamped = MD_ClampTop(new_pos_aligned, arena->cap);
result = buf + pos;
arena->pos = new_pos_aligned;
if (new_pos_clamped > arena->cmt){
MD_u64 cmt_amt_raw = new_pos_clamped - arena->cmt;
MD_u64 cmt_align_m1 = MD_ArenaDefault_CommitSize - 1;
MD_u64 cmt_amt = (cmt_amt_raw + cmt_align_m1)&(~cmt_align_m1);
MD_IMPL_Commit(buf + arena->cmt, cmt_amt);
arena->cmt += cmt_amt;
}
} }
return(result); return(result);
} }
static MD_ArenaDefault*
MD_ArenaDefaultAlloc(void)
{
MD_ArenaDefault *result = MD_ArenaDefaultAlloc__Size(MD_DEFAULT_ARENA_CMT_SIZE,
MD_DEFAULT_ARENA_RES_SIZE);
return(result);
}
static void static void
MD_ArenaDefaultPopTo(MD_ArenaDefault *arena, MD_u64 pos){ MD_ArenaDefaultRelease(MD_ArenaDefault *arena)
{
for (MD_ArenaDefault *node = arena->current, *prev = 0;
node != 0;
node = prev)
{
prev = node->prev;
MD_IMPL_Release(node, node->cap);
}
}
static MD_u64
MD_ArenaDefaultGetPos(MD_ArenaDefault *arena)
{
MD_ArenaDefault *current = arena->current;
MD_u64 result = current->base_pos + current->pos;
return(result);
}
static void*
MD_ArenaDefaultPush(MD_ArenaDefault *arena, MD_u64 size)
{
// try to be fast!
MD_ArenaDefault *current = arena->current;
MD_u64 align = arena->align;
MD_u64 pos = current->pos;
MD_u64 pos_aligned = MD_AlignPow2(pos, align);
MD_u64 new_pos = pos_aligned + size;
void *result = (MD_u8*)current + pos_aligned;
current->pos = new_pos;
// if it's not going to work do the slow path
if (new_pos > current->cmt){
result = 0;
current->pos = pos;
// new chunk if necessary
if (new_pos > current->cap)
{
MD_ArenaDefault *new_arena = 0;
if (size > MD_DEFAULT_ARENA_VERY_BIG)
{
MD_u64 big_size_unrounded = size + MD_IMPL_ArenaHeaderSize;
MD_u64 big_size = MD_AlignPow2(big_size_unrounded, (4 << 10));
new_arena = MD_ArenaDefaultAlloc__Size(big_size, big_size);
}
else
{
new_arena = MD_ArenaDefaultAlloc();
}
// link in new chunk & recompute new_pos
if (new_arena != 0)
{
new_arena->base_pos = current->base_pos + current->cap;
new_arena->prev = current;
current = new_arena;
pos_aligned = current->pos;
new_pos = pos_aligned + size;
}
}
// move ahead if the current chunk has enough reserve
if (new_pos <= current->cap)
{
// extend commit if necessary
if (new_pos > current->cmt)
{
MD_u64 new_cmt_unclamped = MD_AlignPow2(new_pos, MD_DEFAULT_ARENA_CMT_SIZE);
MD_u64 new_cmt = MD_ClampTop(new_cmt_unclamped, current->cap);
MD_u64 cmt_size = new_cmt - current->cmt;
if (MD_IMPL_Commit((MD_u8*)current + current->cmt, cmt_size))
{
current->cmt = new_cmt;
}
}
// move ahead if the current chunk has enough commit
if (new_pos <= current->cmt)
{
result = (MD_u8*)current + current->pos;
current->pos = new_pos;
}
}
}
return(result);
}
static void
MD_ArenaDefaultPopTo(MD_ArenaDefault *arena, MD_u64 pos)
{
// pop chunks in the chain
MD_u64 pos_clamped = MD_ClampBot(MD_IMPL_ArenaHeaderSize, pos); MD_u64 pos_clamped = MD_ClampBot(MD_IMPL_ArenaHeaderSize, pos);
arena->pos = pos_clamped; {
MD_ArenaDefault *node = arena->current;
for (MD_ArenaDefault *prev = 0;
node != 0 && node->base_pos >= pos;
node = prev)
{
prev = node->prev;
MD_IMPL_Release(node, node->cap);
}
arena->current = node;
}
// reset the pos of the current
{
MD_ArenaDefault *current = arena->current;
MD_u64 local_pos_unclamped = pos - current->base_pos;
MD_u64 local_pos = MD_ClampBot(local_pos_unclamped, MD_IMPL_ArenaHeaderSize);
current->pos = local_pos;
}
}
static void
MD_ArenaDefaultSetAutoAlign(MD_ArenaDefault *arena, MD_u64 align)
{
arena->align = align;
} }
#endif #endif
@@ -441,9 +551,6 @@ MD_ArenaDefaultPopTo(MD_ArenaDefault *arena, MD_u64 pos){
#if MD_DEFAULT_SCRATCH #if MD_DEFAULT_SCRATCH
#if !defined(MD_IMPL_ScratchSize)
# define MD_IMPL_ScratchSize (1llu << 30)
#endif
#if !defined(MD_IMPL_ScratchCount) #if !defined(MD_IMPL_ScratchCount)
# define MD_IMPL_ScratchCount 2llu # define MD_IMPL_ScratchCount 2llu
#endif #endif
@@ -460,7 +567,7 @@ MD_GetScratchDefault(MD_Arena **conflicts, MD_u64 count){
if (scratch_pool[0] == 0){ if (scratch_pool[0] == 0){
MD_Arena **arena_ptr = scratch_pool; MD_Arena **arena_ptr = scratch_pool;
for (MD_u64 i = 0; i < MD_IMPL_ScratchCount; i += 1, arena_ptr += 1){ for (MD_u64 i = 0; i < MD_IMPL_ScratchCount; i += 1, arena_ptr += 1){
*arena_ptr = MD_ArenaAlloc(MD_IMPL_ScratchSize); *arena_ptr = MD_ArenaAlloc();
} }
} }
MD_Arena *result = 0; MD_Arena *result = 0;
@@ -519,8 +626,8 @@ static MD_Node _md_nil_node =
//~ Arena Functions //~ Arena Functions
MD_FUNCTION MD_Arena* MD_FUNCTION MD_Arena*
MD_ArenaAlloc(MD_u64 cap){ MD_ArenaAlloc(void){
return(MD_IMPL_ArenaAlloc(cap)); return(MD_IMPL_ArenaAlloc());
} }
MD_FUNCTION void MD_FUNCTION void
+8 -4
View File
@@ -24,13 +24,13 @@
** **
** "low level memory" ** OPTIONAL (required for default arena) ** "low level memory" ** OPTIONAL (required for default arena)
** #define MD_IMPL_Reserve (MD_u64) -> void* ** #define MD_IMPL_Reserve (MD_u64) -> void*
** #define MD_IMPL_Commit (void*, MD_u64) -> void ** #define MD_IMPL_Commit (void*, MD_u64) -> MD_b32
** #define MD_IMPL_Decommit (void*, MD_u64) -> void ** #define MD_IMPL_Decommit (void*, MD_u64) -> void
** #define MD_IMPL_Release (void*, MD_u64) -> void ** #define MD_IMPL_Release (void*, MD_u64) -> void
** **
** "arena" ** REQUIRED (default implementation available) ** "arena" ** REQUIRED (default implementation available)
** #define MD_IMPL_Arena <type> ** #define MD_IMPL_Arena <type>
** #define MD_IMPL_ArenaAlloc (MD_u64) -> MD_IMPL_Arena* ** #define MD_IMPL_ArenaAlloc () -> MD_IMPL_Arena*
** #define MD_IMPL_ArenaRelease (MD_IMPL_Arena*) -> void ** #define MD_IMPL_ArenaRelease (MD_IMPL_Arena*) -> void
** #define MD_IMPL_ArenaGetPos (MD_IMPL_Arena*) -> MD_u64 ** #define MD_IMPL_ArenaGetPos (MD_IMPL_Arena*) -> MD_u64
** #define MD_IMPL_ArenaPush (MD_IMPL_Arena*, MD_u64) -> void* ** #define MD_IMPL_ArenaPush (MD_IMPL_Arena*, MD_u64) -> void*
@@ -41,7 +41,6 @@
** "scratch" ** REQUIRED (default implementation available) ** "scratch" ** REQUIRED (default implementation available)
** #define MD_IMPL_GetScratch (MD_IMPL_Arena**, MD_u64) -> MD_IMPL_Arena* ** #define MD_IMPL_GetScratch (MD_IMPL_Arena**, MD_u64) -> MD_IMPL_Arena*
** "scratch constants" ** OPTIONAL (required for default scratch) ** "scratch constants" ** OPTIONAL (required for default scratch)
** #define MD_IMPL_ScratchSize MD_u64 / default 1 gigabyte
** #define MD_IMPL_ScratchCount MD_u64 / default 2 ** #define MD_IMPL_ScratchCount MD_u64 / default 2
** **
** Default Implementation Controls ** Default Implementation Controls
@@ -332,6 +331,8 @@
#define MD_ClampBot(a,b) MD_Max(a,b) #define MD_ClampBot(a,b) MD_Max(a,b)
#define MD_ClampTop(a,b) MD_Min(a,b) #define MD_ClampTop(a,b) MD_Min(a,b)
#define MD_AlignPow2(x,b) (((x)+((b)-1))&(~((b)-1)))
//~ Linked List Macros. //~ Linked List Macros.
// terminator modes // terminator modes
@@ -416,6 +417,9 @@ typedef double MD_f64;
typedef struct MD_ArenaDefault MD_ArenaDefault; typedef struct MD_ArenaDefault MD_ArenaDefault;
struct MD_ArenaDefault{ struct MD_ArenaDefault{
MD_ArenaDefault *prev;
MD_ArenaDefault *current;
MD_u64 base_pos;
MD_u64 pos; MD_u64 pos;
MD_u64 cmt; MD_u64 cmt;
MD_u64 cap; MD_u64 cap;
@@ -881,7 +885,7 @@ struct MD_FileIter
//~ Arena //~ Arena
MD_FUNCTION MD_Arena* MD_ArenaAlloc(MD_u64 cap); MD_FUNCTION MD_Arena* MD_ArenaAlloc(void);
MD_FUNCTION void MD_ArenaRelease(MD_Arena *arena); MD_FUNCTION void MD_ArenaRelease(MD_Arena *arena);
MD_FUNCTION void* MD_ArenaPush(MD_Arena *arena, MD_u64 size); MD_FUNCTION void* MD_ArenaPush(MD_Arena *arena, MD_u64 size);
+1 -1
View File
@@ -7,7 +7,7 @@ static MD_Arena *arena = 0;
int main(void) int main(void)
{ {
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
printf("%d\n", MD_CPP_VERSION); printf("%d\n", MD_CPP_VERSION);
+1 -1
View File
@@ -201,7 +201,7 @@ operator_array[Op_##name].op = (MD_ExprOperator){ .op_id = Op_##name, .kind = MD
OPERATORS OPERATORS
#undef X #undef X
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
/* NOTE: Operator table bake errors */ { /* NOTE: Operator table bake errors */ {
MD_ExprOperatorList operator_list = {0}; MD_ExprOperatorList operator_list = {0};
+1 -1
View File
@@ -84,7 +84,7 @@ TokenMatch(MD_Token token, MD_String8 string, MD_TokenKind kind)
int main(void) int main(void)
{ {
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
Test("Lexer") Test("Lexer")
{ {
+1 -1
View File
@@ -16,7 +16,7 @@ void run_test_on_string(MD_String8 string)
int main(void) int main(void)
{ {
arena = MD_ArenaAlloc(1ull << 40); arena = MD_ArenaAlloc();
// TODO(allen): throw more at this. // TODO(allen): throw more at this.