Handle deferred snoops better.

--HG--
extra : convert_revision : 703da6128832eb0d5cfed7724e5105f4b3fe4f90
This commit is contained in:
Steve Reinhardt 2007-06-26 22:23:10 -07:00
parent 69ff6d9163
commit 1b20df5607
6 changed files with 91 additions and 52 deletions

View file

@ -185,14 +185,16 @@ class Cache : public BaseCache
void satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk); void satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk);
bool satisfyMSHR(MSHR *mshr, PacketPtr pkt, BlkType *blk); bool satisfyMSHR(MSHR *mshr, PacketPtr pkt, BlkType *blk);
void doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data); void doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data,
bool already_copied);
/** /**
* Sets the blk to the new state. * Sets the blk to the new state.
* @param blk The cache block being snooped. * @param blk The cache block being snooped.
* @param new_state The new coherence state for the block. * @param new_state The new coherence state for the block.
*/ */
void handleSnoop(PacketPtr ptk, BlkType *blk, bool is_timing); void handleSnoop(PacketPtr ptk, BlkType *blk,
bool is_timing, bool is_deferred);
/** /**
* Create a writeback request for the given block. * Create a writeback request for the given block.

View file

@ -622,7 +622,7 @@ Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt,
} else { } else {
// response to snoop request // response to snoop request
DPRINTF(Cache, "processing deferred snoop...\n"); DPRINTF(Cache, "processing deferred snoop...\n");
handleSnoop(target->pkt, blk, true); handleSnoop(target->pkt, blk, true, true);
} }
mshr->popTarget(); mshr->popTarget();
@ -678,12 +678,10 @@ Cache<TagStore,Coherence>::handleResponse(PacketPtr pkt)
pkt->getAddr()); pkt->getAddr());
BlkType *blk = tags->findBlock(pkt->getAddr()); BlkType *blk = tags->findBlock(pkt->getAddr());
if (blk == NULL && pkt->cmd == MemCmd::UpgradeResp) { if (!mshr->handleFill(pkt, blk)) {
if (!mshr->handleReplacedPendingUpgrade(pkt)) { mq->markPending(mshr);
mq->markPending(mshr); requestMemSideBus((RequestCause)mq->index, pkt->finishTime);
requestMemSideBus((RequestCause)mq->index, pkt->finishTime); return;
return;
}
} }
PacketList writebacks; PacketList writebacks;
@ -814,10 +812,12 @@ Cache<TagStore,Coherence>::handleFill(PacketPtr pkt, BlkType *blk,
template<class TagStore, class Coherence> template<class TagStore, class Coherence>
void void
Cache<TagStore,Coherence>::doTimingSupplyResponse(PacketPtr req_pkt, Cache<TagStore,Coherence>::doTimingSupplyResponse(PacketPtr req_pkt,
uint8_t *blk_data) uint8_t *blk_data,
bool already_copied)
{ {
// timing-mode snoop responses require a new packet // timing-mode snoop responses require a new packet, unless we
PacketPtr pkt = new Packet(req_pkt); // already made a copy...
PacketPtr pkt = already_copied ? req_pkt : new Packet(req_pkt);
pkt->allocate(); pkt->allocate();
pkt->makeTimingResponse(); pkt->makeTimingResponse();
pkt->setDataFromBlock(blk_data, blkSize); pkt->setDataFromBlock(blk_data, blkSize);
@ -827,7 +827,7 @@ Cache<TagStore,Coherence>::doTimingSupplyResponse(PacketPtr req_pkt,
template<class TagStore, class Coherence> template<class TagStore, class Coherence>
void void
Cache<TagStore,Coherence>::handleSnoop(PacketPtr pkt, BlkType *blk, Cache<TagStore,Coherence>::handleSnoop(PacketPtr pkt, BlkType *blk,
bool is_timing) bool is_timing, bool is_deferred)
{ {
if (!blk || !blk->isValid()) { if (!blk || !blk->isValid()) {
return; return;
@ -854,9 +854,10 @@ Cache<TagStore,Coherence>::handleSnoop(PacketPtr pkt, BlkType *blk,
} }
if (supply) { if (supply) {
assert(!pkt->memInhibitAsserted());
pkt->assertMemInhibit(); pkt->assertMemInhibit();
if (is_timing) { if (is_timing) {
doTimingSupplyResponse(pkt, blk->data); doTimingSupplyResponse(pkt, blk->data, is_deferred);
} else { } else {
pkt->makeAtomicResponse(); pkt->makeAtomicResponse();
pkt->setDataFromBlock(blk->data, blkSize); pkt->setDataFromBlock(blk->data, blkSize);
@ -892,6 +893,8 @@ Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
// better not be snooping a request that conflicts with something // better not be snooping a request that conflicts with something
// we have outstanding... // we have outstanding...
if (mshr && mshr->inService) { if (mshr && mshr->inService) {
DPRINTF(Cache, "Deferring snoop on in-service MSHR to blk %x\n",
blk_addr);
mshr->allocateSnoopTarget(pkt, curTick, order++); mshr->allocateSnoopTarget(pkt, curTick, order++);
if (mshr->getNumTargets() > numTarget) if (mshr->getNumTargets() > numTarget)
warn("allocating bonus target for snoop"); //handle later warn("allocating bonus target for snoop"); //handle later
@ -913,6 +916,7 @@ Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
assert(wb_pkt->cmd == MemCmd::Writeback); assert(wb_pkt->cmd == MemCmd::Writeback);
if (pkt->isRead()) { if (pkt->isRead()) {
assert(!pkt->memInhibitAsserted());
pkt->assertMemInhibit(); pkt->assertMemInhibit();
if (!pkt->needsExclusive()) { if (!pkt->needsExclusive()) {
pkt->assertShared(); pkt->assertShared();
@ -922,7 +926,7 @@ Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
// the packet's invalidate flag is set... // the packet's invalidate flag is set...
assert(pkt->isInvalidate()); assert(pkt->isInvalidate());
} }
doTimingSupplyResponse(pkt, wb_pkt->getPtr<uint8_t>()); doTimingSupplyResponse(pkt, wb_pkt->getPtr<uint8_t>(), false);
} }
if (pkt->isInvalidate()) { if (pkt->isInvalidate()) {
@ -933,7 +937,7 @@ Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
} }
} }
handleSnoop(pkt, blk, true); handleSnoop(pkt, blk, true, false);
} }
@ -948,7 +952,7 @@ Cache<TagStore,Coherence>::snoopAtomic(PacketPtr pkt)
} }
BlkType *blk = tags->findBlock(pkt->getAddr()); BlkType *blk = tags->findBlock(pkt->getAddr());
handleSnoop(pkt, blk, false); handleSnoop(pkt, blk, false, false);
return hitLatency; return hitLatency;
} }

View file

@ -75,6 +75,7 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target,
assert(deferredTargets.empty()); assert(deferredTargets.empty());
deferredNeedsExclusive = false; deferredNeedsExclusive = false;
pendingInvalidate = false; pendingInvalidate = false;
pendingShared = false;
replacedPendingUpgrade = false; replacedPendingUpgrade = false;
data = NULL; data = NULL;
} }
@ -120,7 +121,7 @@ MSHR::allocateTarget(PacketPtr target, Tick when, Counter _order)
} }
void void
MSHR::allocateSnoopTarget(PacketPtr target, Tick when, Counter _order) MSHR::allocateSnoopTarget(PacketPtr pkt, Tick when, Counter _order)
{ {
assert(inService); // don't bother to call otherwise assert(inService); // don't bother to call otherwise
@ -130,23 +131,33 @@ MSHR::allocateSnoopTarget(PacketPtr target, Tick when, Counter _order)
return; return;
} }
if (needsExclusive) { DPRINTF(Cache, "deferred snoop on %x: %s %s\n", addr,
// We're awaiting an exclusive copy, so ownership is pending. needsExclusive ? "needsExclusive" : "",
// It's up to us to respond once the data arrives. pkt->needsExclusive() ? "pkt->needsExclusive()" : "");
target->assertMemInhibit();
}
if (target->needsExclusive()) { if (needsExclusive || pkt->needsExclusive()) {
// This transaction will take away our pending copy // actual target device (typ. PhysicalMemory) will delete the
pendingInvalidate = true; // packet on reception, so we need to save a copy here
targets.push_back(Target(new Packet(pkt), when, _order, false));
++ntargets;
if (needsExclusive) {
// We're awaiting an exclusive copy, so ownership is pending.
// It's up to us to respond once the data arrives.
pkt->assertMemInhibit();
}
if (pkt->needsExclusive()) {
// This transaction will take away our pending copy
pendingInvalidate = true;
}
} else { } else {
// We'll keep our pending copy, but we can't let the other guy // Read to a read: no conflict, so no need to record as
// think he's getting it exclusive // target, but make sure neither reader thinks he's getting an
target->assertShared(); // exclusive copy
pendingShared = true;
pkt->assertShared();
} }
targets.push_back(Target(target, when, _order, false));
++ntargets;
} }
@ -164,6 +175,7 @@ MSHR::promoteDeferredTargets()
needsExclusive = deferredNeedsExclusive; needsExclusive = deferredNeedsExclusive;
pendingInvalidate = false; pendingInvalidate = false;
pendingShared = false;
deferredNeedsExclusive = false; deferredNeedsExclusive = false;
order = targets.front().order; order = targets.front().order;
readyTick = std::max(curTick, targets.front().time); readyTick = std::max(curTick, targets.front().time);
@ -200,25 +212,33 @@ MSHR::handleReplacement(CacheBlk *blk, int blkSize)
bool bool
MSHR::handleReplacedPendingUpgrade(Packet *pkt) MSHR::handleFill(Packet *pkt, CacheBlk *blk)
{ {
// @TODO: if upgrade is nacked and replacedPendingUpgradeDirty is true, then we need to writeback the data (or rel if (replacedPendingUpgrade) {
assert(pkt->cmd == MemCmd::UpgradeResp); // block was replaced while upgrade request was in service
assert(replacedPendingUpgrade); assert(pkt->cmd == MemCmd::UpgradeResp);
replacedPendingUpgrade = false; // reset assert(blk == NULL);
if (replacedPendingUpgradeDirty) { assert(replacedPendingUpgrade);
// we wrote back the previous copy; just reissue as a ReadEx replacedPendingUpgrade = false; // reset
return false; if (replacedPendingUpgradeDirty) {
// we wrote back the previous copy; just reissue as a ReadEx
return false;
}
// previous copy was not dirty, but we are now owner... fake out
// cache by taking saved data and converting UpgradeResp to
// ReadExResp
assert(data);
pkt->cmd = MemCmd::ReadExResp;
pkt->setData(data);
delete [] data;
data = NULL;
} else if (pendingShared) {
// we snooped another read while this read was in
// service... assert shared line on its behalf
pkt->assertShared();
} }
// previous copy was not dirty, but we are now owner... fake out
// cache by taking saved data and converting UpgradeResp to
// ReadExResp
assert(data);
pkt->cmd = MemCmd::ReadExResp;
pkt->setData(data);
delete [] data;
data = NULL;
return true; return true;
} }

View file

@ -105,6 +105,7 @@ class MSHR : public Packet::SenderState
bool deferredNeedsExclusive; bool deferredNeedsExclusive;
bool pendingInvalidate; bool pendingInvalidate;
bool pendingShared;
/** Is there a pending upgrade that got replaced? */ /** Is there a pending upgrade that got replaced? */
bool replacedPendingUpgrade; bool replacedPendingUpgrade;
bool replacedPendingUpgradeDirty; bool replacedPendingUpgradeDirty;
@ -213,7 +214,7 @@ public:
bool promoteDeferredTargets(); bool promoteDeferredTargets();
void handleReplacement(CacheBlk *blk, int blkSize); void handleReplacement(CacheBlk *blk, int blkSize);
bool handleReplacedPendingUpgrade(Packet *pkt); bool handleFill(Packet *pkt, CacheBlk *blk);
/** /**
* Prints the contents of this MSHR to stderr. * Prints the contents of this MSHR to stderr.

View file

@ -207,6 +207,9 @@ LRU::findReplacement(Addr addr, PacketList &writebacks)
totalRefs += blk->refCount; totalRefs += blk->refCount;
++sampledRefs; ++sampledRefs;
blk->refCount = 0; blk->refCount = 0;
DPRINTF(Cache, "set %x: selecting blk %x for replacement\n",
set, regenerateBlkAddr(blk->tag, set));
} else if (!blk->isTouched) { } else if (!blk->isTouched) {
tagsInUse++; tagsInUse++;
blk->isTouched = true; blk->isTouched = true;
@ -216,8 +219,6 @@ LRU::findReplacement(Addr addr, PacketList &writebacks)
} }
} }
DPRINTF(Cache, "set %x: selecting blk %x for replacement\n",
set, regenerateBlkAddr(blk->tag, set));
return blk; return blk;
} }

View file

@ -69,11 +69,21 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
// if we ever added it back. // if we ever added it back.
assert(pkt->isRequest()); assert(pkt->isRequest());
assert(pkt->result == Packet::Unknown); assert(pkt->result == Packet::Unknown);
if (pkt->memInhibitAsserted()) {
// snooper will supply based on copy of packet
// still target's responsibility to delete packet
delete pkt->req;
delete pkt;
return true;
}
bool needsResponse = pkt->needsResponse(); bool needsResponse = pkt->needsResponse();
Tick latency = recvAtomic(pkt); Tick latency = recvAtomic(pkt);
// turn packet around to go back to requester if response expected // turn packet around to go back to requester if response expected
if (needsResponse) { if (needsResponse) {
// recvAtomic() should already have turned packet into atomic response // recvAtomic() should already have turned packet into
// atomic response
assert(pkt->isResponse()); assert(pkt->isResponse());
pkt->convertAtomicToTimingResponse(); pkt->convertAtomicToTimingResponse();
schedSendTiming(pkt, curTick + latency); schedSendTiming(pkt, curTick + latency);
@ -81,6 +91,7 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
delete pkt->req; delete pkt->req;
delete pkt; delete pkt;
} }
return true; return true;
} }