port: Implement cache for port interfaces and ranges
authorVincentius Robby <acolyte@umich.edu>
Sat, 4 Aug 2007 20:05:55 +0000 (16:05 -0400)
committerVincentius Robby <acolyte@umich.edu>
Sat, 4 Aug 2007 20:05:55 +0000 (16:05 -0400)
--HG--
extra : convert_revision : d7cbec7c277fb8f4d8846203caae36ce629602d5

src/mem/bus.cc
src/mem/bus.hh

index cb359734b515d3422ba6f9038649d9be3bc3440d..9fa61a76d2a1c87ce4ae37c36357fbecdad03ea8 100644 (file)
@@ -84,6 +84,7 @@ Bus::deletePortRefs(Port *p)
     if (funcPort == bp)
         return;
     interfaces.erase(bp->getId());
+    clearBusCache();
     delete bp;
 }
 
@@ -176,7 +177,16 @@ Bus::recvTiming(PacketPtr pkt)
     DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
             src, pkt->getDest(), pkt->getAddr(), pkt->cmdString());
 
-    BusPort *src_port = (src == defaultId) ? defaultPort : interfaces[src];
+    BusPort *src_port;
+    if (src == defaultId)
+        src_port = defaultPort;
+    else {
+        src_port = checkBusCache(src);
+        if (src_port == NULL) {
+            src_port = interfaces[src];
+            updateBusCache(src, src_port);
+        }
+    }
 
     // If the bus is busy, or other devices are in line ahead of the current
     // one, put this device on the retry list.
@@ -220,6 +230,15 @@ Bus::recvTiming(PacketPtr pkt)
         assert(dest >= 0 && dest < maxId);
         assert(dest != src); // catch infinite loops
         dest_port_id = dest;
+        if (dest_port_id == defaultId)
+            dest_port = defaultPort;
+        else {
+            dest_port = checkBusCache(dest);
+            if (dest_port == NULL) {
+                dest_port = interfaces[dest_port_id];
+            // updateBusCache(dest_port_id, dest_port);
+            }
+        }
         dest_port = (dest_port_id == defaultId) ?
             defaultPort : interfaces[dest_port_id];
     }
@@ -291,9 +310,13 @@ Bus::findPort(Addr addr)
     /* An interval tree would be a better way to do this. --ali. */
     int dest_id = -1;
 
