From 1092d59612d9295941c2ec76d8461ae1d2f935d6 Mon Sep 17 00:00:00 2001 From: Unknown <0.tamas.marton@gmail.com> Date: Sat, 7 Mar 2020 11:13:08 +0000 Subject: [PATCH] rewrote CPA, added test for it --- driver/ConsecutivePoolAllocator.c | 175 ++++++++++++++++++------------ driver/command.c | 3 + test/CMakeLists.txt | 1 + test/CPAtest/CMakeLists.txt | 9 ++ test/CPAtest/CPAtest.cpp | 59 ++++++++++ 5 files changed, 177 insertions(+), 70 deletions(-) create mode 100644 test/CPAtest/CMakeLists.txt create mode 100644 test/CPAtest/CPAtest.cpp diff --git a/driver/ConsecutivePoolAllocator.c b/driver/ConsecutivePoolAllocator.c index b67a0d3..32e0a3b 100644 --- a/driver/ConsecutivePoolAllocator.c +++ b/driver/ConsecutivePoolAllocator.c @@ -48,59 +48,46 @@ void* consecutivePoolAllocate(ConsecutivePoolAllocator* pa, uint32_t numBlocks) { assert(pa->buf); - CPAdebugPrint(pa); + //CPAdebugPrint(pa); - if(!pa->nextFreeBlock) + uint32_t* ptr = pa->nextFreeBlock; + + if(!ptr) { return 0; //no free blocks } - void* ret = 0; - for(uint32_t* candidate = pa->nextFreeBlock; candidate; candidate = (uint32_t*)*candidate) + for(; ptr; ptr = *ptr) { uint32_t found = 1; - uint32_t* prevBlock = candidate; - uint32_t* blockAfterCandidate = (uint32_t*)*candidate; - //check if there are enough consecutive free blocks - for(uint32_t c = 0; c < numBlocks - 1; ++c) + char* nextBlock = (char*)ptr + pa->blockSize; + uint32_t* nextFree = *ptr; + for(uint32_t c = 1; c != numBlocks; ++c) { - if(blockAfterCandidate - prevBlock != pa->blockSize) + if(nextBlock == nextFree) { - //signal if not consecutive (ie. diff is greater than blocksize) - found = 0; - break; - } - prevBlock = blockAfterCandidate; - blockAfterCandidate = (uint32_t*)*blockAfterCandidate; - } - - //numblocks consecutive blocks found - if(found) - { - ret = candidate; - if(pa->nextFreeBlock == candidate) - { - //candidate found immediately - pa->nextFreeBlock = blockAfterCandidate; + nextFree = *nextFree; + nextBlock += pa->blockSize; } else { - //somewhere the linked list would point to candidate, we need to correct this - for(uint32_t* nextFreeBlockCandidate = pa->nextFreeBlock; nextFreeBlockCandidate; nextFreeBlockCandidate = (uint32_t*)*nextFreeBlockCandidate) - { - if((uint32_t*)*nextFreeBlockCandidate == candidate) - { - *nextFreeBlockCandidate = (uint32_t)blockAfterCandidate; - break; - } - } + found = 0; + break; } + } + + if(found) + { + //set the next free block to the one that the last block we allocated points to + pa->nextFreeBlock = *(uint32_t*)((char*)ptr + (numBlocks - 1) * pa->blockSize); break; } } - //return a pointer pointing past the linked list ptr - return ret > 0 ? (char*)ret + 4 : ret; + //TODO debug stuff, not for release + memset(ptr, 0, numBlocks * pa->blockSize); + + return ptr; } //free numBlocks consecutive memory @@ -108,66 +95,114 @@ void consecutivePoolFree(ConsecutivePoolAllocator* pa, void* p, uint32_t numBloc { assert(pa->buf); assert(p); + assert(numBlocks); - p = (char*)p - 4; + //TODO debug stuff, not for release + memset(p, 0, numBlocks * pa->blockSize); - if((void*)pa->nextFreeBlock > p) + //if linked list of free entries is empty + if(!pa->nextFreeBlock) { + //then restart linked list + pa->nextFreeBlock = p; + char* listPtr = pa->nextFreeBlock; for(uint32_t c = 0; c < numBlocks - 1; ++c) { - //set each allocated block to form a linked list - *(uint32_t*)((char*)p + c * pa->blockSize) = (uint32_t)((char*)p + (c + 1) * pa->blockSize); + *(uint32_t*)listPtr = listPtr + pa->blockSize; + listPtr += pa->blockSize; } - //set last block to point to the next free - *(uint32_t*)((char*)p + (numBlocks - 1) * pa->blockSize) = (uint32_t)pa->nextFreeBlock; - //set next free to the newly freed block - pa->nextFreeBlock = p; - return; - } - //somewhere the linked list may point after the free block (or null), we need to correct this - for(uint32_t* nextFreeBlockCandidate = pa->nextFreeBlock; nextFreeBlockCandidate; nextFreeBlockCandidate = (uint32_t*)*nextFreeBlockCandidate) + //end list + *(uint32_t*)listPtr = 0; + } + else { - if((void*)*nextFreeBlockCandidate > p || !*nextFreeBlockCandidate) + //if list is not empty, try to form consecutive parts + + //search free list to see if the freed element fits anywhere + uint32_t found = 0; + for(uint32_t* listPtr = pa->nextFreeBlock; listPtr; listPtr = *listPtr) { + //if the freed block fits in the list somewhere + if(((char*)listPtr + pa->blockSize) == p) + { + //add it into the list + uint32_t* tmp = *listPtr; + *listPtr = p; + + //reconstruct linked list within the freed element + char* ptr = *listPtr; + for(uint32_t c = 0; c < numBlocks - 1; ++c) + { + *(uint32_t*)ptr = ptr + pa->blockSize; + ptr += pa->blockSize; + } + + //set the last element to point to the one after + *(uint32_t*)ptr = tmp; + + found = 1; + } + } + + if(!found) + { + //if it doesn't fit anywhere, just simply add it to the linked list + uint32_t* tmp = pa->nextFreeBlock; + + pa->nextFreeBlock = p; + char* listPtr = pa->nextFreeBlock; for(uint32_t c = 0; c < numBlocks - 1; ++c) { - //set each allocated block to form a linked list - *(uint32_t*)((char*)p + c * pa->blockSize) = (uint32_t)((char*)p + (c + 1) * pa->blockSize); + *(uint32_t*)listPtr = listPtr + pa->blockSize; + listPtr += pa->blockSize; } - //set last block to point to the next free - *(uint32_t*)((char*)p + (numBlocks - 1) * pa->blockSize) = *nextFreeBlockCandidate; - *nextFreeBlockCandidate = (uint32_t)p; - break; + //set the last element to point to the one after + *(uint32_t*)listPtr = tmp; } } } -//if there's a block free after the current block, it just allocates one more block -//else it frees current block and allocates a new one void* consecutivePoolReAllocate(ConsecutivePoolAllocator* pa, void* currentMem, uint32_t currNumBlocks) { fprintf(stderr, "CPA realloc\n"); - currentMem = (char*)currentMem - 4; + uint32_t* nextCandidate = (char*)currentMem + pa->blockSize * currNumBlocks; - if(pa->nextFreeBlock == (uint32_t*)((char*)currentMem + currNumBlocks * pa->blockSize)) + uint32_t* prevPtr = 0; + for(uint32_t* listPtr = pa->nextFreeBlock; listPtr; listPtr = *listPtr) { - //we have one more block after current one, so just expand current - pa->nextFreeBlock = (uint32_t*)*pa->nextFreeBlock; - return currentMem; + if(listPtr == nextCandidate) + { + //if the free list contains an element that points right after our currentMem + //we can just use that one + *prevPtr = *listPtr; + + //TODO debug stuff, not for release + memset(nextCandidate, 0, pa->blockSize); + + return currentMem; + } + + prevPtr = listPtr; } - else + { - void* ret = consecutivePoolAllocate(pa, currNumBlocks + 1); - char* newContents = ret; - char* oldContents = currentMem; - newContents += 4; - oldContents += 4; - memcpy(newContents, oldContents, currNumBlocks * pa->blockSize - 4); + //try to allocate one more block + void* newMem = consecutivePoolAllocate(pa, currNumBlocks + 1); + + if(!newMem) + { + return 0; + } + + //copy over old content + memcpy(newMem, currentMem, currNumBlocks * pa->blockSize); + //free current element consecutivePoolFree(pa, currentMem, currNumBlocks); - return newContents; + + return newMem; } } diff --git a/driver/command.c b/driver/command.c index 9eecd61..f2f3b7d 100644 --- a/driver/command.c +++ b/driver/command.c @@ -52,6 +52,9 @@ VKAPI_ATTR VkResult VKAPI_CALL rpi_vkCreateCommandPool( int numCommandBufs = 128; int consecutiveBlockSize = ARM_PAGE_SIZE>>2; int consecutiveBlockNumber = 64; + //int numCommandBufs = 30; + //int consecutiveBlockSize = getCPABlockSize(256); + //int consecutiveBlockNumber = 30; int consecutivePoolSize = consecutiveBlockNumber * consecutiveBlockSize; static int counter = 0; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 709a955..36a2f06 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,3 +12,4 @@ add_subdirectory(HDR) add_subdirectory(ETC) add_subdirectory(query) add_subdirectory(mipmapping) +add_subdirectory(CPAtest) \ No newline at end of file diff --git a/test/CPAtest/CMakeLists.txt b/test/CPAtest/CMakeLists.txt new file mode 100644 index 0000000..cb40470 --- /dev/null +++ b/test/CPAtest/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB testSrc + "*.h" + "*.cpp" +) + +add_executable(CPAtest ${testSrc}) +target_compile_options(CPAtest PRIVATE -Wall -std=c++11) + +target_link_libraries(CPAtest rpi-vk-driver) diff --git a/test/CPAtest/CPAtest.cpp b/test/CPAtest/CPAtest.cpp new file mode 100644 index 0000000..edd5731 --- /dev/null +++ b/test/CPAtest/CPAtest.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "driver/CustomAssert.h" +#include "driver/ConsecutivePoolAllocator.h" + +#include + +#include "driver/vkExt.h" + +void simpleTest() +{ + uint32_t blocksize = 16; + uint32_t numblocks = 8; + uint32_t size = numblocks * blocksize; + + ConsecutivePoolAllocator cpa = createConsecutivePoolAllocator((char*)malloc(size), blocksize, size); + CPAdebugPrint(&cpa); + + void* mem1 = consecutivePoolAllocate(&cpa, 1); + CPAdebugPrint(&cpa); + + void* mem2 = consecutivePoolAllocate(&cpa, 2); + CPAdebugPrint(&cpa); + + void* mem3 = consecutivePoolAllocate(&cpa, 3); + CPAdebugPrint(&cpa); + + void* mem11 = consecutivePoolAllocate(&cpa, 1); + CPAdebugPrint(&cpa); + + void* mem111 = consecutivePoolAllocate(&cpa, 1); + CPAdebugPrint(&cpa); + + void* mem0 = consecutivePoolAllocate(&cpa, 1); + fprintf(stderr, "\n%p\n", mem0); + + consecutivePoolFree(&cpa, mem11, 1); + CPAdebugPrint(&cpa); + + consecutivePoolFree(&cpa, mem111, 1); + CPAdebugPrint(&cpa); + + consecutivePoolFree(&cpa, mem2, 2); + CPAdebugPrint(&cpa); + + consecutivePoolFree(&cpa, mem3, 3); + CPAdebugPrint(&cpa); + + consecutivePoolFree(&cpa, mem1, 1); + CPAdebugPrint(&cpa); +} + +int main() { + simpleTest(); + + return 0; +}