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)
{
// setup the global arena
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
// parse all files passed to the command line
MD_b32 failed_parse = 0;
+1 -1
View File
@@ -14,7 +14,7 @@ static MD_Arena *arena = 0;
int
main(int argc, char **argv){
// setup the global arena
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
// parse a string
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)
{
// setup the global arena
// @notes This code makes an arena with a 1 terabyte reserve which works as
// long as we only have one or a few arenas.
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
// parse all files passed to the command line
MD_Node *list = MD_MakeList(arena);
+1 -1
View File
@@ -57,7 +57,7 @@ int
main(int argc, char **argv)
{
// setup the global arena
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
// parse all files passed to the command line
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)
{
// setup the global arena
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
// parse all files passed to the command line
MD_Node *list = MD_MakeList(arena);
+164 -57
View File
@@ -181,9 +181,10 @@ MD_WIN32_Reserve(MD_u64 size){
return(result);
}
static void
static MD_b32
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
@@ -309,9 +310,10 @@ MD_LINUX_Reserve(MD_u64 size){
return(result);
}
static void
static MD_b32
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
@@ -333,6 +335,15 @@ MD_LINUX_Release(void *ptr, MD_u64 size){
#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
#if !defined(MD_IMPL_Reserve)
# error Missing implementation for MD_IMPL_Reserve
@@ -348,66 +359,165 @@ MD_LINUX_Release(void *ptr, MD_u64 size){
#endif
#define MD_IMPL_ArenaHeaderSize 64
#define MD_ArenaDefault_CommitSize (1 << 20)
MD_StaticAssert(sizeof(MD_ArenaDefault) <= MD_IMPL_ArenaHeaderSize, arena_def_size_check);
#define MD_IMPL_ArenaAlloc MD_ArenaDefaultAlloc
#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_ArenaPopTo MD_ArenaDefaultPopTo
#define MD_IMPL_ArenaSetAutoAlign(a,b) ((a)->align = (b))
#define MD_IMPL_ArenaSetAutoAlign MD_ArenaDefaultSetAutoAlign
static MD_Arena*
MD_ArenaDefaultAlloc(MD_u64 cap){
void *mem = MD_IMPL_Reserve(cap);
MD_u64 cmt = MD_ClampTop(cap, MD_ArenaDefault_CommitSize);
MD_IMPL_Commit(mem, cmt);
MD_ArenaDefault *arena = (MD_ArenaDefault*)mem;
arena->pos = MD_IMPL_ArenaHeaderSize;
arena->cmt = cmt;
arena->cap = cap;
arena->align = sizeof(void*);
return((MD_Arena*)arena);
}
static void
MD_ArenaDefaultRelease(MD_Arena *arena_opq){
MD_ArenaDefault *arena = (MD_ArenaDefault*)arena_opq;
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;
}
static MD_ArenaDefault*
MD_ArenaDefaultAlloc__Size(MD_u64 cmt, MD_u64 res)
{
MD_Assert(MD_IMPL_ArenaHeaderSize < cmt && cmt <= res);
MD_u64 cmt_clamped = MD_ClampTop(cmt, res);
MD_ArenaDefault *result = 0;
void *mem = MD_IMPL_Reserve(res);
if (MD_IMPL_Commit(mem, cmt_clamped))
{
result = (MD_ArenaDefault*)mem;
result->prev = 0;
result->current = result;
result->base_pos = 0;
result->pos = MD_IMPL_ArenaHeaderSize;
result->cmt = cmt_clamped;
result->cap = res;
result->align = 8;
}
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
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);
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
@@ -441,9 +551,6 @@ MD_ArenaDefaultPopTo(MD_ArenaDefault *arena, MD_u64 pos){
#if MD_DEFAULT_SCRATCH
#if !defined(MD_IMPL_ScratchSize)
# define MD_IMPL_ScratchSize (1llu << 30)
#endif
#if !defined(MD_IMPL_ScratchCount)
# define MD_IMPL_ScratchCount 2llu
#endif
@@ -460,7 +567,7 @@ MD_GetScratchDefault(MD_Arena **conflicts, MD_u64 count){
if (scratch_pool[0] == 0){
MD_Arena **arena_ptr = scratch_pool;
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;
@@ -519,8 +626,8 @@ static MD_Node _md_nil_node =
//~ Arena Functions
MD_FUNCTION MD_Arena*
MD_ArenaAlloc(MD_u64 cap){
return(MD_IMPL_ArenaAlloc(cap));
MD_ArenaAlloc(void){
return(MD_IMPL_ArenaAlloc());
}
MD_FUNCTION void
+8 -4
View File
@@ -24,13 +24,13 @@
**
** "low level memory" ** OPTIONAL (required for default arena)
** #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_Release (void*, MD_u64) -> void
**
** "arena" ** REQUIRED (default implementation available)
** #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_ArenaGetPos (MD_IMPL_Arena*) -> MD_u64
** #define MD_IMPL_ArenaPush (MD_IMPL_Arena*, MD_u64) -> void*
@@ -41,7 +41,6 @@
** "scratch" ** REQUIRED (default implementation available)
** #define MD_IMPL_GetScratch (MD_IMPL_Arena**, MD_u64) -> MD_IMPL_Arena*
** "scratch constants" ** OPTIONAL (required for default scratch)
** #define MD_IMPL_ScratchSize MD_u64 / default 1 gigabyte
** #define MD_IMPL_ScratchCount MD_u64 / default 2
**
** Default Implementation Controls
@@ -332,6 +331,8 @@
#define MD_ClampBot(a,b) MD_Max(a,b)
#define MD_ClampTop(a,b) MD_Min(a,b)
#define MD_AlignPow2(x,b) (((x)+((b)-1))&(~((b)-1)))
//~ Linked List Macros.
// terminator modes
@@ -416,6 +417,9 @@ typedef double MD_f64;
typedef struct MD_ArenaDefault MD_ArenaDefault;
struct MD_ArenaDefault{
MD_ArenaDefault *prev;
MD_ArenaDefault *current;
MD_u64 base_pos;
MD_u64 pos;
MD_u64 cmt;
MD_u64 cap;
@@ -881,7 +885,7 @@ struct MD_FileIter
//~ 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_ArenaPush(MD_Arena *arena, MD_u64 size);
+1 -1
View File
@@ -7,7 +7,7 @@ static MD_Arena *arena = 0;
int main(void)
{
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
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
#undef X
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
/* NOTE: Operator table bake errors */ {
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)
{
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
Test("Lexer")
{
+1 -1
View File
@@ -16,7 +16,7 @@ void run_test_on_string(MD_String8 string)
int main(void)
{
arena = MD_ArenaAlloc(1ull << 40);
arena = MD_ArenaAlloc();
// TODO(allen): throw more at this.