-    PortIter i = portMap.find(RangeSize(addr,1));
-    if (i != portMap.end())
-        dest_id = i->second;
+    dest_id = checkPortCache(addr);
+    if (dest_id == -1) {
+        PortIter i = portMap.find(RangeSize(addr,1));
+        if (i != portMap.end())
+          dest_id = i->second;
+        updatePortCache(dest_id, i->first.start, i->first.end);
+    }
 
     // Check if this matches the default range
     if (dest_id == -1) {
@@ -340,8 +363,16 @@ Bus::recvAtomic(PacketPtr pkt)
     int orig_src = pkt->getSrc();
 
     int target_port_id = findPort(pkt->getAddr());
-    Port *target_port = (target_port_id == defaultId) ?
-        defaultPort : interfaces[target_port_id];
+    BusPort *target_port;
+    if (target_port_id == defaultId)
+        target_port = defaultPort;
+    else {
+      target_port = checkBusCache(target_port_id);
+      if (target_port == NULL) {
+          target_port = interfaces[target_port_id];
+          updateBusCache(target_port_id, target_port);
+      }
+    }
 
     SnoopIter s_end = snoopPorts.end();
     for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
@@ -438,6 +469,7 @@ Bus::recvStatusChange(Port::Status status, int id)
 
     DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
 
+    clearPortCache();
     if (id == defaultId) {
         defaultRange.clear();
         // Only try to update these ranges if the user set a default responder.
index 06ccd4ac0c844220f8a8f7101515582be604e6f3..f5cad058661da09e29c9a0afe81f21ca699bcbad 100644 (file)
@@ -180,6 +180,58 @@ class Bus : public MemObject
      */
     int findPort(Addr addr);
 
+    // Cache for the findPort function storing recently used ports from portMap
+    struct PortCache {
+        bool valid;
+        int  id;
+        Addr start;
+        Addr end;
+    };
+
+    PortCache portCache[3];
+
+    // Checks the cache and returns the id of the port that has the requested
+    // address within its range
+    inline int checkPortCache(Addr addr) {
+        if (portCache[0].valid && addr >= portCache[0].start &&
+            addr < portCache[0].end) {
+            return portCache[0].id;
+        } else if (portCache[1].valid && addr >= portCache[1].start &&
+                   addr < portCache[1].end) {
+            return portCache[1].id;
+        } else if (portCache[2].valid && addr >= portCache[2].start &&
+                   addr < portCache[2].end) {
+            return portCache[2].id;
+        }
+
+        return -1;
+    }
+
+    // Clears the earliest entry of the cache and inserts a new port entry
+    inline void updatePortCache(short id, Addr start, Addr end) {
+        portCache[2].valid = portCache[1].valid;
+        portCache[2].id    = portCache[1].id;
+        portCache[2].start = portCache[1].start;
+        portCache[2].end   = portCache[1].end;
+
+        portCache[1].valid = portCache[0].valid;
+        portCache[1].id    = portCache[0].id;
+        portCache[1].start = portCache[0].start;
+        portCache[1].end   = portCache[0].end;
+
+        portCache[0].valid = true;
+        portCache[0].id    = id;
+        portCache[0].start = start;
+        portCache[0].end   = end;
+    }
+
+    // Clears the cache. Needs to be called in constructor.
+    inline void clearPortCache() {
+        portCache[2].valid = false;
+        portCache[1].valid = false;
+        portCache[0].valid = false;
+    }
+
     /** Process address range request.
      * @param resp addresses that we can respond to
      * @param snoop addresses that we would like to snoop
@@ -246,6 +298,53 @@ class Bus : public MemObject
     int cachedBlockSize;
     bool cachedBlockSizeValid;
 
+   // Cache for the peer port interfaces
+    struct BusCache {
+        bool  valid;
+        short id;
+        BusPort  *port;
+    };
+
+    BusCache busCache[3];
+
+    // Checks the peer port interfaces cache for the port id and returns
+    // a pointer to the matching port
+    inline BusPort* checkBusCache(short id) {
+        if (busCache[0].valid && id == busCache[0].id) {
+            return busCache[0].port;
+        } else if (busCache[1].valid && id == busCache[1].id) {
+            return busCache[1].port;
+        } else if (busCache[2].valid && id == busCache[2].id) {
+            return busCache[2].port;
+        }
+
+        return NULL;
+    }
+
+    // Replaces the earliest entry in the cache with a new entry
+    inline void updateBusCache(short id, BusPort *port) {
+        busCache[2].valid = busCache[1].valid;
+        busCache[2].id    = busCache[1].id;
+        busCache[2].port  = busCache[1].port;
+
+        busCache[1].valid = busCache[0].valid;
+        busCache[1].id    = busCache[0].id;
+        busCache[1].port  = busCache[0].port;
+
+        busCache[0].valid = true;
+        busCache[0].id    = id;
+        busCache[0].port  = port;
+    }
+
+    // Invalidates the cache. Needs to be called in constructor.
+    inline void clearBusCache() {
+        // memset(busCache, 0, 3 * sizeof(BusCache));
+        busCache[2].valid = false;
+        busCache[1].valid = false;
+        busCache[0].valid = false;
+    }
+
+
   public:
 
     /** A function used to return the port associated with this bus object. */
@@ -270,6 +369,8 @@ class Bus : public MemObject
             fatal("Bus width must be positive\n");
         if (clock <= 0)
             fatal("Bus clock period must be positive\n");
+        clearBusCache();
+        clearPortCache();
     }
 
 };