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)
|
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.
|
||||||
|
|
101
src/mem/bus.hh
101
src/mem/bus.hh
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue