Try separate mem apis for head/tail

This commit is contained in:
Doyle Thai 2018-02-05 01:50:36 +11:00
parent 019aad46ca
commit 701140287f
2 changed files with 172 additions and 82 deletions

240
dqn.h
View File

@ -271,8 +271,12 @@ public:
static DqnMemAPI HeapAllocator (); static DqnMemAPI HeapAllocator ();
// TODO(doyle): No longer necessary now that stack creates its own on init? enum struct StackPushType
static DqnMemAPI StackAllocator(struct DqnMemStack *const stack); {
Head,
Tail,
};
static DqnMemAPI StackAllocator(struct DqnMemStack *const stack, StackPushType type = StackPushType::Head);
void *Realloc(void *const oldPtr, isize const oldSize, isize const newSize); void *Realloc(void *const oldPtr, isize const oldSize, isize const newSize);
void *Alloc (isize const size, bool const zeroClear = true); void *Alloc (isize const size, bool const zeroClear = true);
@ -440,7 +444,8 @@ struct DqnMemStack
DqnAllocatorMetadata metadata; DqnAllocatorMetadata metadata;
DqnMemAPI *memAPI; // API used to add additional memory blocks to this stack. DqnMemAPI *memAPI; // API used to add additional memory blocks to this stack.
DqnMemAPI myAPI; // API for data structures to allocate using this stack's memory. DqnMemAPI myTailAPI; // API for data structures to allocate to the tail of the stack
DqnMemAPI myHeadAPI; // API for data structures to allocate to the head of the stack
Block *block; // Memory block allocated for the stack Block *block; // Memory block allocated for the stack
u32 flags; u32 flags;
i32 tempRegionCount; i32 tempRegionCount;
@ -479,6 +484,9 @@ struct DqnMemStack
// Next allocate will attach a block. // Next allocate will attach a block.
bool FreeLastBlock (); bool FreeLastBlock ();
// Reverts the stack and its usage back to the first block
void Reset();
// Reset the current memory block usage to 0. // Reset the current memory block usage to 0.
void ClearCurrBlock(bool zeroClear); void ClearCurrBlock(bool zeroClear);
Info GetInfo () const; Info GetInfo () const;
@ -492,23 +500,21 @@ struct DqnMemStack
Block *startingBlock; // Remember the block to revert to and its memory usage. Block *startingBlock; // Remember the block to revert to and its memory usage.
u8 *startingBlockHead; u8 *startingBlockHead;
u8 *startingBlockTail; u8 *startingBlockTail;
isize allocationCount; // Debug only: For ensuring BoundsGuard allocation tracker reverts as well. bool keepHeadChanges = false;
bool keepTailChanges = false;
}; };
class TempRegionGuard_ struct TempRegionGuard_
{ {
public: TempRegionGuard_(DqnMemStack *const stack);
TempRegionGuard_(DqnMemStack *const stack);
~TempRegionGuard_(); ~TempRegionGuard_();
bool keepChanges = false; TempRegion region;
private:
TempRegion memRegion;
}; };
// Revert all allocations between the Begin() and End() regions. // Revert all allocations between the Begin() and End() regions. Guard version is RAII'ed.
TempRegion TempRegionBegin (); TempRegion TempRegionBegin ();
void TempRegionEnd (TempRegion region); void TempRegionEnd (TempRegion region);
TempRegionGuard_ TempRegionGuard (); // RAII Temp Region TempRegionGuard_ TempRegionGuard ();
// Keep allocations that have occurred since Begin(). End() does not need to be called anymore. // Keep allocations that have occurred since Begin(). End() does not need to be called anymore.
void TempRegionKeepChanges(TempRegion region); void TempRegionKeepChanges(TempRegion region);
@ -535,7 +541,7 @@ void DqnArray<T>::Init(T *data_, isize max_, isize count_)
template <typename T> template <typename T>
void DqnArray<T>::Init(DqnMemStack *const stack) void DqnArray<T>::Init(DqnMemStack *const stack)
{ {
this->Init(stack->myAPI); this->Init(stack->myHeadAPI);
} }
template <typename T> template <typename T>
@ -549,7 +555,7 @@ bool DqnArray<T>::InitSize(isize size_, DqnMemAPI *const memAPI_)
template <typename T> template <typename T>
bool DqnArray<T>::InitSize(isize size_, DqnMemStack *const stack) bool DqnArray<T>::InitSize(isize size_, DqnMemStack *const stack)
{ {
bool result = this->InitSize(size_, &stack->myAPI); bool result = this->InitSize(size_, &stack->myHeadAPI);
return result; return result;
} }
@ -1357,7 +1363,7 @@ template <typename T>
bool DqnHashTable<T>::Init(i64 const numTableEntries, DqnMemStack *const stack) bool DqnHashTable<T>::Init(i64 const numTableEntries, DqnMemStack *const stack)
{ {
if (!stack) return false; if (!stack) return false;
bool result = Init(numTableEntries, &stack->myAPI); bool result = Init(numTableEntries, &stack->myHeadAPI);
return result; return result;
} }
@ -3103,7 +3109,20 @@ FILE_SCOPE u8 *DqnMemAPIInternal_HeapAllocatorCallback(DqnMemAPI *api, DqnMemAPI
return result; return result;
} }
FILE_SCOPE u8 *DqnMemAPIInternal_StackAllocatorCallback(DqnMemAPI *api, DqnMemAPI::Request request_) struct DqnMemAPIInternal_DqnMemStackContext
{
enum Mode
{
PushToHead,
PushToTail,
};
DqnMemStack *stack;
Mode mode;
};
FILE_SCOPE u8 *DqnMemAPIInternal_StackAllocatorCallback(DqnMemAPI *api, DqnMemAPI::Request request_,
bool pushToHead)
{ {
DqnMemAPIInternal_ValidateRequest(request_); DqnMemAPIInternal_ValidateRequest(request_);
DQN_ASSERT(request_.userContext); DQN_ASSERT(request_.userContext);
@ -3159,7 +3178,8 @@ FILE_SCOPE u8 *DqnMemAPIInternal_StackAllocatorCallback(DqnMemAPI *api, DqnMemAP
if (request_.type == DqnMemAPI::Type::Alloc) if (request_.type == DqnMemAPI::Type::Alloc)
{ {
auto *request = &request_.alloc; auto *request = &request_.alloc;
result = (u8 *)stack->Push(request->requestSize); if (pushToHead) result = (u8 *)stack->Push(request->requestSize);
else result = (u8 *)stack->PushOnTail(request->requestSize);
if (result) if (result)
{ {
@ -3305,14 +3325,30 @@ FILE_SCOPE u8 *DqnMemAPIInternal_StackAllocatorCallback(DqnMemAPI *api, DqnMemAP
} }
} }
// TODO(doyle): Stats. Irrelevant now?
(void)api;
#if 0
if (success) if (success)
{ {
DqnMemAPIInternal_UpdateAPIStatistics(api, &request_); DqnMemAPIInternal_UpdateAPIStatistics(api, &request_);
} }
#endif
return result; return result;
} }
FILE_SCOPE u8 *DqnMemAPIInternal_StackAllocatorCallbackPushToHead(DqnMemAPI *api, DqnMemAPI::Request request_)
{
u8 *result = DqnMemAPIInternal_StackAllocatorCallback(api, request_, true);
return result;
}
FILE_SCOPE u8 *DqnMemAPIInternal_StackAllocatorCallbackPushToTail(DqnMemAPI *api, DqnMemAPI::Request request_)
{
u8 *result = DqnMemAPIInternal_StackAllocatorCallback(api, request_, false);
return result;
}
void *DqnMemAPI::Realloc(void *const oldPtr, isize const oldSize, isize const newSize) void *DqnMemAPI::Realloc(void *const oldPtr, isize const oldSize, isize const newSize)
{ {
Request request = {}; Request request = {};
@ -3356,11 +3392,13 @@ DqnMemAPI DqnMemAPI::HeapAllocator()
return result; return result;
} }
DqnMemAPI DqnMemAPI::StackAllocator(struct DqnMemStack *const stack) DqnMemAPI DqnMemAPI::StackAllocator(struct DqnMemStack *const stack, StackPushType type)
{ {
DQN_ASSERT(stack); DQN_ASSERT(stack);
DqnMemAPI result = {0}; DqnMemAPI result = {0};
result.allocator = DqnMemAPIInternal_StackAllocatorCallback; result.allocator = (type == StackPushType::Head)
? DqnMemAPIInternal_StackAllocatorCallbackPushToHead
: DqnMemAPIInternal_StackAllocatorCallbackPushToTail;
result.userContext = stack; result.userContext = stack;
return result; return result;
} }
@ -3536,7 +3574,8 @@ bool DqnMemStack::Init(void *const mem, isize size, bool zeroClear, u32 flags_)
this->block->prevBlock = nullptr; this->block->prevBlock = nullptr;
this->memAPI = nullptr; this->memAPI = nullptr;
this->myAPI = DqnMemAPI::StackAllocator(this); this->myHeadAPI = DqnMemAPI::StackAllocator(this, DqnMemAPI::StackPushType::Head);
this->myTailAPI = DqnMemAPI::StackAllocator(this, DqnMemAPI::StackPushType::Tail);
this->flags = (flags_ | Flag::NonExpandable); this->flags = (flags_ | Flag::NonExpandable);
this->tempRegionCount = 0; this->tempRegionCount = 0;
@ -3573,7 +3612,8 @@ bool DqnMemStack::Init(isize size, bool zeroClear, u32 flags_, DqnMemAPI *const
this->tempRegionCount = 0; this->tempRegionCount = 0;
this->flags = flags_; this->flags = flags_;
this->memAPI = api; this->memAPI = api;
this->myAPI = DqnMemAPI::StackAllocator(this); this->myHeadAPI = DqnMemAPI::StackAllocator(this, DqnMemAPI::StackPushType::Head);
this->myTailAPI = DqnMemAPI::StackAllocator(this, DqnMemAPI::StackPushType::Tail);
bool boundsGuard = Dqn_BitIsSet(this->flags, Flag::BoundsGuard); bool boundsGuard = Dqn_BitIsSet(this->flags, Flag::BoundsGuard);
this->metadata.Init(boundsGuard); this->metadata.Init(boundsGuard);
@ -3646,6 +3686,7 @@ FILE_SCOPE void *DqnMemStackInternal_Push(DqnMemStack *stack, isize size, u8 ali
DQN_ASSERT(stack->block->tail >= stack->block->head); DQN_ASSERT(stack->block->tail >= stack->block->head);
} }
// Instrument allocation with guards and metadata // Instrument allocation with guards and metadata
// ============================================================================================= // =============================================================================================
{ {
@ -3697,15 +3738,15 @@ void *DqnMemStack::Push(isize size, u8 alignment)
return result; return result;
} }
FILE_SCOPE void DqnMemStackInternal_KillMetadataPtrsExistingInBlock(DqnAllocatorMetadata *metadata, FILE_SCOPE void DqnMemStackInternal_KillMetadataPtrsExistingIn(DqnAllocatorMetadata *metadata,
DqnMemStack::Block const *block) u8 const *start, u8 const *end)
{ {
u8 const *blockStart = block->memory; if (start >= end) return;
u8 const *blockEnd = block->memory + block->size;
for (auto index = 0; index < metadata->allocations.count; index++) for (auto index = 0; index < metadata->allocations.count; index++)
{ {
u8 *ptr = metadata->allocations.data[index]; u8 *ptr = metadata->allocations.data[index];
if (ptr >= blockStart && ptr <= blockEnd) if (ptr >= start && ptr < end)
{ {
metadata->allocations.RemoveStable(index); metadata->allocations.RemoveStable(index);
index--; index--;
@ -3713,6 +3754,13 @@ FILE_SCOPE void DqnMemStackInternal_KillMetadataPtrsExistingInBlock(DqnAllocator
} }
} }
FILE_SCOPE void DqnMemStackInternal_KillMetadataPtrsExistingInBlock(DqnAllocatorMetadata *metadata,
DqnMemStack::Block const *block)
{
u8 const *blockStart = block->memory;
u8 const *blockEnd = block->memory + block->size;
DqnMemStackInternal_KillMetadataPtrsExistingIn(metadata, blockStart, blockEnd);
}
FILE_SCOPE void DqnMemStackInternal_Pop(DqnMemStack *stack, void *const ptr, bool zeroClear, bool popHead) FILE_SCOPE void DqnMemStackInternal_Pop(DqnMemStack *stack, void *const ptr, bool zeroClear, bool popHead)
{ {
@ -3793,7 +3841,6 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *memBlock)
if (!this->memAPI) if (!this->memAPI)
return false; return false;
DqnMemStack::Block **blockPtr = &this->block; DqnMemStack::Block **blockPtr = &this->block;
while (*blockPtr && (*blockPtr) != memBlock) while (*blockPtr && (*blockPtr) != memBlock)
@ -3820,6 +3867,16 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *memBlock)
return false; return false;
} }
void DqnMemStack::Reset()
{
while(this->block && this->block->prevBlock)
{
this->FreeLastBlock();
}
this->ClearCurrBlock(false);
}
bool DqnMemStack::FreeLastBlock() bool DqnMemStack::FreeLastBlock()
{ {
bool result = this->FreeMemBlock(this->block); bool result = this->FreeMemBlock(this->block);
@ -3876,56 +3933,92 @@ DqnMemStack::TempRegion DqnMemStack::TempRegionBegin()
result.startingBlockHead = (this->block) ? this->block->head : nullptr; result.startingBlockHead = (this->block) ? this->block->head : nullptr;
result.startingBlockTail = (this->block) ? this->block->tail : nullptr; result.startingBlockTail = (this->block) ? this->block->tail : nullptr;
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
{
result.allocationCount = this->metadata.allocations.count;
}
this->tempRegionCount++; this->tempRegionCount++;
return result; return result;
} }
void DqnMemStack::TempRegionEnd(TempRegion region) void DqnMemStack::TempRegionEnd(TempRegion region)
{ {
DqnMemStack *stack = region.stack; DQN_ASSERT(region.stack == this);
DQN_ASSERT(stack == this);
while (this->block != region.startingBlock) this->tempRegionCount--;
this->FreeLastBlock(); DQN_ASSERT(this->tempRegionCount >= 0);
if (this->block) if (region.keepHeadChanges && region.keepTailChanges)
{ {
// Debug checks return;
}
// Free blocks until you find the first block with changes in the head or tail, this is the
// block we want to start preserving allocation data for keepHead/TailChanges.
if (region.keepHeadChanges)
{
while (this->block && this->block->head == this->block->memory)
this->FreeLastBlock();
}
else if (region.keepTailChanges)
{
while (this->block && this->block->tail == (this->block->memory + this->block->size))
this->FreeLastBlock();
}
else
{
while (this->block != region.startingBlock)
this->FreeLastBlock();
}
for (Block *block_ = this->block; block_; block_ = block_->prevBlock)
{
if (block_ == region.startingBlock)
{ {
u8 const *const start = this->block->memory; if (region.keepHeadChanges)
u8 const *const end = start + this->block->size; {
DQN_ASSERT(region.startingBlockHead >= start && region.startingBlockHead <= end); block_->tail = region.startingBlockTail;
DQN_ASSERT(region.startingBlockTail >= start && region.startingBlockTail <= end); }
else if (region.keepTailChanges)
{
block_->head = region.startingBlockHead;
}
else
{
block_->head = region.startingBlockHead;
block_->tail = region.startingBlockTail;
}
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
{
u8 *blockStart = this->block->head;
u8 *blockEnd = this->block->tail;
DqnMemStackInternal_KillMetadataPtrsExistingIn(&this->metadata, blockStart, blockEnd);
}
break;
} }
else
{
if (region.keepHeadChanges || region.keepTailChanges)
{
u8 *blockStart = nullptr;
u8 *blockEnd = nullptr;
if (region.keepHeadChanges)
{
blockStart = block_->tail;
blockEnd = block_->memory + block_->size;
block_->tail = blockEnd;
}
else
{
blockStart = block_->memory;
blockEnd = block_->memory + block_->size;
block_->head = blockStart;
}
this->block->head = region.startingBlockHead; if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
this->block->tail = region.startingBlockTail; {
DqnMemStackInternal_KillMetadataPtrsExistingIn(&this->metadata, blockStart, blockEnd);
}
}
}
} }
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
{
while(this->metadata.allocations.count != region.allocationCount)
this->metadata.allocations.Pop();
}
this->tempRegionCount--;
DQN_ASSERT(this->tempRegionCount >= 0);
}
void DqnMemStack::TempRegionKeepChanges(TempRegion region)
{
DqnMemStack *stack = region.stack;
DQN_ASSERT(stack == this);
this->tempRegionCount--;
DQN_ASSERT(this->tempRegionCount >= 0);
} }
DqnMemStack::TempRegionGuard_ DqnMemStack::TempRegionGuard() DqnMemStack::TempRegionGuard_ DqnMemStack::TempRegionGuard()
@ -3935,16 +4028,13 @@ DqnMemStack::TempRegionGuard_ DqnMemStack::TempRegionGuard()
DqnMemStack::TempRegionGuard_::TempRegionGuard_(DqnMemStack *const stack) DqnMemStack::TempRegionGuard_::TempRegionGuard_(DqnMemStack *const stack)
{ {
this->memRegion = stack->TempRegionBegin(); this->region = stack->TempRegionBegin();
} }
DqnMemStack::TempRegionGuard_::~TempRegionGuard_() DqnMemStack::TempRegionGuard_::~TempRegionGuard_()
{ {
TempRegion region = this->memRegion; DqnMemStack *const stack = this->region.stack;
DqnMemStack *const stack = region.stack; stack->TempRegionEnd(this->region);
if (this->keepChanges) stack->TempRegionKeepChanges(region);
else stack->TempRegionEnd(region);
} }
// #DqnHash // #DqnHash
@ -5841,12 +5931,12 @@ void DqnString::Init(DqnMemAPI *const api)
void DqnString::Init(DqnMemStack *const stack) void DqnString::Init(DqnMemStack *const stack)
{ {
this->Init(&stack->myAPI); this->Init(&stack->myHeadAPI);
} }
bool DqnString::InitSize(const i32 size, DqnMemStack *const stack) bool DqnString::InitSize(const i32 size, DqnMemStack *const stack)
{ {
bool result = this->InitSize(size, &stack->myAPI); bool result = this->InitSize(size, &stack->myHeadAPI);
return result; return result;
} }
@ -5894,13 +5984,13 @@ bool DqnString::InitFixedMem(char *const memory, i32 const sizeInBytes)
bool DqnString::InitLiteral(char const *const cstr, DqnMemStack *const stack) bool DqnString::InitLiteral(char const *const cstr, DqnMemStack *const stack)
{ {
bool result = this->InitLiteral(cstr, &stack->myAPI); bool result = this->InitLiteral(cstr, &stack->myHeadAPI);
return result; return result;
} }
bool DqnString::InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMemStack *const stack) bool DqnString::InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMemStack *const stack)
{ {
bool result = this->InitLiteral(cstr, lenInBytes, &stack->myAPI); bool result = this->InitLiteral(cstr, lenInBytes, &stack->myHeadAPI);
return result; return result;
} }
@ -5935,7 +6025,7 @@ bool DqnString::InitLiteral(char const *const cstr, DqnMemAPI *const api)
bool DqnString::InitLiteral(wchar_t const *const cstr, DqnMemStack *const stack) bool DqnString::InitLiteral(wchar_t const *const cstr, DqnMemStack *const stack)
{ {
bool result = this->InitLiteral(cstr, &stack->myAPI); bool result = this->InitLiteral(cstr, &stack->myHeadAPI);
return result; return result;
} }

View File

@ -1637,7 +1637,7 @@ void DqnArray_Test()
{ {
auto memGuard0 = stack.TempRegionGuard(); auto memGuard0 = stack.TempRegionGuard();
DqnArray<char> array = {}; DqnArray<char> array = {};
DQN_ASSERT(array.InitSize(1, &stack.myAPI)); DQN_ASSERT(array.InitSize(1, &stack.myHeadAPI));
DqnArray_TestRealDataInternal(&array); DqnArray_TestRealDataInternal(&array);
} }
@ -1646,7 +1646,7 @@ void DqnArray_Test()
{ {
auto memGuard0 = stack.TempRegionGuard(); auto memGuard0 = stack.TempRegionGuard();
DqnArray<char> array = {}; DqnArray<char> array = {};
DQN_ASSERT(array.InitSize(128, &stack.myAPI)); DQN_ASSERT(array.InitSize(128, &stack.myHeadAPI));
stack.Push(1024); stack.Push(1024);
DqnArray_TestRealDataInternal(&array); DqnArray_TestRealDataInternal(&array);
} }
@ -2485,7 +2485,7 @@ FILE_SCOPE void DqnMemStack_Test()
DQN_ASSERT(result5); DQN_ASSERT(result5);
DQN_ASSERT(stack.block != blockToReturnTo); DQN_ASSERT(stack.block != blockToReturnTo);
DQN_ASSERT(stack.tempRegionCount == 1); DQN_ASSERT(stack.tempRegionCount == 1);
memGuard1.keepChanges = true; memGuard1.region.keepHeadChanges = true;
} }
DQN_ASSERT(stack.block != blockToReturnTo); DQN_ASSERT(stack.block != blockToReturnTo);
@ -2762,7 +2762,7 @@ FILE_SCOPE void DqnMemStack_Test()
{ {
DqnMemStack stack = {}; DqnMemStack stack = {};
DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard)); DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard));
auto *api = &stack.myAPI; auto *api = &stack.myHeadAPI;
auto *blockBefore = stack.block; auto *blockBefore = stack.block;
auto *headBefore = stack.block->head; auto *headBefore = stack.block->head;
@ -2793,7 +2793,7 @@ FILE_SCOPE void DqnMemStack_Test()
{ {
DqnMemStack stack = {}; DqnMemStack stack = {};
DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard)); DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard));
auto *api = &stack.myAPI; auto *api = &stack.myHeadAPI;
auto *blockBefore = stack.block; auto *blockBefore = stack.block;
auto *tailBefore = stack.block->tail; auto *tailBefore = stack.block->tail;
@ -2829,7 +2829,7 @@ FILE_SCOPE void DqnMemStack_Test()
{ {
DqnMemStack stack = {}; DqnMemStack stack = {};
DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard)); DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard));
auto *api = &stack.myAPI; auto *api = &stack.myHeadAPI;
auto *blockBefore = stack.block; auto *blockBefore = stack.block;
auto *headBefore = stack.block->head; auto *headBefore = stack.block->head;
@ -2859,7 +2859,7 @@ FILE_SCOPE void DqnMemStack_Test()
{ {
DqnMemStack stack = {}; DqnMemStack stack = {};
DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard)); DQN_ASSERT(stack.Init(DQN_MEGABYTE(1), true, DqnMemStack::Flag::BoundsGuard));
auto *api = &stack.myAPI; auto *api = &stack.myHeadAPI;
auto *blockBefore = stack.block; auto *blockBefore = stack.block;
auto *tailBefore = stack.block->tail; auto *tailBefore = stack.block->tail;