Pull in changes from internal project

This commit is contained in:
2024-08-01 13:34:36 +10:00
parent 765b8255f7
commit 6b403eae71
32 changed files with 2317 additions and 1135 deletions
+138 -53
View File
@@ -56,11 +56,28 @@ DQN_API Dqn_ArenaBlock *Dqn_Arena_BlockInitFlags(uint64_t reserve, uint64_t comm
return result;
}
static void Dqn_Arena_UpdateStatsOnNewBlock_(Dqn_Arena *arena, Dqn_ArenaBlock const *block)
{
DQN_ASSERT(arena);
if (block) {
arena->stats.info.used += block->used;
arena->stats.info.commit += block->commit;
arena->stats.info.reserve += block->reserve;
arena->stats.info.blocks += 1;
arena->stats.hwm.used = DQN_MAX(arena->stats.hwm.used, arena->stats.info.used);
arena->stats.hwm.commit = DQN_MAX(arena->stats.hwm.commit, arena->stats.info.commit);
arena->stats.hwm.reserve = DQN_MAX(arena->stats.hwm.reserve, arena->stats.info.reserve);
arena->stats.hwm.blocks = DQN_MAX(arena->stats.hwm.blocks, arena->stats.info.blocks);
}
}
DQN_API Dqn_Arena Dqn_Arena_InitSize(uint64_t reserve, uint64_t commit, uint8_t flags)
{
Dqn_Arena result = {};
result.flags = flags;
result.curr = Dqn_Arena_BlockInitFlags(reserve, commit, flags);
Dqn_Arena_UpdateStatsOnNewBlock_(&result, result.curr);
return result;
}
@@ -123,8 +140,10 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
if (!arena)
return nullptr;
if (!arena->curr)
if (!arena->curr) {
arena->curr = Dqn_Arena_BlockInitFlags(DQN_ARENA_RESERVE_SIZE, DQN_ARENA_COMMIT_SIZE, arena->flags);
Dqn_Arena_UpdateStatsOnNewBlock_(arena, arena->curr);
}
if (!arena->curr)
return nullptr;
@@ -147,6 +166,7 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
new_block->prev = arena->curr;
arena->curr = new_block;
new_block->reserve_sum = new_block->prev->reserve_sum + new_block->prev->reserve;
Dqn_Arena_UpdateStatsOnNewBlock_(arena, arena->curr);
goto try_alloc_again;
}
@@ -159,11 +179,16 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
return nullptr;
if (poison)
Dqn_ASAN_PoisonMemoryRegion(commit_ptr, commit_size);
curr->commit = end_commit;
curr->commit = end_commit;
arena->stats.info.commit += commit_size;
arena->stats.hwm.commit = DQN_MAX(arena->stats.hwm.commit, arena->stats.info.commit);
}
void *result = DQN_CAST(char *) curr + offset_pos;
curr->used = end_pos;
void *result = DQN_CAST(char *) curr + offset_pos;
Dqn_usize alloc_size = end_pos - curr->used;
curr->used += alloc_size;
arena->stats.info.used += alloc_size;
arena->stats.hwm.used = DQN_MAX(arena->stats.hwm.used, arena->stats.info.used);
Dqn_ASAN_UnpoisonMemoryRegion(result, size);
if (zero_mem == Dqn_ZeroMem_Yes) {
@@ -171,6 +196,10 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
DQN_MEMSET(result, 0, reused_bytes);
}
DQN_ASSERT(arena->stats.hwm.used >= arena->stats.info.used);
DQN_ASSERT(arena->stats.hwm.commit >= arena->stats.info.commit);
DQN_ASSERT(arena->stats.hwm.reserve >= arena->stats.info.reserve);
DQN_ASSERT(arena->stats.hwm.blocks >= arena->stats.info.blocks);
return result;
}
@@ -195,21 +224,27 @@ DQN_API void *Dqn_Arena_Copy(Dqn_Arena *arena, void const *data, uint64_t size,
DQN_API void Dqn_Arena_PopTo(Dqn_Arena *arena, uint64_t init_used)
{
if (!arena)
if (!arena || !arena->curr)
return;
uint64_t used = DQN_MAX(DQN_ARENA_HEADER_SIZE, init_used);
Dqn_ArenaBlock *curr = arena->curr;
while (curr->reserve_sum >= used) {
Dqn_ArenaBlock *block_to_free = curr;
arena->stats.info.used -= block_to_free->used;
arena->stats.info.commit -= block_to_free->commit;
arena->stats.info.reserve -= block_to_free->reserve;
arena->stats.info.blocks -= 1;
curr = curr->prev;
Dqn_Arena_BlockDeinit_(arena, block_to_free);
}
arena->curr = curr;
curr->used = used - curr->reserve_sum;
char *poison_ptr = (char *)curr + Dqn_AlignUpPowerOfTwo(curr->used, DQN_ASAN_POISON_ALIGNMENT);
Dqn_usize poison_size = ((char *)curr + curr->commit) - poison_ptr;
arena->stats.info.used -= curr->used;
arena->curr = curr;
curr->used = used - curr->reserve_sum;
char *poison_ptr = (char *)curr + Dqn_AlignUpPowerOfTwo(curr->used, DQN_ASAN_POISON_ALIGNMENT);
Dqn_usize poison_size = ((char *)curr + curr->commit) - poison_ptr;
Dqn_ASAN_PoisonMemoryRegion(poison_ptr, poison_size);
arena->stats.info.used += curr->used;
}
DQN_API void Dqn_Arena_Pop(Dqn_Arena *arena, uint64_t amount)
@@ -237,7 +272,7 @@ DQN_API bool Dqn_Arena_OwnsPtr(Dqn_Arena const *arena, void *ptr)
{
bool result = false;
uintptr_t uint_ptr = DQN_CAST(uintptr_t)ptr;
for (Dqn_ArenaBlock const *block = arena ? arena->curr : nullptr; !result && block; ) {
for (Dqn_ArenaBlock const *block = arena ? arena->curr : nullptr; !result && block; block = block->prev) {
uintptr_t begin = DQN_CAST(uintptr_t) block + DQN_ARENA_HEADER_SIZE;
uintptr_t end = begin + block->reserve;
result = uint_ptr >= begin && uint_ptr <= end;
@@ -245,6 +280,42 @@ DQN_API bool Dqn_Arena_OwnsPtr(Dqn_Arena const *arena, void *ptr)
return result;
}
DQN_API Dqn_ArenaStats Dqn_Arena_SumStatsArray(Dqn_ArenaStats const *array, Dqn_usize size)
{
Dqn_ArenaStats result = {};
DQN_FOR_UINDEX(index, size) {
Dqn_ArenaStats stats = array[index];
result.info.used += stats.info.used;
result.info.commit += stats.info.commit;
result.info.reserve += stats.info.reserve;
result.info.blocks += stats.info.blocks;
result.hwm.used = DQN_MAX(result.hwm.used, result.info.used);
result.hwm.commit = DQN_MAX(result.hwm.commit, result.info.commit);
result.hwm.reserve = DQN_MAX(result.hwm.reserve, result.info.reserve);
result.hwm.blocks = DQN_MAX(result.hwm.blocks, result.info.blocks);
}
return result;
}
DQN_API Dqn_ArenaStats Dqn_Arena_SumStats(Dqn_ArenaStats lhs, Dqn_ArenaStats rhs)
{
Dqn_ArenaStats array[] = {lhs, rhs};
Dqn_ArenaStats result = Dqn_Arena_SumStatsArray(array, DQN_ARRAY_UCOUNT(array));
return result;
}
DQN_API Dqn_ArenaStats Dqn_Arena_SumArenaArrayToStats(Dqn_Arena const *array, Dqn_usize size)
{
Dqn_ArenaStats result = {};
for (Dqn_usize index = 0; index < size; index++) {
Dqn_Arena const *arena = array + index;
result = Dqn_Arena_SumStats(result, arena->stats);
}
return result;
}
DQN_API Dqn_ArenaTempMem Dqn_Arena_TempMemBegin(Dqn_Arena *arena)
{
Dqn_ArenaTempMem result = {};
@@ -299,13 +370,8 @@ DQN_API void *Dqn_ChunkPool_Alloc(Dqn_ChunkPool *pool, Dqn_usize size)
Dqn_usize const size_to_slot_offset = 5; // __lzcnt64(32) e.g. Dqn_ChunkPoolSlotSize_32B
Dqn_usize slot_index = 0;
if (required_size > 32) {
#if defined(DQN_OS_WIN32)
Dqn_usize dist_to_next_msb = __lzcnt64(required_size) + 1;
#else
Dqn_usize dist_to_next_msb = __builtin_clzll(required_size) + 1;
#endif
// NOTE: Round up if not PoT as the low bits are set.
Dqn_usize dist_to_next_msb = Dqn_CountLeadingZerosU64(required_size) + 1;
dist_to_next_msb -= DQN_CAST(Dqn_usize)(!Dqn_IsPowerOfTwo(required_size));
Dqn_usize const register_size = sizeof(Dqn_usize) * 8;
@@ -401,14 +467,17 @@ DQN_API Dqn_Str8 Dqn_ChunkPool_AllocStr8Copy(Dqn_ChunkPool *pool, Dqn_Str8 strin
DQN_API void Dqn_ChunkPool_Dealloc(Dqn_ChunkPool *pool, void *ptr)
{
if (!Dqn_ChunkPool_IsValid(pool))
if (!Dqn_ChunkPool_IsValid(pool) || !ptr)
return;
Dqn_usize offset_to_original_ptr = 0;
DQN_MEMCPY(&offset_to_original_ptr, &(DQN_CAST(char *)ptr)[-1], 1);
DQN_ASSERT(Dqn_Arena_OwnsPtr(pool->arena, ptr));
char const *one_byte_behind_ptr = DQN_CAST(char *) ptr - 1;
Dqn_usize offset_to_original_ptr = 0;
DQN_MEMCPY(&offset_to_original_ptr, one_byte_behind_ptr, 1);
DQN_ASSERT(offset_to_original_ptr <= sizeof(Dqn_ChunkPoolSlot) + pool->align);
char *original_ptr = DQN_CAST(char *)ptr - offset_to_original_ptr;
char *original_ptr = DQN_CAST(char *)ptr - offset_to_original_ptr;
Dqn_ChunkPoolSlot *slot = DQN_CAST(Dqn_ChunkPoolSlot *)original_ptr;
Dqn_ChunkPoolSlotSize slot_index = DQN_CAST(Dqn_ChunkPoolSlotSize)(DQN_CAST(uintptr_t)slot->next);
DQN_ASSERT(slot_index < Dqn_ChunkPoolSlotSize_Count);
@@ -417,6 +486,20 @@ DQN_API void Dqn_ChunkPool_Dealloc(Dqn_ChunkPool *pool, void *ptr)
pool->slots[slot_index] = slot;
}
DQN_API void *Dqn_ChunkPool_Copy(Dqn_ChunkPool *pool, void const *data, uint64_t size, uint8_t align)
{
if (!pool || !data || size == 0)
return nullptr;
// TODO: Hmm should align be part of the alloc interface in general? I'm not going to worry
// about this until we crash because of misalignment.
DQN_ASSERT(pool->align >= align);
void *result = Dqn_ChunkPool_Alloc(pool, size);
if (result)
DQN_MEMCPY(result, data, size);
return result;
}
// NOTE: [$ACAT] Dqn_ArenaCatalog //////////////////////////////////////////////////////////////////
DQN_API void Dqn_ArenaCatalog_Init(Dqn_ArenaCatalog *catalog, Dqn_ChunkPool *pool)
@@ -440,7 +523,7 @@ DQN_API Dqn_ArenaCatalogItem *Dqn_ArenaCatalog_Find(Dqn_ArenaCatalog *catalog, D
return result;
}
DQN_API void Dqn_ArenaCatalog_AddLabelRef(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label)
static void Dqn_ArenaCatalog_AddInternal_(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label, bool arena_pool_allocated)
{
// NOTE: We could use an atomic for appending to the sentinel but it is such
// a rare operation to append to the catalog that we don't bother.
@@ -451,6 +534,7 @@ DQN_API void Dqn_ArenaCatalog_AddLabelRef(Dqn_ArenaCatalog *catalog, Dqn_Arena *
if (result) {
result->arena = arena;
result->label = label;
result->arena_pool_allocated = arena_pool_allocated;
// NOTE: Add to the catalog (linked list)
Dqn_ArenaCatalogItem *sentinel = &catalog->sentinel;
@@ -463,14 +547,6 @@ DQN_API void Dqn_ArenaCatalog_AddLabelRef(Dqn_ArenaCatalog *catalog, Dqn_Arena *
Dqn_TicketMutex_End(&catalog->ticket_mutex);
}
DQN_API void Dqn_ArenaCatalog_AddLabelCopy(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label)
{
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
Dqn_Str8 label_copy = Dqn_ChunkPool_AllocStr8Copy(catalog->pool, label);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
Dqn_ArenaCatalog_AddLabelRef(catalog, arena, label_copy);
}
DQN_API void Dqn_ArenaCatalog_AddF(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
@@ -479,7 +555,7 @@ DQN_API void Dqn_ArenaCatalog_AddF(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena,
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
va_end(args);
Dqn_ArenaCatalog_AddLabelRef(catalog, arena, label);
Dqn_ArenaCatalog_AddInternal_(catalog, arena, label, false /*arena_pool_allocated*/);
}
DQN_API void Dqn_ArenaCatalog_AddFV(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, va_list args)
@@ -487,35 +563,18 @@ DQN_API void Dqn_ArenaCatalog_AddFV(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena,
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
Dqn_ArenaCatalog_AddLabelRef(catalog, arena, label);
}
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocLabelRef(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, Dqn_Str8 label)
{
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
Dqn_Arena *result = Dqn_ChunkPool_New(catalog->pool, Dqn_Arena);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
*result = Dqn_Arena_InitSize(reserve, commit, arena_flags);
Dqn_ArenaCatalog_AddLabelRef(catalog, result, label);
return result;
}
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocLabelCopy(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, Dqn_Str8 label)
{
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
Dqn_Str8 label_copy = Dqn_ChunkPool_AllocStr8Copy(catalog->pool, label);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
Dqn_Arena *result = Dqn_ArenaCatalog_AllocLabelRef(catalog, reserve, commit, arena_flags, label_copy);
return result;
Dqn_ArenaCatalog_AddInternal_(catalog, arena, label, false /*arena_pool_allocated*/);
}
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocFV(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
Dqn_Arena *result = Dqn_ChunkPool_New(catalog->pool, Dqn_Arena);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
Dqn_Arena *result = Dqn_ArenaCatalog_AllocLabelRef(catalog, reserve, commit, arena_flags, label);
*result = Dqn_Arena_InitSize(reserve, commit, arena_flags);
Dqn_ArenaCatalog_AddInternal_(catalog, result, label, true /*arena_pool_allocated*/);
return result;
}
@@ -525,8 +584,34 @@ DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocF(Dqn_ArenaCatalog *catalog, Dqn_usize
va_start(args, fmt);
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
Dqn_Arena *result = Dqn_ChunkPool_New(catalog->pool, Dqn_Arena);
Dqn_TicketMutex_End(&catalog->ticket_mutex);
Dqn_Arena *result = Dqn_ArenaCatalog_AllocLabelRef(catalog, reserve, commit, arena_flags, label);
va_end(args);
*result = Dqn_Arena_InitSize(reserve, commit, arena_flags);
Dqn_ArenaCatalog_AddInternal_(catalog, result, label, true /*arena_pool_allocated*/);
return result;
}
DQN_API bool Dqn_ArenaCatalog_Erase(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_ArenaCatalogFreeArena free_arena)
{
bool result = false;
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
for (Dqn_ArenaCatalogItem *item = catalog->sentinel.next; item != &catalog->sentinel; item = item->next) {
if (item->arena == arena) {
item->next->prev = item->prev;
item->prev->next = item->next;
if (item->arena_pool_allocated) {
if (free_arena == Dqn_ArenaCatalogFreeArena_Yes)
Dqn_Arena_Deinit(item->arena);
Dqn_ChunkPool_Dealloc(catalog->pool, item->arena);
}
Dqn_ChunkPool_Dealloc(catalog->pool, item->label.data);
Dqn_ChunkPool_Dealloc(catalog->pool, item);
result = true;
break;
}
}
Dqn_TicketMutex_End(&catalog->ticket_mutex);
return result;
}