From 78451f668539192adf92599323bdbc5f1623225b Mon Sep 17 00:00:00 2001 From: Kyle Roarty Date: Thu, 17 Feb 2022 15:28:35 -0600 Subject: [PATCH] gpu-compute: Fix register checking and allocation in dyn manager This patch updates the canAllocate function to account both for the number of regions of registers that need to be allocated, and for the fact that the registers aren't one continuous chunk. The patch also consolidates the registers as much as possible when a register chunk is freed. This prevents fragmentation from making it impossible to allocate enough registers Change-Id: Ic95cfe614d247add475f7139d3703991042f8149 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/56909 Reviewed-by: Matt Sinclair Maintainer: Matt Sinclair Tested-by: kokoro Reviewed-by: Matthew Poremba --- src/gpu-compute/dyn_pool_manager.cc | 53 +++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/gpu-compute/dyn_pool_manager.cc b/src/gpu-compute/dyn_pool_manager.cc index 62a39a977d..3db5e7fb18 100644 --- a/src/gpu-compute/dyn_pool_manager.cc +++ b/src/gpu-compute/dyn_pool_manager.cc @@ -93,8 +93,24 @@ bool DynPoolManager::canAllocate(uint32_t numRegions, uint32_t size) { uint32_t actualSize = minAllocatedElements(size); - DPRINTF(GPUVRF,"Can Allocate %d\n",actualSize); - return (_totRegSpaceAvailable >= actualSize); + uint32_t numAvailChunks = 0; + DPRINTF(GPUVRF, "Checking if we can allocate %d regions of size %d " + "registers\n", numRegions, actualSize); + for (auto it : freeSpaceRecord) { + numAvailChunks += (it.second - it.first)/actualSize; + } + + if (numAvailChunks >= numRegions) { + DPRINTF(GPUVRF, "Able to allocate %d regions of size %d; " + "number of available regions: %d\n", + numRegions, actualSize, numAvailChunks); + return true; + } else { + DPRINTF(GPUVRF, "Unable to allocate %d regions of size %d; " + "number of available regions: %d\n", + numRegions, actualSize, numAvailChunks); + return false; + } } uint32_t @@ -105,7 +121,8 @@ DynPoolManager::allocateRegion(const uint32_t size, uint32_t actualSize = minAllocatedElements(size); auto it = freeSpaceRecord.begin(); while (it != freeSpaceRecord.end()) { - if (it->second >= actualSize) { + uint32_t curChunkSize = it->second - it->first; + if (curChunkSize >= actualSize) { // assign the next block starting from here startIdx = it->first; _regionSize = actualSize; @@ -115,14 +132,13 @@ DynPoolManager::allocateRegion(const uint32_t size, // This case sees if this chunk size is exactly equal to // the size of the requested chunk. If yes, then this can't // contribute to future requests and hence, should be removed - if (it->second == actualSize) { + if (curChunkSize == actualSize) { it = freeSpaceRecord.erase(it); // once entire freeSpaceRecord allocated, increment // reservedSpaceRecord count ++reservedSpaceRecord; } else { it->first += actualSize; - it->second -= actualSize; } break; } @@ -144,7 +160,32 @@ DynPoolManager::freeRegion(uint32_t firstIdx, // Current dynamic register allocation does not handle wraparound assert(firstIdx < lastIdx); _totRegSpaceAvailable += lastIdx-firstIdx; - freeSpaceRecord.push_back(std::make_pair(firstIdx,lastIdx-firstIdx)); + + // Consolidate with other regions. Need to check if firstIdx or lastIdx + // already exist + auto firstIt = std::find_if( + freeSpaceRecord.begin(), + freeSpaceRecord.end(), + [&](const std::pair& element){ + return element.second == firstIdx;} ); + + auto lastIt = std::find_if( + freeSpaceRecord.begin(), + freeSpaceRecord.end(), + [&](const std::pair& element){ + return element.first == lastIdx;} ); + + if (firstIt != freeSpaceRecord.end() && lastIt != freeSpaceRecord.end()) { + firstIt->second = lastIt->second; + freeSpaceRecord.erase(lastIt); + } else if (firstIt != freeSpaceRecord.end()) { + firstIt->second = lastIdx; + } else if (lastIt != freeSpaceRecord.end()) { + lastIt->first = firstIdx; + } else { + freeSpaceRecord.push_back(std::make_pair(firstIdx, lastIdx)); + } + // remove corresponding entry from reservedSpaceRecord too --reservedSpaceRecord; }