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:
parent
63a9f10de8
commit
21aa5734a0
|
@ -154,7 +154,7 @@ structure (CacheMemory, external = "yes") {
|
||||||
Cycles getTagLatency();
|
Cycles getTagLatency();
|
||||||
Cycles getDataLatency();
|
Cycles getDataLatency();
|
||||||
void setMRU(Address);
|
void setMRU(Address);
|
||||||
void recordRequestType(CacheRequestType);
|
void recordRequestType(CacheRequestType, Address);
|
||||||
bool checkResourceAvailable(CacheResourceType, Address);
|
bool checkResourceAvailable(CacheResourceType, Address);
|
||||||
|
|
||||||
int getCacheSize();
|
int getCacheSize();
|
||||||
|
|
|
@ -58,13 +58,29 @@ BankedArray::tryAccess(int64 idx)
|
||||||
assert(bank < banks);
|
assert(bank < banks);
|
||||||
|
|
||||||
if (busyBanks[bank].endAccess >= curTick()) {
|
if (busyBanks[bank].endAccess >= curTick()) {
|
||||||
if (!(busyBanks[bank].startAccess == curTick() &&
|
|
||||||
busyBanks[bank].idx == idx)) {
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
// We tried to allocate resources twice
|
panic("BankedArray reservation error");
|
||||||
// in the same cycle for the same addr
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +88,6 @@ BankedArray::tryAccess(int64 idx)
|
||||||
busyBanks[bank].startAccess = curTick();
|
busyBanks[bank].startAccess = curTick();
|
||||||
busyBanks[bank].endAccess = curTick() +
|
busyBanks[bank].endAccess = curTick() +
|
||||||
(accessLatency-1) * m_ruby_system->clockPeriod();
|
(accessLatency-1) * m_ruby_system->clockPeriod();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
|
|
|
@ -70,6 +70,8 @@ class BankedArray
|
||||||
// This is so we don't get aliasing on blocks being replaced
|
// This is so we don't get aliasing on blocks being replaced
|
||||||
bool tryAccess(int64 idx);
|
bool tryAccess(int64 idx);
|
||||||
|
|
||||||
|
void reserve(int64 idx);
|
||||||
|
|
||||||
Cycles getLatency() const { return accessLatency; }
|
Cycles getLatency() const { return accessLatency; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -528,22 +528,32 @@ CacheMemory::regStats()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assumption: SLICC generated files will only call this function
|
||||||
|
// once **all** resources are granted
|
||||||
void
|
void
|
||||||
CacheMemory::recordRequestType(CacheRequestType requestType)
|
CacheMemory::recordRequestType(CacheRequestType requestType, Address addr)
|
||||||
{
|
{
|
||||||
DPRINTF(RubyStats, "Recorded statistic: %s\n",
|
DPRINTF(RubyStats, "Recorded statistic: %s\n",
|
||||||
CacheRequestType_to_string(requestType));
|
CacheRequestType_to_string(requestType));
|
||||||
switch(requestType) {
|
switch(requestType) {
|
||||||
case CacheRequestType_DataArrayRead:
|
case CacheRequestType_DataArrayRead:
|
||||||
|
if (m_resource_stalls)
|
||||||
|
dataArray.reserve(addressToCacheSet(addr));
|
||||||
numDataArrayReads++;
|
numDataArrayReads++;
|
||||||
return;
|
return;
|
||||||
case CacheRequestType_DataArrayWrite:
|
case CacheRequestType_DataArrayWrite:
|
||||||
|
if (m_resource_stalls)
|
||||||
|
dataArray.reserve(addressToCacheSet(addr));
|
||||||
numDataArrayWrites++;
|
numDataArrayWrites++;
|
||||||
return;
|
return;
|
||||||
case CacheRequestType_TagArrayRead:
|
case CacheRequestType_TagArrayRead:
|
||||||
|
if (m_resource_stalls)
|
||||||
|
tagArray.reserve(addressToCacheSet(addr));
|
||||||
numTagArrayReads++;
|
numTagArrayReads++;
|
||||||
return;
|
return;
|
||||||
case CacheRequestType_TagArrayWrite:
|
case CacheRequestType_TagArrayWrite:
|
||||||
|
if (m_resource_stalls)
|
||||||
|
tagArray.reserve(addressToCacheSet(addr));
|
||||||
numTagArrayWrites++;
|
numTagArrayWrites++;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -117,7 +117,7 @@ class CacheMemory : public SimObject
|
||||||
|
|
||||||
void regStats();
|
void regStats();
|
||||||
bool checkResourceAvailable(CacheResourceType res, Address addr);
|
bool checkResourceAvailable(CacheResourceType res, Address addr);
|
||||||
void recordRequestType(CacheRequestType requestType);
|
void recordRequestType(CacheRequestType requestType, Address addr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Stats::Scalar m_demand_hits;
|
Stats::Scalar m_demand_hits;
|
||||||
|
|
Loading…
Reference in a new issue