|
@@ -1,8 +1,10 @@
|
|
|
#include "anki/util/Memory.h"
|
|
#include "anki/util/Memory.h"
|
|
|
-#include "anki/util/Assert.h"
|
|
|
|
|
#include "anki/util/Exception.h"
|
|
#include "anki/util/Exception.h"
|
|
|
#include "anki/util/Functions.h"
|
|
#include "anki/util/Functions.h"
|
|
|
-#include <limits>
|
|
|
|
|
|
|
+#include "anki/util/Assert.h"
|
|
|
|
|
+#include "anki/util/NonCopyable.h"
|
|
|
|
|
+#include "anki/util/Thread.h"
|
|
|
|
|
+#include "anki/util/Vector.h"
|
|
|
#include <cstdlib>
|
|
#include <cstdlib>
|
|
|
#include <cstring>
|
|
#include <cstring>
|
|
|
|
|
|
|
@@ -68,279 +70,498 @@ void freeAligned(void* ptr)
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-struct MemoryBlockHeader
|
|
|
|
|
|
|
+class StackMemoryPool::Implementation: public NonCopyable
|
|
|
{
|
|
{
|
|
|
- U32 size;
|
|
|
|
|
-};
|
|
|
|
|
|
|
+public:
|
|
|
|
|
+ /// The header of each allocation
|
|
|
|
|
+ struct MemoryBlockHeader
|
|
|
|
|
+ {
|
|
|
|
|
+ U32 size;
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-StackMemoryPool::StackMemoryPool(PtrSize size, U32 alignmentBytes_)
|
|
|
|
|
- : alignmentBytes(alignmentBytes_),
|
|
|
|
|
- memsize(getAlignedRoundUp(alignmentBytes, size))
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(memsize > 0);
|
|
|
|
|
- memory = (U8*)mallocAligned(memsize, alignmentBytes);
|
|
|
|
|
|
|
+ /// Alignment of allocations
|
|
|
|
|
+ U32 alignmentBytes;
|
|
|
|
|
|
|
|
- if(memory != nullptr)
|
|
|
|
|
|
|
+ /// Pre-allocated memory chunk
|
|
|
|
|
+ U8* memory = nullptr;
|
|
|
|
|
+
|
|
|
|
|
+ /// Size of the pre-allocated memory chunk
|
|
|
|
|
+ PtrSize memsize = 0;
|
|
|
|
|
+
|
|
|
|
|
+ /// Points to the memory and more specifically to the top of the stack
|
|
|
|
|
+ std::atomic<U8*> top = {nullptr};
|
|
|
|
|
+
|
|
|
|
|
+ // Construct
|
|
|
|
|
+ Implementation(PtrSize size, U32 alignmentBytes_)
|
|
|
|
|
+ : alignmentBytes(alignmentBytes_),
|
|
|
|
|
+ memsize(getAlignedRoundUp(alignmentBytes, size))
|
|
|
{
|
|
{
|
|
|
- // Align allocated memory
|
|
|
|
|
- top = memory;
|
|
|
|
|
|
|
+ ANKI_ASSERT(memsize > 0);
|
|
|
|
|
+ memory = (U8*)mallocAligned(memsize, alignmentBytes);
|
|
|
|
|
+
|
|
|
|
|
+ if(memory != nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Align allocated memory
|
|
|
|
|
+ top = memory;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ throw ANKI_EXCEPTION("Failed to allocate memory");
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Destroy
|
|
|
|
|
+ ~Implementation()
|
|
|
{
|
|
{
|
|
|
- throw ANKI_EXCEPTION("Failed to allocate memory");
|
|
|
|
|
|
|
+ if(memory != nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ freeAligned(memory);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-StackMemoryPool::~StackMemoryPool()
|
|
|
|
|
-{
|
|
|
|
|
- if(memory != nullptr)
|
|
|
|
|
|
|
+ PtrSize getTotalSize() const
|
|
|
{
|
|
{
|
|
|
- freeAligned(memory);
|
|
|
|
|
|
|
+ return memsize;
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-StackMemoryPool& StackMemoryPool::operator=(StackMemoryPool&& other)
|
|
|
|
|
-{
|
|
|
|
|
- if(memory != nullptr)
|
|
|
|
|
|
|
+ PtrSize getAllocatedSize() const
|
|
|
{
|
|
{
|
|
|
- freeAligned(memory);
|
|
|
|
|
|
|
+ ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
+ return top.load() - memory;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- memory = other.memory;
|
|
|
|
|
- memsize = other.memsize;
|
|
|
|
|
- alignmentBytes = other.alignmentBytes;
|
|
|
|
|
- top.store(other.top.load());
|
|
|
|
|
-
|
|
|
|
|
- other.memory = nullptr;
|
|
|
|
|
- other.memsize = 0;
|
|
|
|
|
- other.top = nullptr;
|
|
|
|
|
-
|
|
|
|
|
- return *this;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ const void* getBaseAddress() const
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
+ return memory;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-PtrSize StackMemoryPool::getAllocatedSize() const
|
|
|
|
|
-{
|
|
|
|
|
- return top.load() - memory;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ /// Allocate
|
|
|
|
|
+ void* allocate(PtrSize size_) throw()
|
|
|
|
|
+ {
|
|
|
|
|
+ // memory is nullptr if moved
|
|
|
|
|
+ ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void* StackMemoryPool::allocate(PtrSize size_) throw()
|
|
|
|
|
-{
|
|
|
|
|
- // memory is nullptr if moved
|
|
|
|
|
- ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
|
|
+ PtrSize headerSize =
|
|
|
|
|
+ getAlignedRoundUp(alignmentBytes, sizeof(MemoryBlockHeader));
|
|
|
|
|
+ PtrSize size =
|
|
|
|
|
+ getAlignedRoundUp(alignmentBytes, size_ + headerSize);
|
|
|
|
|
|
|
|
- PtrSize headerSize =
|
|
|
|
|
- getAlignedRoundUp(alignmentBytes, sizeof(MemoryBlockHeader));
|
|
|
|
|
- PtrSize size =
|
|
|
|
|
- getAlignedRoundUp(alignmentBytes, size_ + headerSize);
|
|
|
|
|
|
|
+ ANKI_ASSERT(size < MAX_U32 && "Too big allocation");
|
|
|
|
|
|
|
|
- ANKI_ASSERT(size < MAX_U32 && "Too big allocation");
|
|
|
|
|
|
|
+ U8* out = top.fetch_add(size);
|
|
|
|
|
|
|
|
- U8* out = top.fetch_add(size);
|
|
|
|
|
|
|
+ if(out + size <= memory + memsize)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Write the block header
|
|
|
|
|
+ ((MemoryBlockHeader*)out)->size = size;
|
|
|
|
|
|
|
|
- if(out + size <= memory + memsize)
|
|
|
|
|
- {
|
|
|
|
|
- // Write the block header
|
|
|
|
|
- ((MemoryBlockHeader*)out)->size = size;
|
|
|
|
|
|
|
+ // Set the correct output
|
|
|
|
|
+ out += headerSize;
|
|
|
|
|
|
|
|
- // Set the correct output
|
|
|
|
|
- out += headerSize;
|
|
|
|
|
|
|
+ // Check alignment
|
|
|
|
|
+ ANKI_ASSERT(isAligned(alignmentBytes, out));
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Error
|
|
|
|
|
+ out = nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Check alignment
|
|
|
|
|
- ANKI_ASSERT(isAligned(alignmentBytes, out));
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // Error
|
|
|
|
|
- out = nullptr;
|
|
|
|
|
|
|
+ return out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return out;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-Bool StackMemoryPool::free(void* ptr) throw()
|
|
|
|
|
-{
|
|
|
|
|
- // ptr shouldn't be null or not aligned. If not aligned it was not
|
|
|
|
|
- // allocated by this class
|
|
|
|
|
- ANKI_ASSERT(ptr != nullptr && isAligned(alignmentBytes, ptr));
|
|
|
|
|
|
|
+ /// Free
|
|
|
|
|
+ Bool free(void* ptr) throw()
|
|
|
|
|
+ {
|
|
|
|
|
+ // ptr shouldn't be null or not aligned. If not aligned it was not
|
|
|
|
|
+ // allocated by this class
|
|
|
|
|
+ ANKI_ASSERT(ptr != nullptr && isAligned(alignmentBytes, ptr));
|
|
|
|
|
|
|
|
- // memory is nullptr if moved
|
|
|
|
|
- ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
|
|
+ // memory is nullptr if moved
|
|
|
|
|
+ ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
|
|
|
- // Correct the p
|
|
|
|
|
- PtrSize headerSize =
|
|
|
|
|
- getAlignedRoundUp(alignmentBytes, sizeof(MemoryBlockHeader));
|
|
|
|
|
- U8* realptr = (U8*)ptr - headerSize;
|
|
|
|
|
|
|
+ // Correct the p
|
|
|
|
|
+ PtrSize headerSize =
|
|
|
|
|
+ getAlignedRoundUp(alignmentBytes, sizeof(MemoryBlockHeader));
|
|
|
|
|
+ U8* realptr = (U8*)ptr - headerSize;
|
|
|
|
|
|
|
|
- // realptr should be inside the pool's preallocated memory
|
|
|
|
|
- ANKI_ASSERT(realptr >= memory);
|
|
|
|
|
|
|
+ // realptr should be inside the pool's preallocated memory
|
|
|
|
|
+ ANKI_ASSERT(realptr >= memory);
|
|
|
|
|
|
|
|
- // Get block size
|
|
|
|
|
- U32 size = ((MemoryBlockHeader*)realptr)->size;
|
|
|
|
|
|
|
+ // Get block size
|
|
|
|
|
+ U32 size = ((MemoryBlockHeader*)realptr)->size;
|
|
|
|
|
|
|
|
- // Check if the size is ok
|
|
|
|
|
- ANKI_ASSERT(realptr + size <= memory + memsize);
|
|
|
|
|
|
|
+ // Check if the size is ok
|
|
|
|
|
+ ANKI_ASSERT(realptr + size <= memory + memsize);
|
|
|
|
|
|
|
|
- // Atomic stuff
|
|
|
|
|
- U8* expected = realptr + size;
|
|
|
|
|
- U8* desired = realptr;
|
|
|
|
|
|
|
+ // Atomic stuff
|
|
|
|
|
+ U8* expected = realptr + size;
|
|
|
|
|
+ U8* desired = realptr;
|
|
|
|
|
|
|
|
- // if(top == expected) {
|
|
|
|
|
- // top = desired;
|
|
|
|
|
- // exchange = true;
|
|
|
|
|
- // } else {
|
|
|
|
|
- // expected = top;
|
|
|
|
|
- // exchange = false;
|
|
|
|
|
- // }
|
|
|
|
|
- Bool exchange = top.compare_exchange_strong(expected, desired);
|
|
|
|
|
|
|
+ // if(top == expected) {
|
|
|
|
|
+ // top = desired;
|
|
|
|
|
+ // exchange = true;
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // expected = top;
|
|
|
|
|
+ // exchange = false;
|
|
|
|
|
+ // }
|
|
|
|
|
+ Bool exchange = top.compare_exchange_strong(expected, desired);
|
|
|
|
|
|
|
|
- return exchange;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ return exchange;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void StackMemoryPool::reset()
|
|
|
|
|
-{
|
|
|
|
|
- // memory is nullptr if moved
|
|
|
|
|
- ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
|
|
+ /// Reset
|
|
|
|
|
+ void reset()
|
|
|
|
|
+ {
|
|
|
|
|
+ // memory is nullptr if moved
|
|
|
|
|
+ ANKI_ASSERT(memory != nullptr);
|
|
|
|
|
|
|
|
#if ANKI_DEBUG
|
|
#if ANKI_DEBUG
|
|
|
- // Invalidate the memory
|
|
|
|
|
- memset(memory, 0xCC, memsize);
|
|
|
|
|
|
|
+ // Invalidate the memory
|
|
|
|
|
+ memset(memory, 0xCC, memsize);
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
- top = memory;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ top = memory;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-// ChainMemoryPool =
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
|
|
+StackMemoryPool::StackMemoryPool(PtrSize size, U32 alignmentBytes)
|
|
|
|
|
+{
|
|
|
|
|
+ impl.reset(new Implementation(size, alignmentBytes));
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-ChainMemoryPool::ChainMemoryPool(
|
|
|
|
|
- NextChunkAllocationMethod allocMethod,
|
|
|
|
|
- U32 allocMethodValue,
|
|
|
|
|
- U32 alignmentBytes_)
|
|
|
|
|
- : alignmentBytes(alignmentBytes_),
|
|
|
|
|
- chAllocMethodValue(allocMethodValue),
|
|
|
|
|
- chAllocMethod(allocMethod)
|
|
|
|
|
|
|
+StackMemoryPool::~StackMemoryPool()
|
|
|
{}
|
|
{}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-ChainMemoryPool::~ChainMemoryPool()
|
|
|
|
|
|
|
+PtrSize StackMemoryPool::getTotalSize() const
|
|
|
{
|
|
{
|
|
|
- // TODO
|
|
|
|
|
|
|
+ ANKI_ASSERT(impl.get() != nullptr);
|
|
|
|
|
+ return impl->getTotalSize();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void* ChainMemoryPool::allocateFromChunk(Chunk* ch, PtrSize size) throw()
|
|
|
|
|
|
|
+PtrSize StackMemoryPool::getAllocatedSize() const
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(ch);
|
|
|
|
|
- void* mem = ch->pool.allocate(size);
|
|
|
|
|
|
|
+ ANKI_ASSERT(impl.get() != nullptr);
|
|
|
|
|
+ return impl->getAllocatedSize();
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if(mem)
|
|
|
|
|
- {
|
|
|
|
|
- ++ch->allocationsCount;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void* StackMemoryPool::allocate(PtrSize size) throw()
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(impl.get() != nullptr);
|
|
|
|
|
+ return impl->allocate(size);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- return mem;
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Bool StackMemoryPool::free(void* ptr) throw()
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(impl.get() != nullptr);
|
|
|
|
|
+ return impl->free(ptr);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-ChainMemoryPool::Chunk* ChainMemoryPool::createNewChunk(PtrSize size) throw()
|
|
|
|
|
|
|
+void StackMemoryPool::reset()
|
|
|
{
|
|
{
|
|
|
- //
|
|
|
|
|
- // Calculate preferred size
|
|
|
|
|
- //
|
|
|
|
|
-
|
|
|
|
|
- // Get the size of the next chunk
|
|
|
|
|
- PtrSize crntMaxSize;
|
|
|
|
|
- if(chAllocMethod == FIXED)
|
|
|
|
|
|
|
+ ANKI_ASSERT(impl.get() != nullptr);
|
|
|
|
|
+ impl->reset();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+// ChainMemoryPool =
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+class ChainMemoryPool::Implementation: public NonCopyable
|
|
|
|
|
+{
|
|
|
|
|
+public:
|
|
|
|
|
+ /// A chunk of memory
|
|
|
|
|
+ class Chunk
|
|
|
{
|
|
{
|
|
|
- crntMaxSize = chAllocMethodValue;
|
|
|
|
|
|
|
+ public:
|
|
|
|
|
+ StackMemoryPool::Implementation pool;
|
|
|
|
|
+ U32 allocationsCount;
|
|
|
|
|
+
|
|
|
|
|
+ Chunk(PtrSize size, U32 alignmentBytes)
|
|
|
|
|
+ : pool(size, alignmentBytes), allocationsCount(0)
|
|
|
|
|
+ {}
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ /// Alignment of allocations
|
|
|
|
|
+ U32 alignmentBytes;
|
|
|
|
|
+
|
|
|
|
|
+ /// A list of chunks
|
|
|
|
|
+ Vector<Chunk*> chunks;
|
|
|
|
|
+
|
|
|
|
|
+ /// Current chunk to allocate from
|
|
|
|
|
+ Chunk* crntChunk = nullptr;
|
|
|
|
|
+
|
|
|
|
|
+ /// Fast thread locking
|
|
|
|
|
+ SpinLock lock;
|
|
|
|
|
+
|
|
|
|
|
+ /// Chunk first chunk size
|
|
|
|
|
+ U32 initSize;
|
|
|
|
|
+
|
|
|
|
|
+ /// Chunk max size
|
|
|
|
|
+ U32 maxSize;
|
|
|
|
|
+
|
|
|
|
|
+ /// Chunk allocation method value
|
|
|
|
|
+ U32 step;
|
|
|
|
|
+
|
|
|
|
|
+ /// Chunk allocation method
|
|
|
|
|
+ U8 method;
|
|
|
|
|
+
|
|
|
|
|
+ /// Construct
|
|
|
|
|
+ Implementation(
|
|
|
|
|
+ U32 initialChunkSize,
|
|
|
|
|
+ U32 maxChunkSize,
|
|
|
|
|
+ ChunkAllocationStepMethod chunkAllocStepMethod,
|
|
|
|
|
+ U32 chunkAllocStep,
|
|
|
|
|
+ U32 alignmentBytes_)
|
|
|
|
|
+ : alignmentBytes(alignmentBytes_),
|
|
|
|
|
+ initSize(initialChunkSize),
|
|
|
|
|
+ maxSize(maxChunkSize),
|
|
|
|
|
+ step(chunkAllocStep),
|
|
|
|
|
+ method(chunkAllocStepMethod)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Initial size should be > 0
|
|
|
|
|
+ ANKI_ASSERT(initSize > 0);
|
|
|
|
|
+
|
|
|
|
|
+ // On fixed step should be 0
|
|
|
|
|
+ ANKI_ASSERT(!(method == FIXED && step != 0));
|
|
|
|
|
+
|
|
|
|
|
+ // On fixed initial size is the same as the max
|
|
|
|
|
+ ANKI_ASSERT(!(method == FIXED && initSize != maxSize));
|
|
|
|
|
+
|
|
|
|
|
+ // On add and mul the max size should be greater than initial
|
|
|
|
|
+ ANKI_ASSERT(!(
|
|
|
|
|
+ (method == ADD || method == MULTIPLY) && initSize < maxSize));
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /// Destroy
|
|
|
|
|
+ ~Implementation()
|
|
|
|
|
+ {
|
|
|
|
|
+ for(Chunk* ch : chunks)
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(ch);
|
|
|
|
|
+ delete ch;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Create a new chunk
|
|
|
|
|
+ Chunk* createNewChunk(PtrSize size) throw()
|
|
|
{
|
|
{
|
|
|
- // Get the size of the previous max chunk
|
|
|
|
|
- crntMaxSize = 0;
|
|
|
|
|
- for(Chunk* c : chunks)
|
|
|
|
|
|
|
+ ANKI_ASSERT(size <= maxSize && "To big chunk");
|
|
|
|
|
+ //
|
|
|
|
|
+ // Calculate preferred size
|
|
|
|
|
+ //
|
|
|
|
|
+
|
|
|
|
|
+ // Get the size of the next chunk
|
|
|
|
|
+ PtrSize crntMaxSize;
|
|
|
|
|
+ if(method == FIXED)
|
|
|
{
|
|
{
|
|
|
- if(c)
|
|
|
|
|
|
|
+ crntMaxSize = initSize;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Get the size of the previous max chunk
|
|
|
|
|
+ if(chunks.size() > 0)
|
|
|
{
|
|
{
|
|
|
- PtrSize poolSize = c->pool.getSize();
|
|
|
|
|
- crntMaxSize = std::max(crntMaxSize, poolSize);
|
|
|
|
|
|
|
+ // Get the size of previous
|
|
|
|
|
+ crntMaxSize = chunks.back()->pool.getTotalSize();
|
|
|
|
|
+
|
|
|
|
|
+ // Increase it
|
|
|
|
|
+ if(method == MULTIPLY)
|
|
|
|
|
+ {
|
|
|
|
|
+ crntMaxSize *= step;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(method == ADD);
|
|
|
|
|
+ crntMaxSize += step;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // No chunks. Choose initial size
|
|
|
|
|
+
|
|
|
|
|
+ ANKI_ASSERT(crntChunk == nullptr);
|
|
|
|
|
+ crntMaxSize = initSize;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ANKI_ASSERT(crntMaxSize > 0);
|
|
|
|
|
+
|
|
|
|
|
+ // Fix the size
|
|
|
|
|
+ crntMaxSize = std::min(crntMaxSize, (PtrSize)maxSize);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Increase it
|
|
|
|
|
- if(chAllocMethod == MULTIPLY)
|
|
|
|
|
|
|
+ size = crntMaxSize;
|
|
|
|
|
+
|
|
|
|
|
+ //
|
|
|
|
|
+ // Create the chunk
|
|
|
|
|
+ //
|
|
|
|
|
+ Chunk* chunk = new Chunk(size, alignmentBytes);
|
|
|
|
|
+
|
|
|
|
|
+ if(chunk)
|
|
|
{
|
|
{
|
|
|
- crntMaxSize *= chAllocMethodValue;
|
|
|
|
|
|
|
+ chunks.push_back(chunk);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(chAllocMethod == ADD);
|
|
|
|
|
- crntMaxSize += chAllocMethodValue;
|
|
|
|
|
|
|
+ throw ANKI_EXCEPTION("Chunk creation failed");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return chunk;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Fix the size
|
|
|
|
|
- size = std::max(crntMaxSize, size * 2);
|
|
|
|
|
-
|
|
|
|
|
- //
|
|
|
|
|
- // Create the chunk
|
|
|
|
|
- //
|
|
|
|
|
- Chunk* chunk = new Chunk(size, alignmentBytes);
|
|
|
|
|
-
|
|
|
|
|
- if(chunk)
|
|
|
|
|
|
|
+ /// Allocate from chunk
|
|
|
|
|
+ void* allocateFromChunk(Chunk* ch, PtrSize size) throw()
|
|
|
{
|
|
{
|
|
|
- chunks.push_back(chunk);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return chunk;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ ANKI_ASSERT(ch);
|
|
|
|
|
+ ANKI_ASSERT(size <= maxSize);
|
|
|
|
|
+ void* mem = ch->pool.allocate(size);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void* ChainMemoryPool::allocate(PtrSize size) throw()
|
|
|
|
|
-{
|
|
|
|
|
- Chunk* ch;
|
|
|
|
|
- void* mem = nullptr;
|
|
|
|
|
|
|
+ if(mem)
|
|
|
|
|
+ {
|
|
|
|
|
+ ++ch->allocationsCount;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Get chunk
|
|
|
|
|
- lock.lock();
|
|
|
|
|
- ch = crntChunk;
|
|
|
|
|
- lock.unlock();
|
|
|
|
|
|
|
+ return mem;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Create new chunk if needed
|
|
|
|
|
- if(ch == nullptr || (mem = allocateFromChunk(ch, size)) == nullptr)
|
|
|
|
|
|
|
+ /// Allocate memory
|
|
|
|
|
+ void* allocate(PtrSize size) throw()
|
|
|
{
|
|
{
|
|
|
- // Create new chunk
|
|
|
|
|
|
|
+ Chunk* ch;
|
|
|
|
|
+ void* mem = nullptr;
|
|
|
|
|
+
|
|
|
lock.lock();
|
|
lock.lock();
|
|
|
|
|
|
|
|
- crntChunk = createNewChunk(size);
|
|
|
|
|
|
|
+ // Get chunk
|
|
|
ch = crntChunk;
|
|
ch = crntChunk;
|
|
|
|
|
|
|
|
- lock.unlock();
|
|
|
|
|
|
|
+ // Create new chunk if needed
|
|
|
|
|
+ if(ch == nullptr || (mem = allocateFromChunk(ch, size)) == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create new chunk
|
|
|
|
|
+ crntChunk = createNewChunk(size);
|
|
|
|
|
+ ch = crntChunk;
|
|
|
|
|
|
|
|
- // Chunk creation failed
|
|
|
|
|
- if(ch == nullptr)
|
|
|
|
|
|
|
+ // Chunk creation failed
|
|
|
|
|
+ if(ch == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ lock.unlock();
|
|
|
|
|
+ return mem;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(mem == nullptr)
|
|
|
{
|
|
{
|
|
|
- return mem;
|
|
|
|
|
|
|
+ mem = allocateFromChunk(ch, size);
|
|
|
|
|
+ ANKI_ASSERT(mem != nullptr && "The chunk should have space");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ lock.unlock();
|
|
|
|
|
+ return mem;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if(mem == nullptr)
|
|
|
|
|
|
|
+ /// Free memory
|
|
|
|
|
+ Bool free(void* ptr) throw()
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(ch != nullptr);
|
|
|
|
|
- mem = allocateFromChunk(ch, size);
|
|
|
|
|
- ANKI_ASSERT(mem != nullptr && "The chunk should have space");
|
|
|
|
|
|
|
+ lock.lock();
|
|
|
|
|
+
|
|
|
|
|
+ // Get the chunk that ptr belongs to
|
|
|
|
|
+ Vector<Chunk*>::iterator it;
|
|
|
|
|
+ for(it = chunks.begin(); it != chunks.end(); it++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Chunk* ch = *it;
|
|
|
|
|
+ ANKI_ASSERT(ch);
|
|
|
|
|
+
|
|
|
|
|
+ const U8* from = (const U8*)ch->pool.getBaseAddress();
|
|
|
|
|
+ const U8* to = from + ch->pool.getTotalSize();
|
|
|
|
|
+ const U8* cptr = (const U8*)ptr;
|
|
|
|
|
+ if(cptr >= from && cptr < to)
|
|
|
|
|
+ {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ANKI_ASSERT(it != chunks.end()
|
|
|
|
|
+ && "Not initialized or ptr is incorrect");
|
|
|
|
|
+
|
|
|
|
|
+ // Decrease the deallocation refcount and if it's zero delete the chunk
|
|
|
|
|
+ ANKI_ASSERT((*it)->allocationsCount > 0);
|
|
|
|
|
+ if(--(*it)->allocationsCount == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Chunk is empty. Delete it
|
|
|
|
|
+
|
|
|
|
|
+ Chunk* ch = *it;
|
|
|
|
|
+ ANKI_ASSERT(ch);
|
|
|
|
|
+
|
|
|
|
|
+ delete ch;
|
|
|
|
|
+ chunks.erase(it);
|
|
|
|
|
+
|
|
|
|
|
+ // Change the crntChunk
|
|
|
|
|
+ ANKI_ASSERT(crntChunk);
|
|
|
|
|
+ if(ch == crntChunk)
|
|
|
|
|
+ {
|
|
|
|
|
+ // If there are chunks chose the last. It's probably full but
|
|
|
|
|
+ // let the allocate() create a new one
|
|
|
|
|
+ if(chunks.size() > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ crntChunk = chunks.back();
|
|
|
|
|
+ ANKI_ASSERT(crntChunk);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ crntChunk = nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ lock.unlock();
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+ChainMemoryPool::ChainMemoryPool(
|
|
|
|
|
+ U32 initialChunkSize,
|
|
|
|
|
+ U32 maxChunkSize,
|
|
|
|
|
+ ChunkAllocationStepMethod chunkAllocStepMethod,
|
|
|
|
|
+ U32 chunkAllocStep,
|
|
|
|
|
+ U32 alignmentBytes)
|
|
|
|
|
+{
|
|
|
|
|
+ impl.reset(new Implementation(
|
|
|
|
|
+ initialChunkSize, maxChunkSize, chunkAllocStepMethod, chunkAllocStep,
|
|
|
|
|
+ alignmentBytes));
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- return mem;
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+ChainMemoryPool::~ChainMemoryPool()
|
|
|
|
|
+{}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void* ChainMemoryPool::allocate(PtrSize size) throw()
|
|
|
|
|
+{
|
|
|
|
|
+ return impl->allocate(size);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Bool ChainMemoryPool::free(void* ptr) throw()
|
|
|
|
|
+{
|
|
|
|
|
+ return impl->free(ptr);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+PtrSize ChainMemoryPool::getChunksCount() const
|
|
|
|
|
+{
|
|
|
|
|
+ return impl->chunks.size();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // end namespace anki
|
|
} // end namespace anki
|