Make L2+ caches allocate new block for writeback misses
instead of forwarding down the line. --HG-- extra : convert_revision : b0d6e7862c92ea7a2d21f817d30398735e7bb8ba
This commit is contained in:
parent
69ce7f953b
commit
4597a71cef
2 changed files with 95 additions and 58 deletions
8
src/mem/cache/cache.hh
vendored
8
src/mem/cache/cache.hh
vendored
|
@ -169,6 +169,14 @@ class Cache : public BaseCache
|
||||||
*/
|
*/
|
||||||
void cmpAndSwap(BlkType *blk, PacketPtr pkt);
|
void cmpAndSwap(BlkType *blk, PacketPtr pkt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a block frame for new block at address addr, assuming that
|
||||||
|
* the block is not currently in the cache. Append writebacks if
|
||||||
|
* any to provided packet list. Return free block frame. May
|
||||||
|
* return NULL if there are no replaceable blocks at the moment.
|
||||||
|
*/
|
||||||
|
BlkType *allocateBlock(Addr addr, PacketList &writebacks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates a cache block and handles all outstanding requests for the
|
* Populates a cache block and handles all outstanding requests for the
|
||||||
* satisfied fill request. This version takes two memory requests. One
|
* satisfied fill request. This version takes two memory requests. One
|
||||||
|
|
145
src/mem/cache/cache_impl.hh
vendored
145
src/mem/cache/cache_impl.hh
vendored
|
@ -267,7 +267,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool satisfied = false; // assume the worst
|
|
||||||
blk = tags->findBlock(pkt->getAddr(), lat);
|
blk = tags->findBlock(pkt->getAddr(), lat);
|
||||||
|
|
||||||
if (prefetchAccess) {
|
if (prefetchAccess) {
|
||||||
|
@ -279,7 +278,7 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
|
||||||
(blk) ? "hit" : "miss");
|
(blk) ? "hit" : "miss");
|
||||||
|
|
||||||
if (blk != NULL) {
|
if (blk != NULL) {
|
||||||
// HIT
|
|
||||||
if (blk->isPrefetch()) {
|
if (blk->isPrefetch()) {
|
||||||
//Signal that this was a hit under prefetch (no need for
|
//Signal that this was a hit under prefetch (no need for
|
||||||
//use prefetch (only can get here if true)
|
//use prefetch (only can get here if true)
|
||||||
|
@ -296,37 +295,54 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
|
||||||
if (pkt->needsExclusive() ? blk->isWritable() : blk->isValid()) {
|
if (pkt->needsExclusive() ? blk->isWritable() : blk->isValid()) {
|
||||||
// OK to satisfy access
|
// OK to satisfy access
|
||||||
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
||||||
satisfied = true;
|
|
||||||
satisfyCpuSideRequest(pkt, blk);
|
satisfyCpuSideRequest(pkt, blk);
|
||||||
} else if (pkt->cmd == MemCmd::Writeback) {
|
return true;
|
||||||
// special case: writeback to read-only block (e.g., from
|
|
||||||
// L1 into L2). since we're really just passing ownership
|
|
||||||
// from one cache to another, we can update this cache to
|
|
||||||
// be the owner without making the block writeable
|
|
||||||
assert(!blk->isWritable() /* && !blk->isDirty() */);
|
|
||||||
assert(blkSize == pkt->getSize());
|
|
||||||
std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
|
|
||||||
blk->status |= BlkDirty;
|
|
||||||
satisfied = true;
|
|
||||||
// nothing else to do; writeback doesn't expect response
|
|
||||||
assert(!pkt->needsResponse());
|
|
||||||
} else {
|
|
||||||
// permission violation... nothing to do here, leave unsatisfied
|
|
||||||
// for statistics purposes this counts like a complete miss
|
|
||||||
incMissCount(pkt);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// complete miss (no matching block)
|
|
||||||
incMissCount(pkt);
|
|
||||||
|
|
||||||
if (pkt->isLocked() && pkt->isWrite()) {
|
|
||||||
// miss on store conditional... just give up now
|
|
||||||
pkt->req->setExtraData(0);
|
|
||||||
satisfied = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return satisfied;
|
// Can't satisfy access normally... either no block (blk == NULL)
|
||||||
|
// or have block but need exclusive & only have shared.
|
||||||
|
|
||||||
|
// Writeback handling is special case. We can write the block
|
||||||
|
// into the cache without having a writeable copy (or any copy at
|
||||||
|
// all).
|
||||||
|
if (pkt->cmd == MemCmd::Writeback) {
|
||||||
|
PacketList writebacks;
|
||||||
|
assert(blkSize == pkt->getSize());
|
||||||
|
if (blk == NULL) {
|
||||||
|
// need to do a replacement
|
||||||
|
blk = allocateBlock(pkt->getAddr(), writebacks);
|
||||||
|
if (blk == NULL) {
|
||||||
|
// no replaceable block available, give up.
|
||||||
|
// writeback will be forwarded to next level.
|
||||||
|
incMissCount(pkt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
blk->status = BlkValid;
|
||||||
|
}
|
||||||
|
std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
|
||||||
|
blk->status |= BlkDirty;
|
||||||
|
// copy writebacks from replacement to write buffer
|
||||||
|
while (!writebacks.empty()) {
|
||||||
|
PacketPtr wbPkt = writebacks.front();
|
||||||
|
allocateWriteBuffer(wbPkt, curTick + hitLatency, true);
|
||||||
|
writebacks.pop_front();
|
||||||
|
}
|
||||||
|
// nothing else to do; writeback doesn't expect response
|
||||||
|
assert(!pkt->needsResponse());
|
||||||
|
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
incMissCount(pkt);
|
||||||
|
|
||||||
|
if (blk == NULL && pkt->isLocked() && pkt->isWrite()) {
|
||||||
|
// complete miss on store conditional... just give up now
|
||||||
|
pkt->req->setExtraData(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -850,6 +866,40 @@ Cache<TagStore>::writebackBlk(BlkType *blk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class TagStore>
|
||||||
|
typename Cache<TagStore>::BlkType*
|
||||||
|
Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks)
|
||||||
|
{
|
||||||
|
BlkType *blk = tags->findReplacement(addr, writebacks);
|
||||||
|
|
||||||
|
if (blk->isValid()) {
|
||||||
|
Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set);
|
||||||
|
MSHR *repl_mshr = mshrQueue.findMatch(repl_addr);
|
||||||
|
if (repl_mshr) {
|
||||||
|
// must be an outstanding upgrade request on block
|
||||||
|
// we're about to replace...
|
||||||
|
assert(!blk->isWritable());
|
||||||
|
assert(repl_mshr->needsExclusive());
|
||||||
|
// too hard to replace block with transient state
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
|
||||||
|
repl_addr, addr,
|
||||||
|
blk->isDirty() ? "writeback" : "clean");
|
||||||
|
|
||||||
|
if (blk->isDirty()) {
|
||||||
|
// Save writeback packet for handling by caller
|
||||||
|
writebacks.push_back(writebackBlk(blk));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set tag for new block. Caller is responsible for setting status.
|
||||||
|
blk->tag = tags->extractTag(addr);
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Note that the reason we return a list of writebacks rather than
|
// Note that the reason we return a list of writebacks rather than
|
||||||
// inserting them directly in the write buffer is that this function
|
// inserting them directly in the write buffer is that this function
|
||||||
// is called by both atomic and timing-mode accesses, and in atomic
|
// is called by both atomic and timing-mode accesses, and in atomic
|
||||||
|
@ -868,37 +918,16 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
|
||||||
if (blk == NULL) {
|
if (blk == NULL) {
|
||||||
// better have read new data...
|
// better have read new data...
|
||||||
assert(pkt->hasData());
|
assert(pkt->hasData());
|
||||||
|
|
||||||
// need to do a replacement
|
// need to do a replacement
|
||||||
blk = tags->findReplacement(addr, writebacks);
|
blk = allocateBlock(addr, writebacks);
|
||||||
if (blk->isValid()) {
|
if (blk == NULL) {
|
||||||
Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set);
|
// No replaceable block... just use temporary storage to
|
||||||
MSHR *repl_mshr = mshrQueue.findMatch(repl_addr);
|
// complete the current request and then get rid of it
|
||||||
if (repl_mshr) {
|
assert(!tempBlock->isValid());
|
||||||
// must be an outstanding upgrade request on block
|
blk = tempBlock;
|
||||||
// we're about to replace...
|
tempBlock->set = tags->extractSet(addr);
|
||||||
assert(!blk->isWritable());
|
DPRINTF(Cache, "using temp block for %x\n", addr);
|
||||||
assert(repl_mshr->needsExclusive());
|
|
||||||
// too hard to replace block with transient state;
|
|
||||||
// just use temporary storage to complete the current
|
|
||||||
// request and then get rid of it
|
|
||||||
assert(!tempBlock->isValid());
|
|
||||||
blk = tempBlock;
|
|
||||||
tempBlock->set = tags->extractSet(addr);
|
|
||||||
DPRINTF(Cache, "using temp block for %x\n", addr);
|
|
||||||
} else {
|
|
||||||
DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
|
|
||||||
repl_addr, addr,
|
|
||||||
blk->isDirty() ? "writeback" : "clean");
|
|
||||||
|
|
||||||
if (blk->isDirty()) {
|
|
||||||
// Save writeback packet for handling by caller
|
|
||||||
writebacks.push_back(writebackBlk(blk));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blk->tag = tags->extractTag(addr);
|
|
||||||
} else {
|
} else {
|
||||||
// existing block... probably an upgrade
|
// existing block... probably an upgrade
|
||||||
assert(blk->tag == tags->extractTag(addr));
|
assert(blk->tag == tags->extractTag(addr));
|
||||||
|
|
Loading…
Reference in a new issue