Handle deferred snoops better.
--HG-- extra : convert_revision : 703da6128832eb0d5cfed7724e5105f4b3fe4f90
This commit is contained in:
parent
69ff6d9163
commit
1b20df5607
6 changed files with 91 additions and 52 deletions
6
src/mem/cache/cache.hh
vendored
6
src/mem/cache/cache.hh
vendored
|
@ -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.
|
||||||
|
|
28
src/mem/cache/cache_impl.hh
vendored
28
src/mem/cache/cache_impl.hh
vendored
|
@ -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,13 +678,11 @@ 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;
|
||||||
blk = handleFill(pkt, blk, writebacks);
|
blk = handleFill(pkt, blk, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
src/mem/cache/miss/mshr.cc
vendored
44
src/mem/cache/miss/mshr.cc
vendored
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DPRINTF(Cache, "deferred snoop on %x: %s %s\n", addr,
|
||||||
|
needsExclusive ? "needsExclusive" : "",
|
||||||
|
pkt->needsExclusive() ? "pkt->needsExclusive()" : "");
|
||||||
|
|
||||||
|
if (needsExclusive || pkt->needsExclusive()) {
|
||||||
|
// actual target device (typ. PhysicalMemory) will delete the
|
||||||
|
// packet on reception, so we need to save a copy here
|
||||||
|
targets.push_back(Target(new Packet(pkt), when, _order, false));
|
||||||
|
++ntargets;
|
||||||
|
|
||||||
if (needsExclusive) {
|
if (needsExclusive) {
|
||||||
// We're awaiting an exclusive copy, so ownership is pending.
|
// We're awaiting an exclusive copy, so ownership is pending.
|
||||||
// It's up to us to respond once the data arrives.
|
// It's up to us to respond once the data arrives.
|
||||||
target->assertMemInhibit();
|
pkt->assertMemInhibit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->needsExclusive()) {
|
if (pkt->needsExclusive()) {
|
||||||
// This transaction will take away our pending copy
|
// This transaction will take away our pending copy
|
||||||
pendingInvalidate = true;
|
pendingInvalidate = true;
|
||||||
} else {
|
|
||||||
// We'll keep our pending copy, but we can't let the other guy
|
|
||||||
// think he's getting it exclusive
|
|
||||||
target->assertShared();
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
targets.push_back(Target(target, when, _order, false));
|
// Read to a read: no conflict, so no need to record as
|
||||||
++ntargets;
|
// target, but make sure neither reader thinks he's getting an
|
||||||
|
// exclusive copy
|
||||||
|
pendingShared = true;
|
||||||
|
pkt->assertShared();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,10 +212,12 @@ 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) {
|
||||||
|
// block was replaced while upgrade request was in service
|
||||||
assert(pkt->cmd == MemCmd::UpgradeResp);
|
assert(pkt->cmd == MemCmd::UpgradeResp);
|
||||||
|
assert(blk == NULL);
|
||||||
assert(replacedPendingUpgrade);
|
assert(replacedPendingUpgrade);
|
||||||
replacedPendingUpgrade = false; // reset
|
replacedPendingUpgrade = false; // reset
|
||||||
if (replacedPendingUpgradeDirty) {
|
if (replacedPendingUpgradeDirty) {
|
||||||
|
@ -219,6 +233,12 @@ MSHR::handleReplacedPendingUpgrade(Packet *pkt)
|
||||||
pkt->setData(data);
|
pkt->setData(data);
|
||||||
delete [] data;
|
delete [] data;
|
||||||
data = NULL;
|
data = NULL;
|
||||||
|
} else if (pendingShared) {
|
||||||
|
// we snooped another read while this read was in
|
||||||
|
// service... assert shared line on its behalf
|
||||||
|
pkt->assertShared();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
src/mem/cache/miss/mshr.hh
vendored
3
src/mem/cache/miss/mshr.hh
vendored
|
@ -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.
|
||||||
|
|
5
src/mem/cache/tags/lru.cc
vendored
5
src/mem/cache/tags/lru.cc
vendored
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue