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 <mattdsinclair@gmail.com>
Maintainer: Matt Sinclair <mattdsinclair@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Matthew Poremba <matthew.poremba@amd.com>
This commit is contained in:
Kyle Roarty
2022-02-17 15:28:35 -06:00
committed by Matt Sinclair
parent 4d2cbefd1e
commit 78451f6685

View File

@@ -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<int, int>& element){
return element.second == firstIdx;} );
auto lastIt = std::find_if(
freeSpaceRecord.begin(),
freeSpaceRecord.end(),
[&](const std::pair<int, int>& 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;
}