port: Implement cache for port interfaces and ranges

--HG--
extra : convert_revision : d7cbec7c277fb8f4d8846203caae36ce629602d5
This commit is contained in:
Vincentius Robby 2007-08-04 16:05:55 -04:00
parent 2898d76827
commit 1db9e1fb8f
2 changed files with 139 additions and 6 deletions

View file

@ -84,6 +84,7 @@ Bus::deletePortRefs(Port *p)
if (funcPort == bp) if (funcPort == bp)
return; return;
interfaces.erase(bp->getId()); interfaces.erase(bp->getId());
clearBusCache();
delete bp; delete bp;
} }
@ -176,7 +177,16 @@ Bus::recvTiming(PacketPtr pkt)
DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
src, pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 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 // If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list. // one, put this device on the retry list.
@ -220,6 +230,15 @@ Bus::recvTiming(PacketPtr pkt)
assert(dest >= 0 && dest < maxId); assert(dest >= 0 && dest < maxId);
assert(dest != src); // catch infinite loops assert(dest != src); // catch infinite loops
dest_port_id = dest; 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) ? dest_port = (dest_port_id == defaultId) ?
defaultPort : interfaces[dest_port_id]; 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. */ /* An interval tree would be a better way to do this. --ali. */
int dest_id = -1; int dest_id = -1;
PortIter i = portMap.find(RangeSize(addr,1)); dest_id = checkPortCache(addr);
if (i != portMap.end()) if (dest_id == -1) {
dest_id = i->second; 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 // Check if this matches the default range
if (dest_id == -1) { if (dest_id == -1) {
@ -340,8 +363,16 @@ Bus::recvAtomic(PacketPtr pkt)
int orig_src = pkt->getSrc(); int orig_src = pkt->getSrc();
int target_port_id = findPort(pkt->getAddr()); int target_port_id = findPort(pkt->getAddr());
Port *target_port = (target_port_id == defaultId) ? BusPort *target_port;
defaultPort : interfaces[target_port_id]; 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(); SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 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); DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
clearPortCache();
if (id == defaultId) { if (id == defaultId) {
defaultRange.clear(); defaultRange.clear();
// Only try to update these ranges if the user set a default responder. // Only try to update these ranges if the user set a default responder.

View file

@ -180,6 +180,58 @@ class Bus : public MemObject
*/ */
int findPort(Addr addr); 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. /** Process address range request.
* @param resp addresses that we can respond to * @param resp addresses that we can respond to
* @param snoop addresses that we would like to snoop * @param snoop addresses that we would like to snoop
@ -246,6 +298,53 @@ class Bus : public MemObject
int cachedBlockSize; int cachedBlockSize;
bool cachedBlockSizeValid; 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: public:
/** A function used to return the port associated with this bus object. */ /** 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"); fatal("Bus width must be positive\n");
if (clock <= 0) if (clock <= 0)
fatal("Bus clock period must be positive\n"); fatal("Bus clock period must be positive\n");
clearBusCache();
clearPortCache();
} }
}; };