Better handling of deferred targets.

--HG--
extra : convert_revision : 0fbc28c32c1eeb3dd672df14c1d53bd516f81d0f
This commit is contained in:
Steve Reinhardt 2007-06-24 17:32:31 -07:00
parent 245b0bd9b9
commit 47bce8ef78
6 changed files with 144 additions and 104 deletions

View file

@ -42,8 +42,7 @@ using namespace std;
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache) BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
: SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL), : SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL),
blocked(false), waitingOnRetry(false), mustSendRetry(false), blocked(false), mustSendRetry(false), requestCauses(0)
requestCauses(0)
{ {
} }

View file

@ -118,8 +118,6 @@ class BaseCache : public MemObject
bool blocked; bool blocked;
bool waitingOnRetry;
bool mustSendRetry; bool mustSendRetry;
/** /**

View file

@ -182,8 +182,7 @@ class Cache : public BaseCache
BlkType *handleFill(PacketPtr pkt, BlkType *blk, BlkType *handleFill(PacketPtr pkt, BlkType *blk,
PacketList &writebacks); PacketList &writebacks);
bool satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk); void satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk);
bool satisfyTarget(MSHR::Target *target, 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);

View file

@ -368,7 +368,7 @@ Cache<TagStore,Coherence>::timingAccess(PacketPtr pkt)
if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) { if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) {
mshr->threadNum = -1; mshr->threadNum = -1;
} }
mshr->allocateTarget(pkt, true); mshr->allocateTarget(pkt);
if (mshr->getNumTargets() == numTarget) { if (mshr->getNumTargets() == numTarget) {
noTargetMSHR = mshr; noTargetMSHR = mshr;
setBlocked(Blocked_NoTargets); setBlocked(Blocked_NoTargets);
@ -483,8 +483,7 @@ Cache<TagStore,Coherence>::atomicAccess(PacketPtr pkt)
if (isCacheFill) { if (isCacheFill) {
PacketList writebacks; PacketList writebacks;
blk = handleFill(busPkt, blk, writebacks); blk = handleFill(busPkt, blk, writebacks);
bool status = satisfyCpuSideRequest(pkt, blk); satisfyCpuSideRequest(pkt, blk);
assert(status);
delete busPkt; delete busPkt;
// Handle writebacks if needed // Handle writebacks if needed
@ -538,12 +537,14 @@ Cache<TagStore,Coherence>::functionalAccess(PacketPtr pkt,
// There can be many matching outstanding writes. // There can be many matching outstanding writes.
std::vector<MSHR*> writes; std::vector<MSHR*> writes;
writeBuffer.findMatches(blk_addr, writes); assert(!writeBuffer.findMatches(blk_addr, writes));
/* Need to change this to iterate through targets in mshr??
for (int i = 0; i < writes.size(); ++i) { for (int i = 0; i < writes.size(); ++i) {
MSHR *mshr = writes[i]; MSHR *mshr = writes[i];
if (pkt->checkFunctional(mshr->addr, mshr->size, mshr->writeData)) if (pkt->checkFunctional(mshr->addr, mshr->size, mshr->writeData))
return; return;
} }
*/
otherSidePort->checkAndSendFunctional(pkt); otherSidePort->checkAndSendFunctional(pkt);
} }
@ -557,43 +558,30 @@ Cache<TagStore,Coherence>::functionalAccess(PacketPtr pkt,
template<class TagStore, class Coherence> template<class TagStore, class Coherence>
bool void
Cache<TagStore,Coherence>::satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk) Cache<TagStore,Coherence>::satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk)
{ {
if (blk && (pkt->needsExclusive() ? blk->isWritable() : blk->isValid())) { assert(blk);
assert(pkt->isWrite() || pkt->isReadWrite() || pkt->isRead()); assert(pkt->needsExclusive() ? blk->isWritable() : blk->isValid());
assert(pkt->getOffset(blkSize) + pkt->getSize() <= blkSize); assert(pkt->isWrite() || pkt->isReadWrite() || pkt->isRead());
assert(pkt->getOffset(blkSize) + pkt->getSize() <= blkSize);
if (pkt->isWrite()) { if (pkt->isWrite()) {
if (blk->checkWrite(pkt)) { if (blk->checkWrite(pkt)) {
blk->status |= BlkDirty; blk->status |= BlkDirty;
pkt->writeDataToBlock(blk->data, blkSize); pkt->writeDataToBlock(blk->data, blkSize);
}
} else if (pkt->isReadWrite()) {
cmpAndSwap(blk, pkt);
} else {
if (pkt->isLocked()) {
blk->trackLoadLocked(pkt);
}
pkt->setDataFromBlock(blk->data, blkSize);
} }
} else if (pkt->isReadWrite()) {
return true; cmpAndSwap(blk, pkt);
} else { } else {
return false; if (pkt->isLocked()) {
blk->trackLoadLocked(pkt);
}
pkt->setDataFromBlock(blk->data, blkSize);
} }
} }
template<class TagStore, class Coherence>
bool
Cache<TagStore,Coherence>::satisfyTarget(MSHR::Target *target, BlkType *blk)
{
assert(target != NULL);
assert(target->isCpuSide());
return satisfyCpuSideRequest(target->pkt, blk);
}
template<class TagStore, class Coherence> template<class TagStore, class Coherence>
bool bool
Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt, Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt,
@ -611,37 +599,42 @@ Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt,
while (mshr->hasTargets()) { while (mshr->hasTargets()) {
MSHR::Target *target = mshr->getTarget(); MSHR::Target *target = mshr->getTarget();
if (!satisfyTarget(target, blk)) { if (target->isCpuSide()) {
// Invalid access, need to do another request satisfyCpuSideRequest(target->pkt, blk);
// can occur if block is invalidated, or not correct // How many bytes pass the first request is this one
// permissions int transfer_offset =
MSHRQueue *mq = mshr->queue; target->pkt->getOffset(blkSize) - initial_offset;
mq->markPending(mshr); if (transfer_offset < 0) {
mshr->order = order++; transfer_offset += blkSize;
requestMemSideBus((RequestCause)mq->index, pkt->finishTime); }
return false;
// If critical word (no offset) return first word time
Tick completion_time = tags->getHitLatency() +
transfer_offset ? pkt->finishTime : pkt->firstWordTime;
if (!target->pkt->req->isUncacheable()) {
missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
completion_time - target->time;
}
target->pkt->makeTimingResponse();
cpuSidePort->respond(target->pkt, completion_time);
} else {
// response to snoop request
DPRINTF(Cache, "processing deferred snoop...\n");
handleSnoop(target->pkt, blk, true);
} }
// How many bytes pass the first request is this one
int transfer_offset = target->pkt->getOffset(blkSize) - initial_offset;
if (transfer_offset < 0) {
transfer_offset += blkSize;
}
// If critical word (no offset) return first word time
Tick completion_time = tags->getHitLatency() +
transfer_offset ? pkt->finishTime : pkt->firstWordTime;
if (!target->pkt->req->isUncacheable()) {
missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
completion_time - target->time;
}
target->pkt->makeTimingResponse();
cpuSidePort->respond(target->pkt, completion_time);
mshr->popTarget(); mshr->popTarget();
} }
if (mshr->promoteDeferredTargets()) {
MSHRQueue *mq = mshr->queue;
mq->markPending(mshr);
mshr->order = order++;
requestMemSideBus((RequestCause)mq->index, pkt->finishTime);
return false;
}
return true; return true;
} }
@ -653,6 +646,7 @@ Cache<TagStore,Coherence>::handleResponse(PacketPtr pkt)
Tick time = curTick + hitLatency; Tick time = curTick + hitLatency;
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
assert(mshr); assert(mshr);
if (pkt->result == Packet::Nacked) { if (pkt->result == Packet::Nacked) {
//pkt->reinitFromRequest(); //pkt->reinitFromRequest();
warn("NACKs from devices not connected to the same bus " warn("NACKs from devices not connected to the same bus "
@ -661,7 +655,7 @@ Cache<TagStore,Coherence>::handleResponse(PacketPtr pkt)
} }
assert(pkt->result != Packet::BadAddress); assert(pkt->result != Packet::BadAddress);
assert(pkt->result == Packet::Success); assert(pkt->result == Packet::Success);
DPRINTF(Cache, "Handling reponse to %x\n", pkt->getAddr()); DPRINTF(Cache, "Handling response to %x\n", pkt->getAddr());
MSHRQueue *mq = mshr->queue; MSHRQueue *mq = mshr->queue;
bool wasFull = mq->isFull(); bool wasFull = mq->isFull();
@ -883,7 +877,12 @@ Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
MSHR *mshr = mshrQueue.findMatch(blk_addr); MSHR *mshr = mshrQueue.findMatch(blk_addr);
// 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...
assert(!mshr || !mshr->inService); if (mshr && mshr->inService) {
assert(mshr->getNumTargets() < numTarget); //handle later
mshr->allocateSnoopTarget(pkt);
assert(mshr->getNumTargets() < numTarget); //handle later
return;
}
//We also need to check the writeback buffers and handle those //We also need to check the writeback buffers and handle those
std::vector<MSHR *> writebacks; std::vector<MSHR *> writebacks;
@ -895,6 +894,9 @@ Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
for (int i=0; i<writebacks.size(); i++) { for (int i=0; i<writebacks.size(); i++) {
mshr = writebacks[i]; mshr = writebacks[i];
assert(!mshr->isUncacheable()); assert(!mshr->isUncacheable());
assert(mshr->getNumTargets() == 1);
PacketPtr wb_pkt = mshr->getTarget()->pkt;
assert(wb_pkt->cmd == MemCmd::Writeback);
if (pkt->isRead()) { if (pkt->isRead()) {
pkt->assertMemInhibit(); pkt->assertMemInhibit();
@ -906,7 +908,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, mshr->writeData); doTimingSupplyResponse(pkt, wb_pkt->getPtr<uint8_t>());
} }
if (pkt->isInvalidate()) { if (pkt->isInvalidate()) {
@ -1208,7 +1210,7 @@ Cache<TagStore,Coherence>::MemSidePort::sendPacket()
waitingOnRetry = !success; waitingOnRetry = !success;
if (waitingOnRetry) { if (waitingOnRetry) {
DPRINTF(CachePort, "%s now waiting on a retry\n", name()); DPRINTF(CachePort, "now waiting on a retry\n");
} else { } else {
myCache()->markInService(mshr); myCache()->markInService(mshr);
} }
@ -1220,8 +1222,7 @@ Cache<TagStore,Coherence>::MemSidePort::sendPacket()
if (!waitingOnRetry) { if (!waitingOnRetry) {
if (isBusRequested()) { if (isBusRequested()) {
// more requests/writebacks: rerequest ASAP // more requests/writebacks: rerequest ASAP
DPRINTF(CachePort, "%s still more MSHR requests to send\n", DPRINTF(CachePort, "still more MSHR requests to send\n");
name());
sendEvent->schedule(curTick+1); sendEvent->schedule(curTick+1);
} else if (!transmitList.empty()) { } else if (!transmitList.empty()) {
// deferred packets: rerequest bus, but possibly not until later // deferred packets: rerequest bus, but possibly not until later

View file

@ -68,12 +68,16 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target)
// Don't know of a case where we would allocate a new MSHR for a // Don't know of a case where we would allocate a new MSHR for a
// snoop (mem0-side request), so set cpuSide to true here. // snoop (mem0-side request), so set cpuSide to true here.
targets.push_back(Target(target, true)); targets.push_back(Target(target, true));
assert(deferredTargets.empty());
deferredNeedsExclusive = false;
pendingInvalidate = false;
} }
void void
MSHR::deallocate() MSHR::deallocate()
{ {
assert(targets.empty()); assert(targets.empty());
assert(deferredTargets.empty());
assert(ntargets == 0); assert(ntargets == 0);
inService = false; inService = false;
//allocIter = NULL; //allocIter = NULL;
@ -84,41 +88,77 @@ MSHR::deallocate()
* Adds a target to an MSHR * Adds a target to an MSHR
*/ */
void void
MSHR::allocateTarget(PacketPtr target, bool cpuSide) MSHR::allocateTarget(PacketPtr target)
{ {
//If we append an invalidate and we issued a read to the bus, if (inService) {
//but now have some pending writes, we need to move if (!deferredTargets.empty() || pendingInvalidate ||
//the invalidate to before the first non-read (!needsExclusive && target->needsExclusive())) {
if (inService && !inServiceForExclusive && needsExclusive // need to put on deferred list
&& !cpuSide && target->isInvalidate()) { deferredTargets.push_back(Target(target, true));
std::list<Target> temp; if (target->needsExclusive()) {
deferredNeedsExclusive = true;
while (!targets.empty()) { }
if (targets.front().pkt->needsExclusive()) break; } else {
//Place on top of temp stack // still OK to append to outstanding request
temp.push_front(targets.front()); targets.push_back(Target(target, true));
//Remove from targets }
targets.pop_front(); } else {
if (target->needsExclusive()) {
needsExclusive = true;
} }
//Now that we have all the reads off until first non-read, we can targets.push_back(Target(target, true));
//place the invalidate on
targets.push_front(Target(target, cpuSide));
//Now we pop off the temp_stack and put them back
while (!temp.empty()) {
targets.push_front(temp.front());
temp.pop_front();
}
}
else {
targets.push_back(Target(target, cpuSide));
} }
++ntargets; ++ntargets;
}
void
MSHR::allocateSnoopTarget(PacketPtr target)
{
assert(inService); // don't bother to call otherwise
if (pendingInvalidate) {
// a prior snoop has already appended an invalidation, so
// logically we don't have the block anymore...
return;
}
if (needsExclusive) {
// We're awaiting an exclusive copy, so ownership is pending.
// It's up to us to respond once the data arrives.
target->assertMemInhibit();
} else if (target->needsExclusive()) {
// This transaction will take away our pending copy
pendingInvalidate = true;
} else {
// If we're not going to supply data or perform an
// invalidation, we don't need to save this.
return;
}
targets.push_back(Target(target, false));
++ntargets;
}
bool
MSHR::promoteDeferredTargets()
{
if (deferredTargets.empty()) {
return false;
}
assert(targets.empty());
targets = deferredTargets;
deferredTargets.clear();
assert(targets.size() == ntargets); assert(targets.size() == ntargets);
needsExclusive = needsExclusive || target->needsExclusive(); needsExclusive = deferredNeedsExclusive;
pendingInvalidate = false;
deferredNeedsExclusive = false;
return true;
} }

View file

@ -85,9 +85,6 @@ class MSHR : public Packet::SenderState
/** Size of the request. */ /** Size of the request. */
int size; int size;
/** Data associated with the request (if a write). */
uint8_t *writeData;
/** True if the request has been sent to the bus. */ /** True if the request has been sent to the bus. */
bool inService; bool inService;
@ -95,12 +92,13 @@ class MSHR : public Packet::SenderState
bool isCacheFill; bool isCacheFill;
/** True if we need to get an exclusive copy of the block. */ /** True if we need to get an exclusive copy of the block. */
bool needsExclusive; bool needsExclusive;
/** True if the request is uncacheable */ /** True if the request is uncacheable */
bool _isUncacheable; bool _isUncacheable;
/** True if the request that has been sent to the bus is for en bool deferredNeedsExclusive;
* exclusive copy. */ bool pendingInvalidate;
bool inServiceForExclusive;
/** Thread number of the miss. */ /** Thread number of the miss. */
short threadNum; short threadNum;
/** The number of currently allocated targets. */ /** The number of currently allocated targets. */
@ -124,6 +122,8 @@ private:
/** List of all requests that match the address */ /** List of all requests that match the address */
TargetList targets; TargetList targets;
TargetList deferredTargets;
public: public:
bool isUncacheable() { return _isUncacheable; } bool isUncacheable() { return _isUncacheable; }
@ -153,7 +153,8 @@ public:
* Add a request to the list of targets. * Add a request to the list of targets.
* @param target The target. * @param target The target.
*/ */
void allocateTarget(PacketPtr target, bool cpuSide); void allocateTarget(PacketPtr target);
void allocateSnoopTarget(PacketPtr target);
/** A simple constructor. */ /** A simple constructor. */
MSHR(); MSHR();
@ -201,6 +202,8 @@ public:
return tgt->isCpuSide() && !tgt->pkt->needsResponse(); return tgt->isCpuSide() && !tgt->pkt->needsResponse();
} }
bool promoteDeferredTargets();
/** /**
* Prints the contents of this MSHR to stderr. * Prints the contents of this MSHR to stderr.
*/ */