mem: Deallocate all write-queue entries when sent

This patch removes the write-queue entry tracking previously used for
uncacheable writes. The write-queue entry is now deallocated as soon
as the packet is sent. As a result we also forego the stats for
uncacheable writes. Additionally, there is no longer a need to attach
the write-queue entry to the packet.
This commit is contained in:
Andreas Hansson 2016-04-21 04:48:07 -04:00
parent 6c92ee49f1
commit 13b9d4215d
4 changed files with 14 additions and 101 deletions

View file

@ -1226,45 +1226,13 @@ Cache::functionalAccess(PacketPtr pkt, bool fromCpuSide)
void
Cache::handleUncacheableWriteResp(PacketPtr pkt)
{
WriteQueueEntry *wq_entry =
dynamic_cast<WriteQueueEntry*>(pkt->senderState);
assert(wq_entry);
WriteQueueEntry::Target *target = wq_entry->getTarget();
Packet *tgt_pkt = target->pkt;
// we send out invalidation reqs and get invalidation
// responses for write-line requests
assert(tgt_pkt->cmd != MemCmd::WriteLineReq);
int stats_cmd_idx = tgt_pkt->cmdToIndex();
Tick miss_latency = curTick() - target->recvTime;
assert(pkt->req->masterId() < system->maxMasters());
mshr_uncacheable_lat[stats_cmd_idx][pkt->req->masterId()] +=
miss_latency;
tgt_pkt->makeTimingResponse();
// if this packet is an error copy that to the new packet
if (pkt->isError())
tgt_pkt->copyError(pkt);
// Reset the bus additional time as it is now accounted for
tgt_pkt->headerDelay = tgt_pkt->payloadDelay = 0;
Tick completion_time = clockEdge(responseLatency) +
pkt->headerDelay + pkt->payloadDelay;
cpuSidePort->schedTimingResp(tgt_pkt, completion_time, true);
// Reset the bus additional time as it is now accounted for
pkt->headerDelay = pkt->payloadDelay = 0;
wq_entry->popTarget();
assert(!wq_entry->hasTargets());
bool wasFull = writeBuffer.isFull();
writeBuffer.deallocate(wq_entry);
if (wasFull && !writeBuffer.isFull()) {
clearBlocked(Blocked_NoWBBuffers);
}
delete pkt;
cpuSidePort->schedTimingResp(pkt, completion_time, true);
}
void
@ -1299,7 +1267,7 @@ Cache::recvTimingResp(PacketPtr pkt)
// we have dealt with any (uncacheable) writes above, from here on
// we know we are dealing with an MSHR due to a miss or a prefetch
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
MSHR *mshr = dynamic_cast<MSHR*>(pkt->popSenderState());
assert(mshr);
if (mshr == noTargetMSHR) {
@ -2248,12 +2216,8 @@ Cache::getNextQueueEntry()
WriteQueueEntry *wq_entry = writeBuffer.getNext();
// If we got a write buffer request ready, first priority is a
// full write buffer (but only if we have no uncacheable write
// responses outstanding, possibly revisit this last part),
// otherwhise we favour the miss requests
if (wq_entry &&
((writeBuffer.isFull() && writeBuffer.numInService() == 0) ||
!miss_mshr)) {
// full write buffer, otherwise we favour the miss requests
if (wq_entry && (writeBuffer.isFull() || !miss_mshr)) {
// need to search MSHR queue for conflicting earlier miss.
MSHR *conflict_mshr =
mshrQueue.findPending(wq_entry->blkAddr,
@ -2501,34 +2465,8 @@ Cache::sendWriteQueuePacket(WriteQueueEntry* wq_entry)
tgt_pkt->cmdString(), tgt_pkt->getAddr(),
tgt_pkt->getSize());
PacketPtr pkt = nullptr;
bool delete_pkt = false;
if (tgt_pkt->isEviction()) {
assert(!wq_entry->isUncacheable());
// no response expected, just forward packet as it is
pkt = tgt_pkt;
} else {
// the only thing we deal with besides eviction commands
// are uncacheable writes
assert(tgt_pkt->req->isUncacheable() && tgt_pkt->isWrite());
// not a cache block request, but a response is expected
// make copy of current packet to forward, keep current
// copy for response handling
pkt = new Packet(tgt_pkt, false, true);
pkt->setData(tgt_pkt->getConstPtr<uint8_t>());
delete_pkt = true;
}
pkt->pushSenderState(wq_entry);
if (!memSidePort->sendTimingReq(pkt)) {
if (delete_pkt) {
// we are awaiting a retry, but we
// delete the packet and will be creating a new packet
// when we get the opportunity
delete pkt;
}
// forward as is, both for evictions and uncacheable writes
if (!memSidePort->sendTimingReq(tgt_pkt)) {
// note that we have now masked any requestBus and
// schedSendEvent (we will wait for a retry before
// doing anything), and this is so even if we do not

View file

@ -75,17 +75,10 @@ WriteQueue::allocate(Addr blk_addr, unsigned blk_size, PacketPtr pkt,
void
WriteQueue::markInService(WriteQueueEntry *entry)
{
if (!entry->isUncacheable()) {
// a normal eviction, such as a writeback or a clean evict, no
// more to do as we are done from the perspective of this
// cache
entry->popTarget();
deallocate(entry);
} else {
// uncacheable write, and we will eventually receive a
// response
entry->markInService();
readyList.erase(entry->readyIter);
_numInService += 1;
}
// for a normal eviction, such as a writeback or a clean evict,
// there is no more to do as we are done from the perspective of
// this cache, and for uncacheable write we do not need the entry
// as part of the response handling
entry->popTarget();
deallocate(entry);
}

View file

@ -118,23 +118,6 @@ WriteQueueEntry::allocate(Addr blk_addr, unsigned blk_size, PacketPtr target,
targets.add(target, when_ready, _order);
}
bool
WriteQueueEntry::markInService()
{
assert(!inService);
if (!isUncacheable()) {
// we just forwarded the request packet & don't expect a
// response, so get rid of it
assert(getNumTargets() == 1);
popTarget();
return true;
}
inService = true;
return false;
}
void
WriteQueueEntry::deallocate()
{

View file

@ -136,7 +136,6 @@ class WriteQueueEntry : public QueueEntry, public Printable
void allocate(Addr blk_addr, unsigned blk_size, PacketPtr pkt,
Tick when_ready, Counter _order);
bool markInService();
/**
* Mark this entry as free.