Enhance HeapAllocator with custom alignments
Related-To: NEO-5750 Signed-off-by: Maciej Dziuban <maciej.dziuban@intel.com>
This commit is contained in:
parent
0285bab7cf
commit
32025efafb
|
@ -40,6 +40,11 @@ class HeapAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t allocate(size_t &sizeToAllocate) {
|
uint64_t allocate(size_t &sizeToAllocate) {
|
||||||
|
return allocateWithCustomAlignment(sizeToAllocate, this->allocationAlignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t allocateWithCustomAlignment(size_t &sizeToAllocate, size_t alignment) {
|
||||||
|
UNRECOVERABLE_IF(alignment % allocationAlignment != 0); // custom alignment have to be a multiple of allocator alignment
|
||||||
sizeToAllocate = alignUp(sizeToAllocate, allocationAlignment);
|
sizeToAllocate = alignUp(sizeToAllocate, allocationAlignment);
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
|
@ -53,16 +58,26 @@ class HeapAllocator {
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t sizeOfFreedChunk = 0;
|
size_t sizeOfFreedChunk = 0;
|
||||||
uint64_t ptrReturn = getFromFreedChunks(sizeToAllocate, freedChunks, sizeOfFreedChunk);
|
uint64_t ptrReturn = getFromFreedChunks(sizeToAllocate, freedChunks, sizeOfFreedChunk, alignment);
|
||||||
|
|
||||||
if (ptrReturn == 0llu) {
|
if (ptrReturn == 0llu) {
|
||||||
if (sizeToAllocate > sizeThreshold) {
|
if (sizeToAllocate > sizeThreshold) {
|
||||||
if (pLeftBound + sizeToAllocate <= pRightBound) {
|
const uint64_t misalignment = alignUp(pLeftBound, alignment) - pLeftBound;
|
||||||
|
if (pLeftBound + misalignment + sizeToAllocate <= pRightBound) {
|
||||||
|
if (misalignment) {
|
||||||
|
storeInFreedChunks(pLeftBound, static_cast<size_t>(misalignment), freedChunks);
|
||||||
|
pLeftBound += misalignment;
|
||||||
|
}
|
||||||
ptrReturn = pLeftBound;
|
ptrReturn = pLeftBound;
|
||||||
pLeftBound += sizeToAllocate;
|
pLeftBound += sizeToAllocate;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pRightBound - sizeToAllocate >= pLeftBound) {
|
const uint64_t misalignment = pRightBound - alignDown(pRightBound, alignment);
|
||||||
|
if (pLeftBound + sizeToAllocate + misalignment <= pRightBound) {
|
||||||
|
if (misalignment) {
|
||||||
|
pRightBound -= misalignment;
|
||||||
|
storeInFreedChunks(pRightBound, static_cast<size_t>(misalignment), freedChunks);
|
||||||
|
}
|
||||||
pRightBound -= sizeToAllocate;
|
pRightBound -= sizeToAllocate;
|
||||||
ptrReturn = pRightBound;
|
ptrReturn = pRightBound;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +91,7 @@ class HeapAllocator {
|
||||||
} else {
|
} else {
|
||||||
availableSize -= sizeToAllocate;
|
availableSize -= sizeToAllocate;
|
||||||
}
|
}
|
||||||
|
DEBUG_BREAK_IF(!isAligned(ptrReturn, alignment));
|
||||||
return ptrReturn;
|
return ptrReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,13 +149,18 @@ class HeapAllocator {
|
||||||
std::vector<HeapChunk> freedChunksBig;
|
std::vector<HeapChunk> freedChunksBig;
|
||||||
std::mutex mtx;
|
std::mutex mtx;
|
||||||
|
|
||||||
uint64_t getFromFreedChunks(size_t size, std::vector<HeapChunk> &freedChunks, size_t &sizeOfFreedChunk) {
|
uint64_t getFromFreedChunks(size_t size, std::vector<HeapChunk> &freedChunks, size_t &sizeOfFreedChunk, size_t requiredAlignment) {
|
||||||
size_t elements = freedChunks.size();
|
size_t elements = freedChunks.size();
|
||||||
size_t bestFitIndex = -1;
|
size_t bestFitIndex = -1;
|
||||||
size_t bestFitSize = 0;
|
size_t bestFitSize = 0;
|
||||||
sizeOfFreedChunk = 0;
|
sizeOfFreedChunk = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < elements; i++) {
|
for (size_t i = 0; i < elements; i++) {
|
||||||
|
const bool chunkAligned = isAligned(freedChunks[i].ptr, requiredAlignment);
|
||||||
|
if (!chunkAligned) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (freedChunks[i].size == size) {
|
if (freedChunks[i].size == size) {
|
||||||
auto ptr = freedChunks[i].ptr;
|
auto ptr = freedChunks[i].ptr;
|
||||||
freedChunks.erase(freedChunks.begin() + i);
|
freedChunks.erase(freedChunks.begin() + i);
|
||||||
|
|
|
@ -31,9 +31,9 @@ class HeapAllocatorUnderTest : public HeapAllocator {
|
||||||
size_t getThresholdSize() const { return this->sizeThreshold; }
|
size_t getThresholdSize() const { return this->sizeThreshold; }
|
||||||
using HeapAllocator::defragment;
|
using HeapAllocator::defragment;
|
||||||
|
|
||||||
uint64_t getFromFreedChunks(size_t size, std::vector<HeapChunk> &vec) {
|
uint64_t getFromFreedChunks(size_t size, std::vector<HeapChunk> &vec, size_t requiredAlignment) {
|
||||||
size_t sizeOfFreedChunk;
|
size_t sizeOfFreedChunk;
|
||||||
return HeapAllocator::getFromFreedChunks(size, vec, sizeOfFreedChunk);
|
return HeapAllocator::getFromFreedChunks(size, vec, sizeOfFreedChunk, requiredAlignment);
|
||||||
}
|
}
|
||||||
void storeInFreedChunks(uint64_t ptr, size_t size, std::vector<HeapChunk> &vec) { return HeapAllocator::storeInFreedChunks(ptr, size, vec); }
|
void storeInFreedChunks(uint64_t ptr, size_t size, std::vector<HeapChunk> &vec) { return HeapAllocator::storeInFreedChunks(ptr, size, vec); }
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ TEST(HeapAllocatorTest, GivenExactSizeChunkInFreedChunksWhenGetIsCalledThenChunk
|
||||||
size_t sizeFreed = MemoryConstants::pageSize * 2;
|
size_t sizeFreed = MemoryConstants::pageSize * 2;
|
||||||
freedChunks.emplace_back(ptrFreed, sizeFreed);
|
freedChunks.emplace_back(ptrFreed, sizeFreed);
|
||||||
|
|
||||||
auto ptrReturned = heapAllocator->getFromFreedChunks(sizeFreed, freedChunks);
|
auto ptrReturned = heapAllocator->getFromFreedChunks(sizeFreed, freedChunks, allocationAlignment);
|
||||||
|
|
||||||
EXPECT_EQ(ptrFreed, ptrReturned); // ptr returned is the one that was stored
|
EXPECT_EQ(ptrFreed, ptrReturned); // ptr returned is the one that was stored
|
||||||
EXPECT_EQ(0u, freedChunks.size()); // entry in freed container is removed
|
EXPECT_EQ(0u, freedChunks.size()); // entry in freed container is removed
|
||||||
|
@ -107,7 +107,7 @@ TEST(HeapAllocatorTest, GivenOnlySmallerSizeChunksInFreedChunksWhenGetIsCalledTh
|
||||||
|
|
||||||
EXPECT_EQ(7u, freedChunks.size());
|
EXPECT_EQ(7u, freedChunks.size());
|
||||||
|
|
||||||
auto ptrReturned = heapAllocator->getFromFreedChunks(4 * 4096, freedChunks);
|
auto ptrReturned = heapAllocator->getFromFreedChunks(4 * 4096, freedChunks, allocationAlignment);
|
||||||
|
|
||||||
EXPECT_EQ(0llu, ptrReturned);
|
EXPECT_EQ(0llu, ptrReturned);
|
||||||
EXPECT_EQ(7u, freedChunks.size());
|
EXPECT_EQ(7u, freedChunks.size());
|
||||||
|
@ -138,7 +138,7 @@ TEST(HeapAllocatorTest, GivenOnlyBiggerSizeChunksInFreedChunksWhenGetIsCalledThe
|
||||||
|
|
||||||
EXPECT_EQ(5u, freedChunks.size());
|
EXPECT_EQ(5u, freedChunks.size());
|
||||||
|
|
||||||
auto ptrReturned = heapAllocator->getFromFreedChunks(3 * 4096, freedChunks);
|
auto ptrReturned = heapAllocator->getFromFreedChunks(3 * 4096, freedChunks, allocationAlignment);
|
||||||
|
|
||||||
EXPECT_EQ(ptrExpected, ptrReturned);
|
EXPECT_EQ(ptrExpected, ptrReturned);
|
||||||
EXPECT_EQ(4u, freedChunks.size());
|
EXPECT_EQ(4u, freedChunks.size());
|
||||||
|
@ -166,7 +166,7 @@ TEST(HeapAllocatorTest, GivenOnlyMoreThanTwiceBiggerSizeChunksInFreedChunksWhenG
|
||||||
|
|
||||||
EXPECT_EQ(3u, freedChunks.size());
|
EXPECT_EQ(3u, freedChunks.size());
|
||||||
|
|
||||||
auto ptrReturned = heapAllocator->getFromFreedChunks(requestedSize, freedChunks);
|
auto ptrReturned = heapAllocator->getFromFreedChunks(requestedSize, freedChunks, allocationAlignment);
|
||||||
|
|
||||||
EXPECT_EQ(ptrExpected, ptrReturned);
|
EXPECT_EQ(ptrExpected, ptrReturned);
|
||||||
EXPECT_EQ(3u, freedChunks.size());
|
EXPECT_EQ(3u, freedChunks.size());
|
||||||
|
@ -1000,3 +1000,366 @@ TEST(HeapAllocatorTest, Given10SmallAllocationsWhenMergedToBigAllocatedAsSmallNo
|
||||||
EXPECT_EQ(0u, freedChunksSmall.size());
|
EXPECT_EQ(0u, freedChunksSmall.size());
|
||||||
EXPECT_EQ(0u, freedChunksBig.size());
|
EXPECT_EQ(0u, freedChunksBig.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenAlignedBoundWhenAllocatingMemoryWithCustomAlignmentFromLeftThenReturnAllocations) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + heapSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(32 * MemoryConstants::pageSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase, ptr);
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
|
||||||
|
ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + heapSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(32 * MemoryConstants::pageSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, ptr);
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenAlignedBoundWhenAllocatingMemoryWithCustomAlignmentFromRightThenReturnAllocations) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
|
||||||
|
const size_t customAlignment = 8 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = 8 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - ptrSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapBase, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(8 * MemoryConstants::pageSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - ptrSize, ptr);
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
ptrSize = 8 * MemoryConstants::pageSize;
|
||||||
|
ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 2 * ptrSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapBase, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(8 * MemoryConstants::pageSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 2 * ptrSize, ptr);
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - 2 * ptrSize, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenUnalignedBoundWhenAllocatingWithCustomAlignmentFromLeftThenAlignBoundBeforeAllocation) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, 0);
|
||||||
|
|
||||||
|
// Misalign the left bound
|
||||||
|
const size_t misaligningAllocationSize = 2 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = misaligningAllocationSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocate(ptrSize);
|
||||||
|
EXPECT_EQ(heapBase, ptr);
|
||||||
|
EXPECT_EQ(misaligningAllocationSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(heapSize - misaligningAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
|
||||||
|
// Allocate with alignment
|
||||||
|
const size_t customAlignment = 8 * MemoryConstants::pageSize;
|
||||||
|
const size_t alignedAllocationSize = 16 * MemoryConstants::pageSize;
|
||||||
|
ptrSize = alignedAllocationSize;
|
||||||
|
ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(alignedAllocationSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + customAlignment, ptr);
|
||||||
|
EXPECT_EQ(heapBase + customAlignment + alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(heapSize - misaligningAllocationSize - alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
|
||||||
|
// Try to use w hole, we just created by aligning
|
||||||
|
const size_t additionalAllocationSize = customAlignment - misaligningAllocationSize;
|
||||||
|
ptrSize = additionalAllocationSize;
|
||||||
|
ptr = heapAllocator.allocate(ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + misaligningAllocationSize, ptr);
|
||||||
|
EXPECT_EQ(additionalAllocationSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + customAlignment + alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(heapSize - customAlignment - alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenUnalignedBoundWhenAllocatingWithCustomAlignmentFromRightThenAlignBoundBeforeAllocation) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, std::numeric_limits<size_t>::max());
|
||||||
|
|
||||||
|
// Misalign the right bound
|
||||||
|
const size_t misaligningAllocationSize = 2 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = misaligningAllocationSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocate(ptrSize);
|
||||||
|
EXPECT_EQ(misaligningAllocationSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - misaligningAllocationSize, ptr);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - misaligningAllocationSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapSize - misaligningAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksSmall().size());
|
||||||
|
|
||||||
|
// Allocate with alignment
|
||||||
|
const size_t customAlignment = 8 * MemoryConstants::pageSize;
|
||||||
|
const size_t alignedAllocationSize = 16 * MemoryConstants::pageSize;
|
||||||
|
ptrSize = alignedAllocationSize;
|
||||||
|
ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(alignedAllocationSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - customAlignment - alignedAllocationSize, ptr);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - customAlignment - alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapSize - misaligningAllocationSize - alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksSmall().size());
|
||||||
|
|
||||||
|
// Try to use w hole, we just created by aligning
|
||||||
|
const size_t additionalAllocationSize = customAlignment - misaligningAllocationSize;
|
||||||
|
ptrSize = additionalAllocationSize;
|
||||||
|
ptr = heapAllocator.allocate(ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - customAlignment, ptr);
|
||||||
|
EXPECT_EQ(additionalAllocationSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + heapSize - customAlignment - alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapSize - customAlignment - alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksSmall().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenNoSpaceLeftWhenAllocatingWithCustomAlignmentFromLeftThenReturnZero) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, 0);
|
||||||
|
|
||||||
|
const size_t customAlignment = 256 * MemoryConstants::pageSize;
|
||||||
|
const size_t alignedAllocationSize = 256 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = alignedAllocationSize;
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + 2 * alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + 3 * alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + 4 * alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
|
||||||
|
EXPECT_EQ(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + 4 * alignedAllocationSize, heapAllocator.getLeftBound());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenNoSpaceLeftWhenAllocatingWithCustomAlignmentFromRightThenReturnZero) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, std::numeric_limits<size_t>::max());
|
||||||
|
|
||||||
|
const size_t customAlignment = 256 * MemoryConstants::pageSize;
|
||||||
|
const size_t alignedAllocationSize = 256 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = alignedAllocationSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 2 * alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 3 * alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 4 * alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
|
||||||
|
EXPECT_EQ(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 4 * alignedAllocationSize, heapAllocator.getRightBound());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenNoSpaceLeftAfterAligningWhenAllocatingWithCustomAlignmentFromLeftThenReturnZero) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
const size_t alignedAllocationSize = 64 * MemoryConstants::pageSize;
|
||||||
|
|
||||||
|
// First create a state, where we have desired size free, but not aligned
|
||||||
|
size_t ptrSize = 16 * MemoryConstants::pageSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocate(ptrSize));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 16 * MemoryConstants::pageSize, heapAllocator.getRightBound());
|
||||||
|
ptrSize = heapSize - alignedAllocationSize - ptrSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocate(ptrSize));
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Aligned allocation should fail
|
||||||
|
ptrSize = alignedAllocationSize;
|
||||||
|
EXPECT_EQ(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, ptrSize));
|
||||||
|
EXPECT_EQ(alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Unaligned allocation can be done
|
||||||
|
ptrSize = alignedAllocationSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocate(ptrSize));
|
||||||
|
EXPECT_EQ(0ull, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenNoSpaceLeftAfterAligningWhenAllocatingWithCustomAlignmentFromRightThenReturnZero) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
const size_t alignedAllocationSize = 8 * MemoryConstants::pageSize;
|
||||||
|
|
||||||
|
// First create a state, where we have desired size free, but not aligned
|
||||||
|
size_t ptrSize = 4 * MemoryConstants::pageSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocate(ptrSize));
|
||||||
|
EXPECT_EQ(heapBase + heapSize - 4 * MemoryConstants::pageSize, heapAllocator.getRightBound());
|
||||||
|
ptrSize = heapSize - alignedAllocationSize - ptrSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocate(ptrSize));
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Aligned allocation should fail
|
||||||
|
ptrSize = alignedAllocationSize;
|
||||||
|
EXPECT_EQ(0ull, heapAllocator.allocateWithCustomAlignment(ptrSize, ptrSize));
|
||||||
|
EXPECT_EQ(alignedAllocationSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Unaligned allocation can be done
|
||||||
|
ptrSize = alignedAllocationSize;
|
||||||
|
EXPECT_NE(0ull, heapAllocator.allocate(ptrSize));
|
||||||
|
EXPECT_EQ(0ull, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenSizeNotAlignedToCustomAlignmentWhenAllocatingMemoryWithCustomAlignmentThenDoNotAlignToCustomAlignment) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = 49 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + heapSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(49 * MemoryConstants::pageSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase, ptr);
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenSizeNotAlignedToBaseAllocatorAlignmentWhenAllocatingMemoryWithCustomAlignmentThenDoNotAlignToBaseAlignment) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, 0);
|
||||||
|
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize = 1;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + heapSize, heapAllocator.getRightBound());
|
||||||
|
EXPECT_EQ(heapBase + ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(MemoryConstants::pageSize, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase, ptr);
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenAlignedFreedChunkAvailableWhenAllocatingMemoryWithCustomAlignmentFromLeftThenReturnUseFreedChunk) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
|
||||||
|
// First create an aligned freed chunk
|
||||||
|
size_t ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
const uint64_t freeChunkAddress = heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.free(freeChunkAddress, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Allocate with custom alignment using the freed chunk
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(freeChunkAddress, ptr);
|
||||||
|
EXPECT_EQ(heapSize - 2 * ptrSize, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenAlignedFreedChunkSlightlyBiggerThanAllocationeWhenAllocatingMemoryWithCustomAlignmentFromLeftThenUseEntireFreedChunk) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
|
||||||
|
// First create an aligned freed chunk
|
||||||
|
size_t ptrSize = 48 * MemoryConstants::pageSize;
|
||||||
|
const uint64_t freeChunkAddress = heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.free(freeChunkAddress, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Allocate with custom alignment using the freed chunk
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize2 = 32 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize2, customAlignment);
|
||||||
|
EXPECT_EQ(ptrSize, ptrSize2);
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(0u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(freeChunkAddress, ptr);
|
||||||
|
EXPECT_EQ(heapSize - 2 * ptrSize, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenAlignedFreedChunkTwoTimesBiggerThanAllocationeWhenAllocatingMemoryWithCustomAlignmentFromLeftThenUseAPortionOfTheFreedChunk) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, sizeThreshold);
|
||||||
|
|
||||||
|
// First create an aligned freed chunk
|
||||||
|
size_t ptrSize = 64 * MemoryConstants::pageSize;
|
||||||
|
const uint64_t freeChunkAddress = heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.free(freeChunkAddress, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Allocate with custom alignment using the freed chunk
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
size_t ptrSize2 = 32 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize2, customAlignment);
|
||||||
|
EXPECT_EQ(32 * MemoryConstants::pageSize, ptrSize2);
|
||||||
|
EXPECT_EQ(heapBase + 2 * ptrSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(freeChunkAddress + 32 * MemoryConstants::pageSize, ptr);
|
||||||
|
EXPECT_EQ(heapSize - ptrSize - ptrSize2, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HeapAllocatorTest, givenUnalignedFreedChunkAvailableWhenAllocatingMemoryWithCustomAlignmentFromLeftThenDoNotUseFreedChunk) {
|
||||||
|
const uint64_t heapBase = 0x100000llu;
|
||||||
|
const size_t heapSize = 1024u * 4096u;
|
||||||
|
HeapAllocatorUnderTest heapAllocator(heapBase, heapSize, allocationAlignment, 1);
|
||||||
|
|
||||||
|
// First create an unaligned freed chunk
|
||||||
|
size_t ptrSize = MemoryConstants::pageSize;
|
||||||
|
heapAllocator.allocate(ptrSize);
|
||||||
|
ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
const uint64_t freeChunkAddress = heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.allocate(ptrSize);
|
||||||
|
heapAllocator.free(freeChunkAddress, ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + 65 * MemoryConstants::pageSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - ptrSize - MemoryConstants::pageSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Allocate with custom alignment, the freed chunk cannot be used
|
||||||
|
const size_t customAlignment = 32 * MemoryConstants::pageSize;
|
||||||
|
ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
uint64_t ptr = heapAllocator.allocateWithCustomAlignment(ptrSize, customAlignment);
|
||||||
|
EXPECT_EQ(heapBase + 128 * MemoryConstants::pageSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(heapBase + 96 * MemoryConstants::pageSize, ptr);
|
||||||
|
EXPECT_EQ(2u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - 2 * ptrSize - MemoryConstants::pageSize, heapAllocator.getavailableSize());
|
||||||
|
|
||||||
|
// Allocate without custom alignment, the freed chunk can be used
|
||||||
|
ptrSize = 32 * MemoryConstants::pageSize;
|
||||||
|
ptr = heapAllocator.allocate(ptrSize);
|
||||||
|
EXPECT_EQ(heapBase + 128 * MemoryConstants::pageSize, heapAllocator.getLeftBound());
|
||||||
|
EXPECT_EQ(freeChunkAddress, ptr);
|
||||||
|
EXPECT_EQ(1u, heapAllocator.getFreedChunksBig().size());
|
||||||
|
EXPECT_EQ(heapSize - 3 * ptrSize - MemoryConstants::pageSize, heapAllocator.getavailableSize());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue