mem: don't inhibit WriteInv's or defer snoops on their MSHRs
authorCurtis Dunham <Curtis.Dunham@arm.com>
Tue, 21 Oct 2014 22:04:41 +0000 (17:04 -0500)
committerCurtis Dunham <Curtis.Dunham@arm.com>
Tue, 21 Oct 2014 22:04:41 +0000 (17:04 -0500)
WriteInvalidate semantics depend on the unconditional writeback
or they won't complete.  Also, there's no point in deferring snoops
on their MSHRs, as they don't get new data at the end of their life
cycle the way other transactions do.

Add comment in the cache about a minor inefficiency re: WriteInvalidate.

src/mem/cache/cache_impl.hh
src/mem/cache/mshr.cc
src/mem/cache/mshr.hh

index 4b51a63591d0625b2036cc348e932ceec8545975..66abf6eff90e05586c8bef5f89eb7b63851deb90 100644 (file)
@@ -345,7 +345,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk,
                 blk->status |= BlkSecure;
             }
         }
-        std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
         if (pkt->cmd == MemCmd::Writeback) {
             blk->status |= BlkDirty;
             if (pkt->isSupplyExclusive()) {
@@ -354,11 +353,11 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk,
             // nothing else to do; writeback doesn't expect response
             assert(!pkt->needsResponse());
         } else if (pkt->cmd == MemCmd::WriteInvalidateReq) {
-            assert(blk->isReadable()); // implicitly checks for Valid bit also
-            blk->status |= (BlkDirty | BlkCanGoExclusive);
+            blk->status |= (BlkReadable | BlkDirty | BlkCanGoExclusive);
             blk->status &= ~BlkWritable;
             ++fastWrites;
         }
+        std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
         DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print());
         incHitCount(pkt);
         return true;
@@ -1517,6 +1516,11 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
         // there are cases (such as failed store conditionals or
         // compare-and-swaps) where we'll demand an exclusive copy but
         // end up not writing it.
+        // Caveat: if a Read takes a value from a WriteInvalidate MSHR,
+        // it will get marked Dirty even though it is Clean (once the
+        // WriteInvalidate completes). This is due to insufficient meta-
+        // data and overly presumptive interpretation of the inhibit flag.
+        // The result is an unnecessary extra writeback.
         if (pkt->memInhibitAsserted())
             blk->status |= BlkDirty;
     }
index fcf9fc425ec19a3a9971f747f6c195e083c6cc9d..bc46ed267e562fc8893a95bcdad65e4b418aa484 100644 (file)
 using namespace std;
 
 MSHR::MSHR() : readyTime(0), _isUncacheable(false), downstreamPending(false),
-               pendingDirty(false), postInvalidate(false), postDowngrade(false),
-               _isObsolete(false), queue(NULL), order(0), addr(0), size(0),
-               isSecure(false), inService(false), isForward(false),
-               threadNum(InvalidThreadID), data(NULL)
+               pendingDirty(false), pendingClean(false),
+               postInvalidate(false), postDowngrade(false),
+               _isObsolete(false), queue(NULL), order(0), addr(0),
+               size(0), isSecure(false), inService(false),
+               isForward(false), threadNum(InvalidThreadID), data(NULL)
 {
 }
 
@@ -213,6 +214,7 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target, Tick whenReady,
     isForward = false;
     _isUncacheable = target->req->isUncacheable();
     inService = false;
+    pendingClean = (target->cmd == MemCmd::WriteInvalidateReq);
     downstreamPending = false;
     _isObsolete = false;
     threadNum = 0;
@@ -251,7 +253,8 @@ MSHR::markInService(PacketPtr pkt)
 
     assert(pkt != NULL);
     inService = true;
-    pendingDirty = (targets.needsExclusive ||
+    pendingDirty = ((targets.needsExclusive &&
+                     (pkt->cmd != MemCmd::WriteInvalidateReq)) ||
                     (!pkt->sharedAsserted() && pkt->memInhibitAsserted()));
     postInvalidate = postDowngrade = false;
 
@@ -367,7 +370,12 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
         targets.add(cp_pkt, curTick(), _order, Target::FromSnoop,
                      downstreamPending && targets.needsExclusive);
 
-        if (isPendingDirty()) {
+        // WriteInvalidates must writeback and should not be inhibited on
+        // account of its snoops discovering MSHRs wanting exclusive access
+        // to what it wrote.  We don't want to push this check higher,
+        // however, because we want to be sure to add an invalidating
+        // Target::FromSnoop, above.
+        if (isPendingDirty() && (pkt->cmd != MemCmd::WriteInvalidateReq)) {
             pkt->assertMemInhibit();
             pkt->setSupplyExclusive();
         }
@@ -375,6 +383,13 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
         if (pkt->needsExclusive()) {
             // This transaction will take away our pending copy
             postInvalidate = true;
+
+            // Do not defer (i.e. return true) the snoop if the block is
+            // going to be clean once the MSHR completes, as the data is
+            // ready now.
+            if (isPendingClean()) {
+                return false;
+            }
         }
     }
 
index 9ea9cfb2c031a0b8b0aa8e3352b5aa765eeb19a5..e5a15b61d8e04bc122e8eca8467615ff0662e32a 100644 (file)
@@ -83,6 +83,9 @@ class MSHR : public Packet::SenderState, public Printable
     /** Will we have a dirty copy after this request? */
     bool pendingDirty;
 
+    /** Will we have a clean copy after this request?  (i.e. is writeback) */
+    bool pendingClean;
+
     /** Did we snoop an invalidate while waiting for data? */
     bool postInvalidate;
 
@@ -179,6 +182,10 @@ class MSHR : public Packet::SenderState, public Printable
         assert(inService); return pendingDirty;
     }
 
+    bool isPendingClean() const {
+        return pendingClean;
+    }
+
     bool hasPostInvalidate() const {
         assert(inService); return postInvalidate;
     }