mem-ruby: Deallocating unused entries in MOESI_CMP dir
authorTiago Mück <tiago.muck@arm.com>
Wed, 15 Apr 2020 23:40:02 +0000 (18:40 -0500)
committerTiago Mück <tiago.muck@arm.com>
Wed, 6 May 2020 14:42:33 +0000 (14:42 +0000)
Invalid entries are never removed from the directory the Directory
controller. This patch fixes this by deallocating the entries
when they become invalid.

Change-Id: I616686a78c5eddb7748192bf94bb691a4f158cbc
Signed-off-by: Tiago Mück <tiago.muck@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27847
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Pouya Fotouhi <pfotouhi@ucdavis.edu>
src/mem/ruby/protocol/MOESI_CMP_directory-dir.sm

index 7faa8e0354d3050372468c13ef2c2e8a0dc5f636..e8d0863351e7c9260854570f91abeced8c128a75 100644 (file)
@@ -138,70 +138,97 @@ machine(MachineType:Directory, "Directory protocol")
 
   Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
     Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
+    assert(is_valid(dir_entry));
+    return dir_entry;
+  }
 
-    if (is_valid(dir_entry)) {
-      return dir_entry;
-    }
-
-    dir_entry :=  static_cast(Entry, "pointer",
+  Entry allocateDirectoryEntry(Addr addr), return_by_pointer="yes" {
+    Entry dir_entry := static_cast(Entry, "pointer",
                               directory.allocate(addr, new Entry));
     return dir_entry;
   }
 
+  void deallocateDirectoryEntry(Addr addr) {
+    // Always going to transition from a valid state to I when deallocating
+    // Owners and shares must be clear
+    assert(getDirectoryEntry(addr).DirectoryState != State:I);
+    assert(getDirectoryEntry(addr).Owner.count() == 0);
+    assert(getDirectoryEntry(addr).Sharers.count() == 0);
+
+    directory.deallocate(addr);
+
+    // disable coherence checker
+    // sequencer.checkCoherence(addr);
+  }
+
   State getState(TBE tbe, Addr addr) {
-    return getDirectoryEntry(addr).DirectoryState;
+    Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
+    if (is_valid(dir_entry)) {
+      return dir_entry.DirectoryState;
+    }
+    else {
+      return State:I;
+    }
   }
 
   void setState(TBE tbe, Addr addr, State state) {
     if (directory.isPresent(addr)) {
 
-      if (state == State:I) {
-        assert(getDirectoryEntry(addr).Owner.count() == 0);
-        assert(getDirectoryEntry(addr).Sharers.count() == 0);
-      }
+      Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
 
-      if (state == State:S) {
-        assert(getDirectoryEntry(addr).Owner.count() == 0);
-      }
+      if (is_valid(dir_entry)) {
 
-      if (state == State:O) {
-        assert(getDirectoryEntry(addr).Owner.count() == 1);
-        assert(getDirectoryEntry(addr).Sharers.isSuperset(getDirectoryEntry(addr).Owner) == false);
-      }
+        assert(state != State:I);
 
-      if (state == State:M) {
-        assert(getDirectoryEntry(addr).Owner.count() == 1);
-        assert(getDirectoryEntry(addr).Sharers.count() == 0);
-      }
+        if (state == State:S) {
+          assert(dir_entry.Owner.count() == 0);
+        }
 
-      if ((state != State:SS) && (state != State:OO)) {
-        assert(getDirectoryEntry(addr).WaitingUnblocks == 0);
-      }
+        if (state == State:O) {
+          assert(dir_entry.Owner.count() == 1);
+          assert(dir_entry.Sharers.isSuperset(dir_entry.Owner) == false);
+        }
 
-      if ( (getDirectoryEntry(addr).DirectoryState != State:I) && (state == State:I) ) {
-        getDirectoryEntry(addr).DirectoryState := state;
-         // disable coherence checker
-        // sequencer.checkCoherence(addr);
-      }
-      else {
-        getDirectoryEntry(addr).DirectoryState := state;
+        if (state == State:M) {
+          assert(dir_entry.Owner.count() == 1);
+          assert(dir_entry.Sharers.count() == 0);
+        }
+
+        if ((state != State:SS) && (state != State:OO)) {
+          assert(dir_entry.WaitingUnblocks == 0);
+        }
+
+        dir_entry.DirectoryState := state;
+
+      } else {
+        assert(state == State:I);
       }
     }
   }
 
   AccessPermission getAccessPermission(Addr addr) {
     if (directory.isPresent(addr)) {
-      DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
-      return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+      Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
+      if (is_valid(dir_entry)) {
+        DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(dir_entry.DirectoryState));
+        return Directory_State_to_permission(dir_entry.DirectoryState);
+      } else {
+        DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(State:I));
+        return Directory_State_to_permission(State:I);
+      }
     }
-
     DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
     return AccessPermission:NotPresent;
   }
 
   void setAccessPermission(Addr addr, State state) {
     if (directory.isPresent(addr)) {
-      getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
+      Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
+      if (is_valid(dir_entry)) {
+        dir_entry.changePermission(Directory_State_to_permission(state));
+      } else {
+        assert(state == State:I);
+      }
     }
   }
 
