ruby: fix deadlock bug in banked array resource checks

The Ruby banked array resource checks (initiated from SLICC) did a check and
allocate at the same time. If a transition needs more than one resource, then
it might check/allocate resource #1, then fail to get resource #2. Another
transition might then try to get the same resources, but in reverse order.
Deadlock.

This patch separates resource checking and resource reservation into two
steps to avoid deadlock.
This commit is contained in:
David Hashe 2015-07-20 09:15:18 -05:00
parent 63a9f10de8
commit 21aa5734a0
5 changed files with 36 additions and 10 deletions

View file

@ -154,7 +154,7 @@ structure (CacheMemory, external = "yes") {
Cycles getTagLatency();
Cycles getDataLatency();
void setMRU(Address);
void recordRequestType(CacheRequestType);
void recordRequestType(CacheRequestType, Address);
bool checkResourceAvailable(CacheResourceType, Address);
int getCacheSize();

View file

@ -58,22 +58,36 @@ BankedArray::tryAccess(int64 idx)
assert(bank < banks);
if (busyBanks[bank].endAccess >= curTick()) {
if (!(busyBanks[bank].startAccess == curTick() &&
busyBanks[bank].idx == idx)) {
return false;
} else {
// We tried to allocate resources twice
// in the same cycle for the same addr
}
return true;
}
void
BankedArray::reserve(int64 idx)
{
if (accessLatency == 0)
return;
unsigned int bank = mapIndexToBank(idx);
assert(bank < banks);
if(busyBanks[bank].endAccess >= curTick()) {
if (busyBanks[bank].startAccess == curTick() &&
busyBanks[bank].idx == idx) {
// this is the same reservation (can happen when
// e.g., reserve the same resource for read and write)
return; // OK
} else {
panic("BankedArray reservation error");
}
}
busyBanks[bank].idx = idx;
busyBanks[bank].startAccess = curTick();
busyBanks[bank].endAccess = curTick() +
(accessLatency-1) * m_ruby_system->clockPeriod();
return true;
}
unsigned int

View file

@ -70,6 +70,8 @@ class BankedArray
// This is so we don't get aliasing on blocks being replaced
bool tryAccess(int64 idx);
void reserve(int64 idx);
Cycles getLatency() const { return accessLatency; }
};

View file

@ -528,22 +528,32 @@ CacheMemory::regStats()
;
}
// assumption: SLICC generated files will only call this function
// once **all** resources are granted
void
CacheMemory::recordRequestType(CacheRequestType requestType)
CacheMemory::recordRequestType(CacheRequestType requestType, Address addr)
{
DPRINTF(RubyStats, "Recorded statistic: %s\n",
CacheRequestType_to_string(requestType));
switch(requestType) {
case CacheRequestType_DataArrayRead:
if (m_resource_stalls)
dataArray.reserve(addressToCacheSet(addr));
numDataArrayReads++;
return;
case CacheRequestType_DataArrayWrite:
if (m_resource_stalls)
dataArray.reserve(addressToCacheSet(addr));
numDataArrayWrites++;
return;
case CacheRequestType_TagArrayRead:
if (m_resource_stalls)
tagArray.reserve(addressToCacheSet(addr));
numTagArrayReads++;
return;
case CacheRequestType_TagArrayWrite:
if (m_resource_stalls)
tagArray.reserve(addressToCacheSet(addr));
numTagArrayWrites++;
return;
default:

View file

@ -117,7 +117,7 @@ class CacheMemory : public SimObject
void regStats();
bool checkResourceAvailable(CacheResourceType res, Address addr);
void recordRequestType(CacheRequestType requestType);
void recordRequestType(CacheRequestType requestType, Address addr);
public:
Stats::Scalar m_demand_hits;