mirror of
https://github.com/Ed94/metadesk.git
synced 2026-08-03 05:08:13 +00:00
frying my brain coming up with a decent compromise on arena usage...
This commit is contained in:
Vendored
+4
-1
@@ -21,6 +21,9 @@
|
|||||||
"os.h": "c",
|
"os.h": "c",
|
||||||
"os_core.h": "c",
|
"os_core.h": "c",
|
||||||
"file.h": "c",
|
"file.h": "c",
|
||||||
"xiosbase": "c"
|
"xiosbase": "c",
|
||||||
|
"iterator": "c",
|
||||||
|
"memory": "c",
|
||||||
|
"format": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+23
-122
@@ -11,134 +11,35 @@
|
|||||||
|
|
||||||
//- rjf: arena creation/destruction
|
//- rjf: arena creation/destruction
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal Arena*
|
|
||||||
arena_alloc_(ArenaParams *params)
|
|
||||||
{
|
|
||||||
// rjf: round up reserve/commit sizes
|
|
||||||
U64 reserve_size = params->reserve_size;
|
|
||||||
U64 commit_size = params->commit_size;
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: reserve/commit initial block
|
|
||||||
void *base = params->optional_backing_buffer;
|
|
||||||
if(base == 0)
|
|
||||||
{
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
|
||||||
base = os_reserve_large(reserve_size);
|
|
||||||
os_commit_large(base, commit_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base = os_reserve(reserve_size);
|
|
||||||
os_commit(base, commit_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: panic on arena creation failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
|
||||||
if(Unlikely(base == 0))
|
|
||||||
{
|
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
|
||||||
os_abort(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: extract arena header & fill
|
|
||||||
Arena *arena = (Arena *)base;
|
|
||||||
arena->current = arena;
|
|
||||||
arena->flags = params->flags;
|
|
||||||
arena->cmt_size = (U32)params->commit_size;
|
|
||||||
arena->res_size = params->reserve_size;
|
|
||||||
arena->base_pos = 0;
|
|
||||||
arena->pos = ARENA_HEADER_SIZE;
|
|
||||||
arena->cmt = commit_size;
|
|
||||||
arena->res = reserve_size;
|
|
||||||
AsanPoisonMemoryRegion(base, commit_size);
|
|
||||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Arena*
|
Arena*
|
||||||
arena_alloc_(ArenaParams* params)
|
arena_alloc_(ArenaParams* params)
|
||||||
{
|
{
|
||||||
// rjf: round up reserve/commit sizes
|
B32 is_virtual = false;
|
||||||
U64 reserve_size = params->reserve_size;
|
|
||||||
U64 commit_size = params->commit_size;
|
|
||||||
|
|
||||||
|
// This composite arena has the ability to decide a default behavior for allocation
|
||||||
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
void* base = alloc(params->backing, params->block_size);
|
||||||
{
|
|
||||||
reserve_size = align_pow2(reserve_size, os_get_system_info()->large_page_size);
|
|
||||||
commit_size = align_pow2(commit_size, os_get_system_info()->large_page_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reserve_size = align_pow2(reserve_size, os_get_system_info()->page_size);
|
|
||||||
commit_size = align_pow2(commit_size, os_get_system_info()->page_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: reserve/commit initial block
|
// rjf: panic on arena creation failure
|
||||||
void *base = params->optional_backing_buffer;
|
|
||||||
if(base == 0)
|
|
||||||
{
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
|
||||||
base = os_reserve_large(reserve_size);
|
|
||||||
os_commit_large(base, commit_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base = os_reserve(reserve_size);
|
|
||||||
os_commit(base, commit_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: panic on arena creation failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
#if OS_FEATURE_GRAPHICAL
|
||||||
if(Unlikely(base == 0))
|
if(unlikely(base == 0))
|
||||||
{
|
{
|
||||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
os_abort(1);
|
os_abort(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// rjf: extract arena header & fill
|
// rjf: extract arena header & fill
|
||||||
Arena *arena = (Arena *)base;
|
Arena* arena = (Arena*) base;
|
||||||
arena->current = arena;
|
arena->current = arena;
|
||||||
arena->flags = params->flags;
|
arena->backing = params->backing;
|
||||||
arena->cmt_size = (U32)params->commit_size;
|
arena->pos = size_of(Arena);
|
||||||
arena->res_size = params->reserve_size;
|
arena->block_size = params->block_size;
|
||||||
arena->base_pos = 0;
|
arena->flags = params->flags;
|
||||||
arena->pos = ARENA_HEADER_SIZE;
|
|
||||||
arena->cmt = commit_size;
|
|
||||||
arena->res = reserve_size;
|
|
||||||
AsanPoisonMemoryRegion(base, commit_size);
|
|
||||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
|
||||||
return arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note(Ed): INLINED
|
asan_unpoison_memory_region(base, sizeof(Arena));
|
||||||
// internal void
|
return arena;
|
||||||
// arena_release(Arena *arena)
|
}
|
||||||
// {
|
|
||||||
// for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
|
||||||
// {
|
|
||||||
// prev = n->prev;
|
|
||||||
// os_release(n, n->res);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
//- rjf: arena push/pop core functions
|
//- rjf: arena push/pop core functions
|
||||||
|
|
||||||
@@ -247,16 +148,16 @@ arena_pop(Arena *arena, U64 amt)
|
|||||||
|
|
||||||
//- rjf: temporary arena scopes
|
//- rjf: temporary arena scopes
|
||||||
|
|
||||||
internal Temp
|
internal TempArena
|
||||||
temp_begin(Arena *arena)
|
temp_begin(Arena *arena)
|
||||||
{
|
{
|
||||||
U64 pos = arena_pos(arena);
|
U64 pos = arena_pos(arena);
|
||||||
Temp temp = {arena, pos};
|
TempArena temp = {arena, pos};
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
temp_end(Temp temp)
|
temp_end(TempArena temp)
|
||||||
{
|
{
|
||||||
arena_pop_to(temp.arena, temp.pos);
|
arena_pop_to(temp.arena, temp.pos);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-19
@@ -19,17 +19,19 @@
|
|||||||
typedef U32 ArenaFlags;
|
typedef U32 ArenaFlags;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ArenaFlag_NoChain = ( 1 << 0),
|
// Don't chain this arena
|
||||||
ArenaFlag_LargePages = ( 1 << 1),
|
ArenaFlag_NoChain = (1 << 0),
|
||||||
|
// Only works if backing is virtual memory, will allocate a new backing VArena when the current block exhausts
|
||||||
|
// Otherwise will assume backing can chain multiple block_size arenas until failure.
|
||||||
|
ArenaFlag_ChainVirtual = (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ArenaParams ArenaParams;
|
typedef struct ArenaParams ArenaParams;
|
||||||
struct ArenaParams
|
struct ArenaParams
|
||||||
{
|
{
|
||||||
ArenaFlags flags;
|
AllocatorInfo backing;
|
||||||
U64 reserve_size;
|
ArenaFlags flags;
|
||||||
U64 commit_size;
|
U64 block_size; // If chaining VArenas set this to the reserve size
|
||||||
void* optional_backing_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NOTE(Ed): This is a combination of several concepts into a single interface:
|
/* NOTE(Ed): This is a combination of several concepts into a single interface:
|
||||||
@@ -44,18 +46,14 @@ struct ArenaParams
|
|||||||
typedef struct Arena Arena;
|
typedef struct Arena Arena;
|
||||||
struct Arena
|
struct Arena
|
||||||
{
|
{
|
||||||
AllocatorInfo backing;
|
|
||||||
Arena* prev; // previous arena in chain
|
Arena* prev; // previous arena in chain
|
||||||
Arena* current; // current arena in chain
|
Arena* current; // current arena in chain
|
||||||
ArenaFlags flags;
|
AllocatorInfo backing;
|
||||||
U32 cmt_size;
|
|
||||||
U64 res_size;
|
|
||||||
U64 base_pos;
|
|
||||||
U64 pos;
|
U64 pos;
|
||||||
U64 cmt;
|
U64 block_size;
|
||||||
U64 res;
|
ArenaFlags flags;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Arena) <= ARENA_HEADER_SIZE, "sizeof(Arena) <= MD_ARENA_HEADER_SIZE");
|
static_assert(size_of(Arena) <= ARENA_HEADER_SIZE, "sizeof(Arena) <= ARENA_HEADER_SIZE");
|
||||||
|
|
||||||
typedef struct TempArena TempArena;
|
typedef struct TempArena TempArena;
|
||||||
struct TempArena
|
struct TempArena
|
||||||
@@ -67,12 +65,12 @@ struct TempArena
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Functions
|
//~ rjf: Arena Functions
|
||||||
|
|
||||||
MD_API void* arena_allocator_proc(void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
|
MD_API void* arena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
//- rjf: arena creation/destruction
|
||||||
|
|
||||||
MD_API Arena* arena_alloc_(ArenaParams *params);
|
MD_API Arena* arena_alloc_(ArenaParams *params);
|
||||||
#define arena_alloc(...) arena_alloc_( & ( ArenaParams) { .reserve_size = MB(64), .commit_size = KB(64), __VA_ARGS__ } )
|
#define arena_alloc(...) arena_alloc_( & ( ArenaParams) { .backing = {}, .reserve_size = MB(64), .commit_size = KB(64), __VA_ARGS__ } )
|
||||||
|
|
||||||
void arena_release(Arena *arena);
|
void arena_release(Arena *arena);
|
||||||
|
|
||||||
@@ -109,9 +107,6 @@ arena_release(Arena* arena)
|
|||||||
for (Arena* n = arena->current, *prev = 0; n != 0; n = prev)
|
for (Arena* n = arena->current, *prev = 0; n != 0; n = prev)
|
||||||
{
|
{
|
||||||
prev = n->prev;
|
prev = n->prev;
|
||||||
// os_release(n, n->res);
|
|
||||||
alloc_free(arena->backing, n);
|
alloc_free(arena->backing, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -4,6 +4,7 @@
|
|||||||
# include "linkage.h"
|
# include "linkage.h"
|
||||||
# include "macros.h"
|
# include "macros.h"
|
||||||
# include "platform.h"
|
# include "platform.h"
|
||||||
|
# include "base_types.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -200,19 +201,19 @@ void* mem_move( void* destination, void const* source, SSIZE byte_count )
|
|||||||
{
|
{
|
||||||
if ( to_uptr(src_ptr) % size_of( SSIZE ) == to_uptr(dest_ptr) % size_of( SSIZE ) )
|
if ( to_uptr(src_ptr) % size_of( SSIZE ) == to_uptr(dest_ptr) % size_of( SSIZE ) )
|
||||||
{
|
{
|
||||||
while ( pcast( UPTR, dest_ptr) % size_of( ssize ) )
|
while ( pcast( UPTR, dest_ptr) % size_of( SSIZE ) )
|
||||||
{
|
{
|
||||||
if ( ! byte_count-- )
|
if ( ! byte_count-- )
|
||||||
return destination;
|
return destination;
|
||||||
|
|
||||||
*dest_ptr++ = *src_ptr++;
|
*dest_ptr++ = *src_ptr++;
|
||||||
}
|
}
|
||||||
while ( byte_count >= size_of( ssize ) )
|
while ( byte_count >= size_of( SSIZE ) )
|
||||||
{
|
{
|
||||||
* rcast(SSIZE*, dest_ptr) = * rcast(SSIZE const*, src_ptr);
|
* rcast(SSIZE*, dest_ptr) = * rcast(SSIZE const*, src_ptr);
|
||||||
byte_count -= size_of( ssize );
|
byte_count -= size_of( SSIZE );
|
||||||
dest_ptr += size_of( ssize );
|
dest_ptr += size_of( SSIZE );
|
||||||
src_ptr += size_of( ssize );
|
src_ptr += size_of( SSIZE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ( ; byte_count; byte_count-- )
|
for ( ; byte_count; byte_count-- )
|
||||||
@@ -301,7 +302,7 @@ void* mem_set( void* destination, U8 fill_byte, SSIZE byte_count )
|
|||||||
byte_count -= align_offset;
|
byte_count -= align_offset;
|
||||||
|
|
||||||
{
|
{
|
||||||
u64 fill_doubleword = ( scast( U64, fill_word) << 32 ) | fill_word;
|
U64 fill_doubleword = ( scast( U64, fill_word) << 32 ) | fill_word;
|
||||||
while ( byte_count > 31 )
|
while ( byte_count > 31 )
|
||||||
{
|
{
|
||||||
* rcast( U64*, dest_ptr + 0 ) = fill_doubleword;
|
* rcast( U64*, dest_ptr + 0 ) = fill_doubleword;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# include "../os/os.h"
|
# include "../os/os.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MD_HEAP_ANALYSIS
|
||||||
#define GEN_HEAP_STATS_MAGIC 0xDEADC0DE
|
#define GEN_HEAP_STATS_MAGIC 0xDEADC0DE
|
||||||
|
|
||||||
typedef struct _heap_stats _heap_stats;
|
typedef struct _heap_stats _heap_stats;
|
||||||
@@ -47,8 +48,9 @@ struct _heap_alloc_info
|
|||||||
SSIZE size;
|
SSIZE size;
|
||||||
void* physical_start;
|
void* physical_start;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags )
|
void* heap_allocator_proc( void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags )
|
||||||
{
|
{
|
||||||
void* ptr = nullptr;
|
void* ptr = nullptr;
|
||||||
// unused( allocator_data );
|
// unused( allocator_data );
|
||||||
@@ -62,7 +64,7 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE size, SSI
|
|||||||
ssize track_size = max( alloc_info_size, alignment ) + alloc_info_remainder;
|
ssize track_size = max( alloc_info_size, alignment ) + alloc_info_remainder;
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
case EAllocation_FREE :
|
case EAllocatorMode_FREE :
|
||||||
{
|
{
|
||||||
if ( ! old_memory )
|
if ( ! old_memory )
|
||||||
break;
|
break;
|
||||||
@@ -72,7 +74,7 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE size, SSI
|
|||||||
old_memory = alloc_info->physical_start;
|
old_memory = alloc_info->physical_start;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EAllocation_ALLOC :
|
case EAllocatorMode_ALLOC :
|
||||||
{
|
{
|
||||||
size += track_size;
|
size += track_size;
|
||||||
}
|
}
|
||||||
@@ -82,76 +84,83 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE size, SSI
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch ( type )
|
switch ( mode )
|
||||||
{
|
{
|
||||||
#if defined( COMPILER_MSVC ) || ( defined( COMPILER_GCC ) && defined( OS_WINDOWS ) ) || ( defined( COMPILER_TINYC ) && defined( OS_WINDOWS ) )
|
#if defined( COMPILER_MSVC ) || ( defined( COMPILER_GCC ) && defined( OS_WINDOWS ) ) || ( defined( COMPILER_TINYC ) && defined( OS_WINDOWS ) )
|
||||||
case EAllocType_ALLOC :
|
case AllocatorMode_ALLOC:
|
||||||
|
{
|
||||||
ptr = _aligned_malloc( size, alignment );
|
ptr = _aligned_malloc( size, alignment );
|
||||||
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
||||||
zero_size( ptr, size );
|
zero_size( ptr, size );
|
||||||
break;
|
}
|
||||||
case EAllocType_FREE :
|
break;
|
||||||
|
|
||||||
|
case AllocatorMode_FREE:
|
||||||
_aligned_free( old_memory );
|
_aligned_free( old_memory );
|
||||||
break;
|
break;
|
||||||
case EAllocType_RESIZE :
|
|
||||||
{
|
|
||||||
AllocatorInfo a = heap();
|
|
||||||
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
#elif defined( OS_LINUX ) && ! defined( CPU_ARM ) && ! defined( COMPILER_TINYC )
|
case AllocatorMode_FREE_ALL:
|
||||||
|
{
|
||||||
|
AllocatorInfo a = heap();
|
||||||
|
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#elif defined( OS_LINUX ) && ! defined( CPU_ARM ) && ! defined( COMPILER_TINYC )
|
||||||
case EAllocation_ALLOC :
|
case EAllocation_ALLOC :
|
||||||
{
|
{
|
||||||
ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) );
|
ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) );
|
||||||
|
|
||||||
if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
||||||
{
|
{
|
||||||
zero_size( ptr, size );
|
zero_size( ptr, size );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EAllocation_FREE :
|
case EAllocation_FREE :
|
||||||
{
|
{
|
||||||
free( old_memory );
|
free( old_memory );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EAllocation_RESIZE :
|
case EAllocation_RESIZE :
|
||||||
{
|
{
|
||||||
AllocatorInfo a = heap();
|
AllocatorInfo a = heap();
|
||||||
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case EAllocType_ALLOC :
|
case EAllocType_ALLOC :
|
||||||
{
|
{
|
||||||
posix_memalign( &ptr, alignment, size );
|
posix_memalign( &ptr, alignment, size );
|
||||||
|
|
||||||
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
||||||
{
|
{
|
||||||
zero_size( ptr, size );
|
zero_size( ptr, size );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case EAllocType_FREE :
|
case EAllocType_FREE :
|
||||||
{
|
{
|
||||||
free( old_memory );
|
free( old_memory );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EAllocType_RESIZE :
|
case EAllocType_RESIZE :
|
||||||
{
|
{
|
||||||
AllocatorInfo a = heap();
|
AllocatorInfo a = heap();
|
||||||
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case EAllocType_FREE_ALL :
|
case AllocatorMode_FREE_ALL:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AllocatorMode_QueryType:
|
||||||
|
return (void*) Heap
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GEN_HEAP_ANALYSIS
|
#ifdef GEN_HEAP_ANALYSIS
|
||||||
@@ -172,6 +181,44 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE size, SSI
|
|||||||
|
|
||||||
void* vm_allocator_proc(void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags)
|
void* vm_allocator_proc(void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags)
|
||||||
{
|
{
|
||||||
|
void* result = nullptr;
|
||||||
|
|
||||||
|
// if(params->flags & ArenaFlag_LargePages)
|
||||||
|
// {
|
||||||
|
// base = os_reserve_large(reserve_size);
|
||||||
|
// os_commit_large(base, commit_size);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// base = os_reserve(reserve_size);
|
||||||
|
// os_commit(base, commit_size);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VMemory vm_alloc(VMemoryParams params)
|
||||||
|
{
|
||||||
|
// rjf: round up reserve/commit sizes
|
||||||
|
U64 reserve_size = params->reserve_size;
|
||||||
|
U64 commit_size = params->commit_size;
|
||||||
|
|
||||||
|
if(params->flags & ArenaFlag_LargePages)
|
||||||
|
{
|
||||||
|
reserve_size = align_pow2(reserve_size, os_get_system_info()->large_page_size);
|
||||||
|
commit_size = align_pow2(commit_size, os_get_system_info()->large_page_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reserve_size = align_pow2(reserve_size, os_get_system_info()->page_size);
|
||||||
|
commit_size = align_pow2(commit_size, os_get_system_info()->page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate virtual memory
|
||||||
|
is_virtual = true;
|
||||||
|
|
||||||
|
VMemory vm = ;
|
||||||
|
|
||||||
|
// TODO(Ed): Move this to vmem?
|
||||||
|
asan_poison_memory_region(base, params->commit_size);
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,18 +19,29 @@
|
|||||||
#define MD__HAS_ZERO( x ) ( ( ( x ) - MD__ONES ) & ~( x ) & MD__HIGHS )
|
#define MD__HAS_ZERO( x ) ( ( ( x ) - MD__ONES ) & ~( x ) & MD__HIGHS )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef U32 AllocType;
|
// Return value of allocator_type
|
||||||
enum AllocType enum_underlying(U32)
|
typedef U32 AllocatorType;
|
||||||
|
enum
|
||||||
{
|
{
|
||||||
EAllocType_ALLOC,
|
AllocatorType_Heap = 0, // Genreal heap allocator
|
||||||
EAllocType_FREE,
|
AllocatorType_VArena = 1, // Arena allocator backed by virtual address space
|
||||||
EAllocType_FREE_ALL,
|
AllocatorType_FArena = 2, // Fixed arena backed back by a fixed size block of memory (usually a byte slice)
|
||||||
EAllocType_RESIZE,
|
AllocatorType_Arena = 3, // Composite arena used originally by RAD Debugger & Metadesk
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void*(AllocatorProc)( void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags );
|
typedef U32 AllocatorMode;
|
||||||
|
enum AllocatorMode enum_underlying(U32)
|
||||||
|
{
|
||||||
|
AllocatorMode_ALLOC,
|
||||||
|
AllocatorMode_FREE,
|
||||||
|
AllocatorMode_FREE_ALL,
|
||||||
|
AllocatorMode_RESIZE,
|
||||||
|
AllocatorMode_QueryType,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct AllocatorInfo;
|
typedef void*(AllocatorProc)( void* allocator_data, AllocatorMode type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags );
|
||||||
|
|
||||||
|
typedef struct AllocatorInfo AllocatorInfo;
|
||||||
struct AllocatorInfo
|
struct AllocatorInfo
|
||||||
{
|
{
|
||||||
AllocatorProc* proc;
|
AllocatorProc* proc;
|
||||||
@@ -50,6 +61,9 @@ enum AllocFlag
|
|||||||
# define MD_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
# define MD_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Allows the user to retrieve which type of allocator is being used.
|
||||||
|
AllocatorType allocator_type(AllocatorInfo a);
|
||||||
|
|
||||||
//! Allocate memory with default alignment.
|
//! Allocate memory with default alignment.
|
||||||
void* alloc( AllocatorInfo a, SSIZE size );
|
void* alloc( AllocatorInfo a, SSIZE size );
|
||||||
|
|
||||||
@@ -83,6 +97,7 @@ void* resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size,
|
|||||||
//! Use this if you don't need a "fancy" resize allocation
|
//! Use this if you don't need a "fancy" resize allocation
|
||||||
void* default_resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment );
|
void* default_resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment );
|
||||||
|
|
||||||
|
#ifdef MD_HEAP_ANALYSIS
|
||||||
/* heap memory analysis tools */
|
/* heap memory analysis tools */
|
||||||
/* define GEN_HEAP_ANALYSIS to enable this feature */
|
/* define GEN_HEAP_ANALYSIS to enable this feature */
|
||||||
/* call zpl_heap_stats_init at the beginning of the entry point */
|
/* call zpl_heap_stats_init at the beginning of the entry point */
|
||||||
@@ -91,8 +106,9 @@ MD_API void heap_stats_init( void );
|
|||||||
MD_API SSIZE heap_stats_used_memory( void );
|
MD_API SSIZE heap_stats_used_memory( void );
|
||||||
MD_API SSIZE heap_stats_alloc_count( void );
|
MD_API SSIZE heap_stats_alloc_count( void );
|
||||||
MD_API void heap_stats_check( void );
|
MD_API void heap_stats_check( void );
|
||||||
|
#endif
|
||||||
|
|
||||||
MD_API void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags );
|
MD_API void* heap_allocator_proc( void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags );
|
||||||
|
|
||||||
#ifndef heap
|
#ifndef heap
|
||||||
//! The heap allocator backed by operating system's memory manager.
|
//! The heap allocator backed by operating system's memory manager.
|
||||||
@@ -109,44 +125,83 @@ MD_API void* heap_allocator_proc( void* allocator_data, AllocType type, SSIZE si
|
|||||||
#define mfree( ptr ) free( heap(), ptr )
|
#define mfree( ptr ) free( heap(), ptr )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef U32 VMemoryFlags;
|
/* Virtual Memory Arena
|
||||||
|
This is separate from the composite arena used by HMH/Casey Muratori/RJF
|
||||||
|
This arena stricly manages one reservation of the process's virtual address space.
|
||||||
|
|
||||||
|
Segregating this from composite Arena style causes more moremoy to be used for "allocator headers", however it allows
|
||||||
|
users of a library to have greater control over the allocation strategy used from their side instead of the library itself.
|
||||||
|
|
||||||
|
Like with the composite Arena, the VArena has its struct as the header of the reserve of memory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef U32 VArenaFlags;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
VMemoryFlag_NoChain = (1 << 0),
|
VArenaFlag_LargePages = (1 << 0),
|
||||||
VMemoryFlag_LargePages = (1 << 1),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct VMemory_Params;
|
typedef struct VArenaParams VArenaParams;
|
||||||
struct VMemory_Params
|
struct VArenaParams
|
||||||
{
|
{
|
||||||
VMemoryFlags flags;
|
U64 base_addr;
|
||||||
U64 reserve_size;
|
VArenaFlags flags;
|
||||||
U64 commit_size;
|
U64 reserve_size;
|
||||||
// void* optional_backing_buffer;
|
U64 commit_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct VMemory;
|
typedef struct VArena VArena;
|
||||||
struct VMemory
|
struct VArena
|
||||||
{
|
{
|
||||||
U32 cmt_size;
|
VArenaFlags flags;
|
||||||
U32 res_size;
|
|
||||||
U64 base_pos;
|
U64 base_pos;
|
||||||
U64 cmt;
|
U64 cmt;
|
||||||
U64 res;
|
U64 res;
|
||||||
|
U64 res_size;
|
||||||
|
U64 cmt_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
AllocatorInfo vm_allocator(VMemory* vm) {
|
AllocatorInfo vm_allocator(VArena* vm) {
|
||||||
AllocatorInfo info = { vm_allocator_proc, vm }
|
AllocatorInfo info = { vm_allocator_proc, vm };
|
||||||
return info
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
MD_API void* vm_allocator_proc(void* allocator_data, AllocType type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
|
VArena* varena_alloc (VArenaParams params);
|
||||||
|
void varena_commit (VArena vm, SSIZE commit_size);
|
||||||
|
VArenaParams varena_free (VArena vm);
|
||||||
|
SSIZE varena_page_size(SSIZE* alignment_out);
|
||||||
|
|
||||||
|
MD_API void* varena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
|
||||||
|
|
||||||
|
typedef struct ByteSlice ByteSlice;
|
||||||
|
struct ByteSlice
|
||||||
|
{
|
||||||
|
U8* data;
|
||||||
|
SSIZE len;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fixed size arena
|
||||||
|
typedef struct FArena FArena;
|
||||||
|
struct FArena
|
||||||
|
{
|
||||||
|
ByteSlice slice;
|
||||||
|
SSIZE pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
FArena farena_from_byteslice(ByteSlice slice);
|
||||||
|
|
||||||
|
MD_API void* farena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
|
||||||
|
|
||||||
// Inlines
|
// Inlines
|
||||||
|
|
||||||
|
inline
|
||||||
|
AllocatorType allocator_type(AllocatorInfo a) {
|
||||||
|
return (AllocatorType) a.proc(a.data, AllocatorMode_QueryType, 0, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void* alloc_align( AllocatorInfo a, SSIZE size, SSIZE alignment ) {
|
void* alloc_align( AllocatorInfo a, SSIZE size, SSIZE alignment ) {
|
||||||
return a.Proc( a.Data, EAllocType_ALLOC, size, alignment, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
|
return a.proc( a.data, AllocatorMode_ALLOC, size, alignment, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -157,12 +212,12 @@ void* alloc( AllocatorInfo a, SSIZE size ) {
|
|||||||
inline
|
inline
|
||||||
void allocator_free( AllocatorInfo a, void* ptr ) {
|
void allocator_free( AllocatorInfo a, void* ptr ) {
|
||||||
if ( ptr != nullptr )
|
if ( ptr != nullptr )
|
||||||
a.Proc( a.Data, EAllocType_FREE, 0, 0, ptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
|
a.proc( a.data, AllocatorMode_FREE, 0, 0, ptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void free_all( AllocatorInfo a ) {
|
void free_all( AllocatorInfo a ) {
|
||||||
a.Proc( a.Data, EAllocType_FREE_ALL, 0, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
|
a.proc( a.data, AllocatorMode_FREE_ALL, 0, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -172,7 +227,7 @@ void* resize( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size ) {
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
void* resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment ) {
|
void* resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment ) {
|
||||||
return a.Proc( a.Data, EAllocType_RESIZE, new_size, alignment, ptr, old_size, MD_DEFAULT_ALLOCATOR_FLAGS );
|
return a.proc( a.data, AllocatorMode_RESIZE, new_size, alignment, ptr, old_size, MD_DEFAULT_ALLOCATOR_FLAGS );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
|
|||||||
@@ -36,4 +36,3 @@ MD_NS_END
|
|||||||
|
|
||||||
// metagen
|
// metagen
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user