mem: Be less conservative in clearing load locks in the cache
Avoid being overly conservative in clearing load locks in the cache, and allow writes to the line if they are from the same context. This is in line with ALPHA and ARM.
This commit is contained in:
parent
92f021cbbe
commit
83a5977481
1 changed files with 38 additions and 31 deletions
69
src/mem/cache/blk.hh
vendored
69
src/mem/cache/blk.hh
vendored
|
@ -134,8 +134,9 @@ class CacheBlk
|
||||||
Addr lowAddr; // low address of lock range
|
Addr lowAddr; // low address of lock range
|
||||||
Addr highAddr; // high address of lock range
|
Addr highAddr; // high address of lock range
|
||||||
|
|
||||||
// check for matching execution context
|
// check for matching execution context, and an address that
|
||||||
bool matchesContext(const RequestPtr req) const
|
// is within the lock
|
||||||
|
bool matches(const RequestPtr req) const
|
||||||
{
|
{
|
||||||
Addr req_low = req->getPaddr();
|
Addr req_low = req->getPaddr();
|
||||||
Addr req_high = req_low + req->getSize() -1;
|
Addr req_high = req_low + req->getSize() -1;
|
||||||
|
@ -143,7 +144,8 @@ class CacheBlk
|
||||||
(req_low >= lowAddr) && (req_high <= highAddr);
|
(req_low >= lowAddr) && (req_high <= highAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overlapping(const RequestPtr req) const
|
// check if a request is intersecting and thus invalidating the lock
|
||||||
|
bool intersects(const RequestPtr req) const
|
||||||
{
|
{
|
||||||
Addr req_low = req->getPaddr();
|
Addr req_low = req->getPaddr();
|
||||||
Addr req_high = req_low + req->getSize() - 1;
|
Addr req_high = req_low + req->getSize() - 1;
|
||||||
|
@ -214,7 +216,7 @@ class CacheBlk
|
||||||
{
|
{
|
||||||
status = 0;
|
status = 0;
|
||||||
isTouched = false;
|
isTouched = false;
|
||||||
clearLoadLocks();
|
lockList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,35 +248,35 @@ class CacheBlk
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Track the fact that a local locked was issued to the block. If
|
* Track the fact that a local locked was issued to the
|
||||||
* multiple LLs get issued from the same context we could have
|
* block. Invalidate any previous LL to the same address.
|
||||||
* redundant records on the list, but that's OK, as they'll all
|
|
||||||
* get blown away at the next store.
|
|
||||||
*/
|
*/
|
||||||
void trackLoadLocked(PacketPtr pkt)
|
void trackLoadLocked(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
assert(pkt->isLLSC());
|
assert(pkt->isLLSC());
|
||||||
|
auto l = lockList.begin();
|
||||||
|
while (l != lockList.end()) {
|
||||||
|
if (l->intersects(pkt->req))
|
||||||
|
l = lockList.erase(l);
|
||||||
|
else
|
||||||
|
++l;
|
||||||
|
}
|
||||||
|
|
||||||
lockList.emplace_front(pkt->req);
|
lockList.emplace_front(pkt->req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the list of valid load locks. Should be called whenever
|
* Clear the any load lock that intersect the request, and is from
|
||||||
* block is written to or invalidated.
|
* a different context.
|
||||||
*/
|
*/
|
||||||
void clearLoadLocks(RequestPtr req = nullptr)
|
void clearLoadLocks(RequestPtr req)
|
||||||
{
|
{
|
||||||
if (!req) {
|
auto l = lockList.begin();
|
||||||
// No request, invaldate all locks to this line
|
while (l != lockList.end()) {
|
||||||
lockList.clear();
|
if (l->intersects(req) && l->contextId != req->contextId()) {
|
||||||
} else {
|
l = lockList.erase(l);
|
||||||
// Only invalidate locks that overlap with this request
|
} else {
|
||||||
auto lock_itr = lockList.begin();
|
++l;
|
||||||
while (lock_itr != lockList.end()) {
|
|
||||||
if (lock_itr->overlapping(req)) {
|
|
||||||
lock_itr = lockList.erase(lock_itr);
|
|
||||||
} else {
|
|
||||||
++lock_itr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,22 +346,27 @@ class CacheBlk
|
||||||
// load locked.
|
// load locked.
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
for (const auto& l : lockList) {
|
auto l = lockList.begin();
|
||||||
if (l.matchesContext(req)) {
|
while (l != lockList.end() && !success) {
|
||||||
// it's a store conditional, and as far as the memory
|
if (l->matches(pkt->req)) {
|
||||||
// system can tell, the requesting context's lock is
|
// it's a store conditional, and as far as the
|
||||||
// still valid.
|
// memory system can tell, the requesting
|
||||||
|
// context's lock is still valid.
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
lockList.erase(l);
|
||||||
}
|
}
|
||||||
|
++l;
|
||||||
}
|
}
|
||||||
|
|
||||||
req->setExtraData(success ? 1 : 0);
|
req->setExtraData(success ? 1 : 0);
|
||||||
|
// clear any intersected locks from other contexts (our LL
|
||||||
|
// should already have cleared them)
|
||||||
clearLoadLocks(req);
|
clearLoadLocks(req);
|
||||||
return success;
|
return success;
|
||||||
} else {
|
} else {
|
||||||
// for *all* stores (conditional or otherwise) we have to
|
// a normal write, if there is any lock not from this
|
||||||
// clear the list of load-locks as they're all invalid now.
|
// context we clear the list, thus for a private cache we
|
||||||
|
// never clear locks on normal writes
|
||||||
clearLoadLocks(req);
|
clearLoadLocks(req);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue