diff options
author | Mitch Hayenga <mitch.hayenga+gem5@gmail.com> | 2013-01-08 08:54:07 -0500 |
---|---|---|
committer | Mitch Hayenga <mitch.hayenga+gem5@gmail.com> | 2013-01-08 08:54:07 -0500 |
commit | c7dbd5e7686bbb065dfe2a74b92f4d9463ddfa80 (patch) | |
tree | c7032e991c9e5d15e1d06f4695be9538e33ba3de | |
parent | dc4a0aa2fa1bc3767785b552159ab0ebe5baa72e (diff) | |
download | gem5-c7dbd5e7686bbb065dfe2a74b92f4d9463ddfa80.tar.xz |
mem: Make LL/SC locks fine grained
The current implementation in gem5 just keeps a list of locks per cacheline.
Due to this, a store to a non-overlapping portion of the cacheline can cause an
LL/SC pair to fail. This patch simply adds an address range to the lock
structure, so that the lock is only invalidated if the store overlaps the lock
range.
-rw-r--r-- | src/mem/cache/blk.hh | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/src/mem/cache/blk.hh b/src/mem/cache/blk.hh index 3557bc489..80216ff89 100644 --- a/src/mem/cache/blk.hh +++ b/src/mem/cache/blk.hh @@ -127,15 +127,30 @@ class CacheBlk class Lock { public: int contextId; // locking context + Addr lowAddr; // low address of lock range + Addr highAddr; // high address of lock range // check for matching execution context bool matchesContext(Request *req) { - return (contextId == req->contextId()); + Addr req_low = req->getPaddr(); + Addr req_high = req_low + req->getSize() -1; + return (contextId == req->contextId()) && + (req_low >= lowAddr) && (req_high <= highAddr); + } + + bool overlapping(Request *req) + { + Addr req_low = req->getPaddr(); + Addr req_high = req_low + req->getSize() - 1; + + return (req_low <= highAddr) && (req_high >= lowAddr); } Lock(Request *req) - : contextId(req->contextId()) + : contextId(req->contextId()), + lowAddr(req->getPaddr()), + highAddr(lowAddr + req->getSize() - 1) { } }; @@ -255,7 +270,23 @@ class CacheBlk * Clear the list of valid load locks. Should be called whenever * block is written to or invalidated. */ - void clearLoadLocks() { lockList.clear(); } + void clearLoadLocks(Request *req = NULL) + { + if (!req) { + // No request, invaldate all locks to this line + lockList.clear(); + } else { + // Only invalidate locks that overlap with this request + std::list<Lock>::iterator lock_itr = lockList.begin(); + while (lock_itr != lockList.end()) { + if (lock_itr->overlapping(req)) { + lock_itr = lockList.erase(lock_itr); + } else { + ++lock_itr; + } + } + } + } /** * Handle interaction of load-locked operations and stores. @@ -283,12 +314,12 @@ class CacheBlk } req->setExtraData(success ? 1 : 0); - clearLoadLocks(); + 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. - clearLoadLocks(); + clearLoadLocks(req); return true; } } |