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:
Andreas Hansson 2016-02-10 04:08:25 -05:00
parent 92f021cbbe
commit 83a5977481

69
src/mem/cache/blk.hh vendored
View file

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