@@ -319,6 +346,14 @@ machine(MachineType:Directory, "Directory protocol")
 
   // Actions
 
+  action(allocDirEntry, "alloc", desc="Allocate directory entry") {
+    allocateDirectoryEntry(address);
+  }
+
+  action(deallocDirEntry, "dealloc", desc="Deallocate directory entry") {
+    deallocateDirectoryEntry(address);
+  }
+
   action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
     peek(requestQueue_in, RequestMsg) {
       enqueue(responseNetwork_out, ResponseMsg, directory_latency) {
@@ -600,16 +635,19 @@ machine(MachineType:Directory, "Directory protocol")
 
   // TRANSITIONS
   transition(I, GETX, MM) {
+    allocDirEntry;
     qf_queueMemoryFetchRequest;
     i_popIncomingRequestQueue;
   }
 
   transition(I, DMA_READ, XI_M) {
+    allocDirEntry;
     qf_queueMemoryFetchRequest;
     i_popIncomingRequestQueue;
   }
 
   transition(I, DMA_WRITE, XI_U) {
+    allocDirEntry;
     qw_queueMemoryWBFromDMARequest;
     a_sendDMAAck;  // ack count may be zero
     i_popIncomingRequestQueue;
@@ -617,12 +655,14 @@ machine(MachineType:Directory, "Directory protocol")
 
   transition(XI_M, Memory_Data, I) {
     d_sendDataMsg;  // ack count may be zero
+    deallocDirEntry;
     q_popMemQueue;
   }
 
   transition(XI_U, Exclusive_Unblock, I) {
     cc_clearSharers;
     c_clearOwner;
+    deallocDirEntry;
     j_popIncomingUnblockQueue;
   }
 
@@ -647,6 +687,7 @@ machine(MachineType:Directory, "Directory protocol")
   }
 
   transition(I, GETS, IS) {
+    allocDirEntry;
     qf_queueMemoryFetchRequest;
     i_popIncomingRequestQueue;
   }
@@ -812,6 +853,7 @@ machine(MachineType:Directory, "Directory protocol")
     c_clearOwner;
     cc_clearSharers;
     qw_queueMemoryWBFromCacheRequest;
+    deallocDirEntry;
     i_popIncomingRequestQueue;
   }
 
@@ -846,6 +888,7 @@ machine(MachineType:Directory, "Directory protocol")
   transition(MI, Clean_Writeback, I) {
     c_clearOwner;
     cc_clearSharers;
+    deallocDirEntry;
     i_popIncomingRequestQueue;
   }