SSE2: Implement alignment for arena allocator

This commit is contained in:
kaetemi 2014-06-13 19:26:22 +02:00
parent 641f8552e4
commit 2b9a54a503
3 changed files with 21 additions and 11 deletions

View file

@ -53,6 +53,7 @@ public:
uint getNumAllocatedBlocks() const { return _NumAlloc; }
private:
class CChunk;
NL_ALIGN(NL_DEFAULT_MEMORY_ALIGNMENT)
class CNode
{
public:

View file

@ -33,6 +33,9 @@ CFixedSizeAllocator::CFixedSizeAllocator(uint numBytesPerBlock, uint numBlockPer
_NumChunks = 0;
nlassert(numBytesPerBlock > 1);
_NumBytesPerBlock = numBytesPerBlock;
const uint mask = NL_DEFAULT_MEMORY_ALIGNMENT - 1;
_NumBytesPerBlock = (_NumBytesPerBlock + mask) & ~mask;
nlassert(_NumBytesPerBlock >= numBytesPerBlock);
_NumBlockPerChunk = std::max(numBlockPerChunk, (uint) 3);
_NumAlloc = 0;
}
@ -67,12 +70,14 @@ void *CFixedSizeAllocator::alloc()
return _FreeSpace->unlink();
}
#define aligned_offsetof(s, m) ((offsetof(s, m) + (NL_DEFAULT_MEMORY_ALIGNMENT - 1)) & ~(NL_DEFAULT_MEMORY_ALIGNMENT - 1))
// *****************************************************************************************************************
void CFixedSizeAllocator::free(void *block)
{
if (!block) return;
/// get the node from the object
CNode *node = (CNode *) ((uint8 *) block - offsetof(CNode, Next));
CNode *node = (CNode *) ((uint8 *) block - aligned_offsetof(CNode, Next));
//
nlassert(node->Chunk != NULL);
nlassert(node->Chunk->Allocator == this);
@ -84,7 +89,9 @@ void CFixedSizeAllocator::free(void *block)
// *****************************************************************************************************************
uint CFixedSizeAllocator::CChunk::getBlockSizeWithOverhead() const
{
return std::max((uint)(sizeof(CNode) - offsetof(CNode, Next)),(uint)(Allocator->getNumBytesPerBlock())) + offsetof(CNode, Next);
nlctassert((sizeof(CNode) % NL_DEFAULT_MEMORY_ALIGNMENT) == 0);
return std::max((uint)(sizeof(CNode) - aligned_offsetof(CNode, Next)),
(uint)(Allocator->getNumBytesPerBlock())) + aligned_offsetof(CNode, Next);
}
// *****************************************************************************************************************
@ -105,7 +112,7 @@ CFixedSizeAllocator::CChunk::~CChunk()
nlassert(NumFreeObjs == 0);
nlassert(Allocator->_NumChunks > 0);
-- (Allocator->_NumChunks);
delete[] Mem;
aligned_free(Mem); //delete[] Mem;
}
// *****************************************************************************************************************
@ -115,7 +122,7 @@ void CFixedSizeAllocator::CChunk::init(CFixedSizeAllocator *alloc)
nlassert(alloc != NULL);
Allocator = alloc;
//
Mem = new uint8[getBlockSizeWithOverhead() * alloc->getNumBlockPerChunk()];
Mem = (uint8 *)aligned_malloc(getBlockSizeWithOverhead() * alloc->getNumBlockPerChunk(), NL_DEFAULT_MEMORY_ALIGNMENT); // new uint8[getBlockSizeWithOverhead() * alloc->getNumBlockPerChunk()];
//
getNode(0).Chunk = this;
getNode(0).Next = &getNode(1);
@ -179,7 +186,7 @@ void *CFixedSizeAllocator::CNode::unlink()
*Prev = Next;
nlassert(Chunk->NumFreeObjs > 0);
Chunk->grab(); // tells the containing chunk that a node has been allocated
return (void *) &Next;
return (void *)((uintptr_t)(this) + aligned_offsetof(CNode, Next)); //(void *) &Next;
}
// *****************************************************************************************************************

View file

@ -68,21 +68,23 @@ void *CObjectArenaAllocator::alloc(uint size)
if (size >= _MaxAllocSize)
{
// use standard allocator
uint8 *block = new uint8[size + sizeof(uint)]; // an additionnal uint is needed to store size of block
nlctassert(NL_DEFAULT_MEMORY_ALIGNMENT > sizeof(uint));
uint8 *block = (uint8 *)aligned_malloc(NL_DEFAULT_MEMORY_ALIGNMENT + size, NL_DEFAULT_MEMORY_ALIGNMENT); //new uint8[size + sizeof(uint)]; // an additionnal uint is needed to store size of block
if (!block) return NULL;
#ifdef NL_DEBUG
_MemBlockToAllocID[block] = _AllocID;
#endif
*(uint *) block = size;
return block + sizeof(uint);
return block + NL_DEFAULT_MEMORY_ALIGNMENT;
}
uint entry = ((size + (_Granularity - 1)) / _Granularity) ;
nlassert(entry < _ObjectSizeToAllocator.size());
if (!_ObjectSizeToAllocator[entry])
{
_ObjectSizeToAllocator[entry] = new CFixedSizeAllocator(entry * _Granularity + sizeof(uint), _MaxAllocSize / size); // an additionnal uint is needed to store size of block
_ObjectSizeToAllocator[entry] = new CFixedSizeAllocator(entry * _Granularity + NL_DEFAULT_MEMORY_ALIGNMENT, _MaxAllocSize / size); // an additionnal uint is needed to store size of block
}
void *block = _ObjectSizeToAllocator[entry]->alloc();
nlassert(((uintptr_t)block % NL_DEFAULT_MEMORY_ALIGNMENT) == 0);
#ifdef NL_DEBUG
if (block)
{
@ -91,14 +93,14 @@ void *CObjectArenaAllocator::alloc(uint size)
++_AllocID;
#endif
*(uint *) block = size;
return (void *) ((uint8 *) block + sizeof(uint));
return (void *) ((uint8 *) block + NL_DEFAULT_MEMORY_ALIGNMENT);
}
// *****************************************************************************************************************
void CObjectArenaAllocator::free(void *block)
{
if (!block) return;
uint8 *realBlock = (uint8 *) block - sizeof(uint); // a uint is used at start of block to give its size
uint8 *realBlock = (uint8 *) block - NL_DEFAULT_MEMORY_ALIGNMENT; // sizeof(uint); // a uint is used at start of block to give its size
uint size = *(uint *) realBlock;
if (size >= _MaxAllocSize)
{
@ -107,7 +109,7 @@ void CObjectArenaAllocator::free(void *block)
nlassert(it != _MemBlockToAllocID.end());
_MemBlockToAllocID.erase(it);
#endif
delete realBlock;
aligned_free(realBlock);
return;
}
uint entry = ((size + (_Granularity - 1)) / _Granularity);