port: Implement cache for port interfaces and ranges
--HG-- extra : convert_revision : d7cbec7c277fb8f4d8846203caae36ce629602d5
This commit is contained in:
parent
2898d76827
commit
1db9e1fb8f
2 changed files with 139 additions and 6 deletions
|
@ -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.
|
||||
|
|
101
src/mem/bus.hh
101
src/mem/bus.hh
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue