diff options
Diffstat (limited to 'src/mem/cache/base_cache.hh')
-rw-r--r-- | src/mem/cache/base_cache.hh | 633 |
1 files changed, 228 insertions, 405 deletions
diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh index f06a79dc0..719ab0245 100644 --- a/src/mem/cache/base_cache.hh +++ b/src/mem/cache/base_cache.hh @@ -26,6 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Erik Hallnor + * Steve Reinhardt + * Ron Dreslinski */ /** @@ -39,37 +41,19 @@ #include <vector> #include <string> #include <list> +#include <algorithm> #include <inttypes.h> #include "base/misc.hh" #include "base/statistics.hh" #include "base/trace.hh" +#include "mem/cache/miss/mshr_queue.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" -#include "mem/port.hh" +#include "mem/tport.hh" #include "mem/request.hh" #include "sim/eventq.hh" - -/** - * Reasons for Caches to be Blocked. - */ -enum BlockedCause{ - Blocked_NoMSHRs, - Blocked_NoTargets, - Blocked_NoWBBuffers, - Blocked_Coherence, - NUM_BLOCKED_CAUSES -}; - -/** - * Reasons for cache to request a bus. - */ -enum RequestCause{ - Request_MSHR, - Request_WB, - Request_Coherence, - Request_PF -}; +#include "sim/sim_exit.hh" class MSHR; /** @@ -77,91 +61,133 @@ class MSHR; */ class BaseCache : public MemObject { - class CachePort : public Port + /** + * Indexes to enumerate the MSHR queues. + */ + enum MSHRQueueIndex { + MSHRQueue_MSHRs, + MSHRQueue_WriteBuffer + }; + + /** + * Reasons for caches to be blocked. + */ + enum BlockedCause { + Blocked_NoMSHRs = MSHRQueue_MSHRs, + Blocked_NoWBBuffers = MSHRQueue_WriteBuffer, + Blocked_NoTargets, + NUM_BLOCKED_CAUSES + }; + + public: + /** + * Reasons for cache to request a bus. + */ + enum RequestCause { + Request_MSHR = MSHRQueue_MSHRs, + Request_WB = MSHRQueue_WriteBuffer, + Request_PF, + NUM_REQUEST_CAUSES + }; + + private: + + class CachePort : public SimpleTimingPort { public: BaseCache *cache; protected: - CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide); - virtual void recvStatusChange(Status status); + CachePort(const std::string &_name, BaseCache *_cache); - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop); + virtual void recvStatusChange(Status status); virtual int deviceBlockSize(); - virtual void recvRetry(); + bool recvRetryCommon(); + + typedef EventWrapper<Port, &Port::sendRetry> + SendRetryEvent; public: + void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; } + void setBlocked(); void clearBlocked(); - bool checkFunctional(PacketPtr pkt); - void checkAndSendFunctional(PacketPtr pkt); - bool canDrain() { return drainList.empty() && transmitList.empty(); } + CachePort *otherPort; bool blocked; bool mustSendRetry; - bool isCpuSide; + void requestBus(RequestCause cause, Tick time) + { + DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause); + if (!waitingOnRetry) { + schedSendEvent(time); + } + } - bool waitingOnRetry; + void respond(PacketPtr pkt, Tick time) { + schedSendTiming(pkt, time); + } + }; - std::list<PacketPtr> drainList; + public: //Made public so coherence can get at it. + CachePort *cpuSidePort; + CachePort *memSidePort; - std::list<std::pair<Tick,PacketPtr> > transmitList; - }; + protected: - struct RequestEvent : public Event - { - CachePort *cachePort; + /** Miss status registers */ + MSHRQueue mshrQueue; - RequestEvent(CachePort *_cachePort, Tick when); - void process(); - const char *description(); - }; + /** Write/writeback buffer */ + MSHRQueue writeBuffer; - struct ResponseEvent : public Event + MSHR *allocateBufferInternal(MSHRQueue *mq, Addr addr, int size, + PacketPtr pkt, Tick time, bool requestBus) { - CachePort *cachePort; + MSHR *mshr = mq->allocate(addr, size, pkt, time, order++); - ResponseEvent(CachePort *_cachePort); - void process(); - const char *description(); - }; + if (mq->isFull()) { + setBlocked((BlockedCause)mq->index); + } - public: //Made public so coherence can get at it. - CachePort *cpuSidePort; - CachePort *memSidePort; + if (requestBus) { + requestMemSideBus((RequestCause)mq->index, time); + } - ResponseEvent *sendEvent; - ResponseEvent *memSendEvent; + return mshr; + } - private: - void recvStatusChange(Port::Status status, bool isCpuSide) + void markInServiceInternal(MSHR *mshr) { - if (status == Port::RangeChange){ - if (!isCpuSide) { - cpuSidePort->sendStatusChange(Port::RangeChange); - } - else { - memSidePort->sendStatusChange(Port::RangeChange); - } + MSHRQueue *mq = mshr->queue; + bool wasFull = mq->isFull(); + mq->markInService(mshr); + if (wasFull && !mq->isFull()) { + clearBlocked((BlockedCause)mq->index); } } - virtual PacketPtr getPacket() = 0; + /** Block size of this cache */ + const int blkSize; - virtual PacketPtr getCoherencePacket() = 0; + /** + * The latency of a hit in this device. + */ + int hitLatency; - virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success) = 0; + /** The number of targets for each MSHR. */ + const int numTarget; - virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success) = 0; + /** Increasing order number assigned to each incoming request. */ + uint64_t order; /** * Bit vector of the blocking reasons for the access path. @@ -169,29 +195,11 @@ class BaseCache : public MemObject */ uint8_t blocked; - /** - * Bit vector for the blocking reasons for the snoop path. - * @sa #BlockedCause - */ - uint8_t blockedSnoop; - - /** - * Bit vector for the outstanding requests for the master interface. - */ - uint8_t masterRequests; - - /** - * Bit vector for the outstanding requests for the slave interface. - */ - uint8_t slaveRequests; - - protected: - /** Stores time the cache blocked for statistics. */ Tick blockedCycle; - /** Block size of this cache */ - const int blkSize; + /** Pointer to the MSHR that has no targets. */ + MSHR *noTargetMSHR; /** The number of misses to trigger an exit event. */ Counter missCount; @@ -265,6 +273,73 @@ class BaseCache : public MemObject /** The number of cache copies performed. */ Stats::Scalar<> cacheCopies; + /** Number of blocks written back per thread. */ + Stats::Vector<> writebacks; + + /** Number of misses that hit in the MSHRs per command and thread. */ + Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS]; + /** Demand misses that hit in the MSHRs. */ + Stats::Formula demandMshrHits; + /** Total number of misses that hit in the MSHRs. */ + Stats::Formula overallMshrHits; + + /** Number of misses that miss in the MSHRs, per command and thread. */ + Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS]; + /** Demand misses that miss in the MSHRs. */ + Stats::Formula demandMshrMisses; + /** Total number of misses that miss in the MSHRs. */ + Stats::Formula overallMshrMisses; + + /** Number of misses that miss in the MSHRs, per command and thread. */ + Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS]; + /** Total number of misses that miss in the MSHRs. */ + Stats::Formula overallMshrUncacheable; + + /** Total cycle latency of each MSHR miss, per command and thread. */ + Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS]; + /** Total cycle latency of demand MSHR misses. */ + Stats::Formula demandMshrMissLatency; + /** Total cycle latency of overall MSHR misses. */ + Stats::Formula overallMshrMissLatency; + + /** Total cycle latency of each MSHR miss, per command and thread. */ + Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS]; + /** Total cycle latency of overall MSHR misses. */ + Stats::Formula overallMshrUncacheableLatency; + + /** The total number of MSHR accesses per command and thread. */ + Stats::Formula mshrAccesses[MemCmd::NUM_MEM_CMDS]; + /** The total number of demand MSHR accesses. */ + Stats::Formula demandMshrAccesses; + /** The total number of MSHR accesses. */ + Stats::Formula overallMshrAccesses; + + /** The miss rate in the MSHRs pre command and thread. */ + Stats::Formula mshrMissRate[MemCmd::NUM_MEM_CMDS]; + /** The demand miss rate in the MSHRs. */ + Stats::Formula demandMshrMissRate; + /** The overall miss rate in the MSHRs. */ + Stats::Formula overallMshrMissRate; + + /** The average latency of an MSHR miss, per command and thread. */ + Stats::Formula avgMshrMissLatency[MemCmd::NUM_MEM_CMDS]; + /** The average latency of a demand MSHR miss. */ + Stats::Formula demandAvgMshrMissLatency; + /** The average overall latency of an MSHR miss. */ + Stats::Formula overallAvgMshrMissLatency; + + /** The average latency of an MSHR miss, per command and thread. */ + Stats::Formula avgMshrUncacheableLatency[MemCmd::NUM_MEM_CMDS]; + /** The average overall latency of an MSHR miss. */ + Stats::Formula overallAvgMshrUncacheableLatency; + + /** The number of times a thread hit its MSHR cap. */ + Stats::Vector<> mshr_cap_events; + /** The number of times software prefetches caused the MSHR to block. */ + Stats::Vector<> soft_prefetch_mshr_full; + + Stats::Scalar<> mshr_no_allocate_misses; + /** * @} */ @@ -279,12 +354,13 @@ class BaseCache : public MemObject class Params { public: - /** List of address ranges of this cache. */ - std::vector<Range<Addr> > addrRange; /** The hit latency for this cache. */ int hitLatency; /** The block size of this cache. */ int blkSize; + int numMSHRs; + int numTargets; + int numWriteBuffers; /** * The maximum number of misses this cache should handle before * ending the simulation. @@ -294,10 +370,12 @@ class BaseCache : public MemObject /** * Construct an instance of this parameter class. */ - Params(std::vector<Range<Addr> > addr_range, - int hit_latency, int _blkSize, Counter max_misses) - : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize), - maxMisses(max_misses) + Params(int _hitLatency, int _blkSize, + int _numMSHRs, int _numTargets, int _numWriteBuffers, + Counter _maxMisses) + : hitLatency(_hitLatency), blkSize(_blkSize), + numMSHRs(_numMSHRs), numTargets(_numTargets), + numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses) { } }; @@ -309,20 +387,10 @@ class BaseCache : public MemObject * of this cache. * @param params The parameter object for this BaseCache. */ - BaseCache(const std::string &name, Params ¶ms) - : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0), - slaveRequests(0), blkSize(params.blkSize), - missCount(params.maxMisses), drainEvent(NULL) - { - //Start ports at null if more than one is created we should panic - cpuSidePort = NULL; - memSidePort = NULL; - } + BaseCache(const std::string &name, Params ¶ms); ~BaseCache() { - delete sendEvent; - delete memSendEvent; } virtual void init(); @@ -336,20 +404,41 @@ class BaseCache : public MemObject return blkSize; } - /** - * Returns true if the cache is blocked for accesses. - */ - bool isBlocked() + + Addr blockAlign(Addr addr) const { return (addr & ~(blkSize - 1)); } + + + MSHR *allocateMissBuffer(PacketPtr pkt, Tick time, bool requestBus) { - return blocked != 0; + assert(!pkt->req->isUncacheable()); + return allocateBufferInternal(&mshrQueue, + blockAlign(pkt->getAddr()), blkSize, + pkt, time, requestBus); + } + + MSHR *allocateWriteBuffer(PacketPtr pkt, Tick time, bool requestBus) + { + assert(pkt->isWrite() && !pkt->isRead()); + return allocateBufferInternal(&writeBuffer, + pkt->getAddr(), pkt->getSize(), + pkt, time, requestBus); + } + + MSHR *allocateUncachedReadBuffer(PacketPtr pkt, Tick time, bool requestBus) + { + assert(pkt->req->isUncacheable()); + assert(pkt->isRead()); + return allocateBufferInternal(&mshrQueue, + pkt->getAddr(), pkt->getSize(), + pkt, time, requestBus); } /** - * Returns true if the cache is blocked for snoops. + * Returns true if the cache is blocked for accesses. */ - bool isBlockedForSnoop() + bool isBlocked() { - return blockedSnoop != 0; + return blocked != 0; } /** @@ -363,32 +452,10 @@ class BaseCache : public MemObject if (blocked == 0) { blocked_causes[cause]++; blockedCycle = curTick; + cpuSidePort->setBlocked(); } - int old_state = blocked; - if (!(blocked & flag)) { - //Wasn't already blocked for this cause - blocked |= flag; - DPRINTF(Cache,"Blocking for cause %s\n", cause); - if (!old_state) - cpuSidePort->setBlocked(); - } - } - - /** - * Marks the snoop path of the cache as blocked for the given cause. This - * also sets the blocked flag in the master interface. - * @param cause The reason to block the snoop path. - */ - void setBlockedForSnoop(BlockedCause cause) - { - uint8_t flag = 1 << cause; - uint8_t old_state = blockedSnoop; - if (!(blockedSnoop & flag)) { - //Wasn't already blocked for this cause - blockedSnoop |= flag; - if (!old_state) - memSidePort->setBlocked(); - } + blocked |= flag; + DPRINTF(Cache,"Blocking for cause %d, mask=%d\n", cause, blocked); } /** @@ -401,33 +468,18 @@ class BaseCache : public MemObject void clearBlocked(BlockedCause cause) { uint8_t flag = 1 << cause; - DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n", - cause, blocked); - if (blocked & flag) - { - blocked &= ~flag; - if (!isBlocked()) { - blocked_cycles[cause] += curTick - blockedCycle; - DPRINTF(Cache,"Unblocking from all causes\n"); - cpuSidePort->clearBlocked(); - } - } - if (blockedSnoop & flag) - { - blockedSnoop &= ~flag; - if (!isBlockedForSnoop()) { - memSidePort->clearBlocked(); - } + blocked &= ~flag; + DPRINTF(Cache,"Unblocking for cause %d, mask=%d\n", cause, blocked); + if (blocked == 0) { + blocked_cycles[cause] += curTick - blockedCycle; + cpuSidePort->clearBlocked(); } } - /** - * True if the master bus should be requested. - * @return True if there are outstanding requests for the master bus. - */ - bool doMasterRequest() + Tick nextMSHRReadyTime() { - return masterRequests != 0; + return std::min(mshrQueue.nextMSHRReadyTime(), + writeBuffer.nextMSHRReadyTime()); } /** @@ -435,269 +487,40 @@ class BaseCache : public MemObject * @param cause The reason for the request. * @param time The time to make the request. */ - void setMasterRequest(RequestCause cause, Tick time) + void requestMemSideBus(RequestCause cause, Tick time) { - if (!doMasterRequest() && !memSidePort->waitingOnRetry) - { - new RequestEvent(memSidePort, time); - } - uint8_t flag = 1<<cause; - masterRequests |= flag; + memSidePort->requestBus(cause, time); } /** * Clear the master bus request for the given cause. * @param cause The request reason to clear. */ - void clearMasterRequest(RequestCause cause) + void deassertMemSideBusRequest(RequestCause cause) { - uint8_t flag = 1<<cause; - masterRequests &= ~flag; - checkDrain(); + // obsolete!! + assert(false); + // memSidePort->deassertBusRequest(cause); + // checkDrain(); } - /** - * Return true if the slave bus should be requested. - * @return True if there are outstanding requests for the slave bus. - */ - bool doSlaveRequest() - { - return slaveRequests != 0; - } - - /** - * Request the slave bus for the given reason and time. - * @param cause The reason for the request. - * @param time The time to make the request. - */ - void setSlaveRequest(RequestCause cause, Tick time) - { - if (!doSlaveRequest() && !cpuSidePort->waitingOnRetry) - { - new RequestEvent(cpuSidePort, time); - } - uint8_t flag = 1<<cause; - slaveRequests |= flag; - } - - /** - * Clear the slave bus request for the given reason. - * @param cause The request reason to clear. - */ - void clearSlaveRequest(RequestCause cause) - { - uint8_t flag = 1<<cause; - slaveRequests &= ~flag; - checkDrain(); - } - - /** - * Send a response to the slave interface. - * @param pkt The request being responded to. - * @param time The time the response is ready. - */ - void respond(PacketPtr pkt, Tick time) - { - assert(time >= curTick); - if (pkt->needsResponse()) { -/* CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt); - reqCpu->schedule(time); -*/ - if (cpuSidePort->transmitList.empty()) { - assert(!sendEvent->scheduled()); - sendEvent->schedule(time); - cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr> - (time,pkt)); - return; - } - - // something is on the list and this belongs at the end - if (time >= cpuSidePort->transmitList.back().first) { - cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr> - (time,pkt)); - return; - } - // Something is on the list and this belongs somewhere else - std::list<std::pair<Tick,PacketPtr> >::iterator i = - cpuSidePort->transmitList.begin(); - std::list<std::pair<Tick,PacketPtr> >::iterator end = - cpuSidePort->transmitList.end(); - bool done = false; - - while (i != end && !done) { - if (time < i->first) { - if (i == cpuSidePort->transmitList.begin()) { - //Inserting at begining, reschedule - sendEvent->reschedule(time); - } - cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr> - (time,pkt)); - done = true; - } - i++; - } - } - else { - if (pkt->cmd != MemCmd::UpgradeReq) - { - delete pkt->req; - delete pkt; - } - } - } - - /** - * Send a reponse to the slave interface and calculate miss latency. - * @param pkt The request to respond to. - * @param time The time the response is ready. - */ - void respondToMiss(PacketPtr pkt, Tick time) - { - assert(time >= curTick); - if (!pkt->req->isUncacheable()) { - missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] += - time - pkt->time; - } - if (pkt->needsResponse()) { -/* CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt); - reqCpu->schedule(time); -*/ - if (cpuSidePort->transmitList.empty()) { - assert(!sendEvent->scheduled()); - sendEvent->schedule(time); - cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr> - (time,pkt)); - return; - } - - // something is on the list and this belongs at the end - if (time >= cpuSidePort->transmitList.back().first) { - cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr> - (time,pkt)); - return; - } - // Something is on the list and this belongs somewhere else - std::list<std::pair<Tick,PacketPtr> >::iterator i = - cpuSidePort->transmitList.begin(); - std::list<std::pair<Tick,PacketPtr> >::iterator end = - cpuSidePort->transmitList.end(); - bool done = false; - - while (i != end && !done) { - if (time < i->first) { - if (i == cpuSidePort->transmitList.begin()) { - //Inserting at begining, reschedule - sendEvent->reschedule(time); - } - cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr> - (time,pkt)); - done = true; - } - i++; - } - } - else { - if (pkt->cmd != MemCmd::UpgradeReq) - { - delete pkt->req; - delete pkt; - } - } - } - - /** - * Suppliess the data if cache to cache transfers are enabled. - * @param pkt The bus transaction to fulfill. - */ - void respondToSnoop(PacketPtr pkt, Tick time) - { - assert(time >= curTick); - assert (pkt->needsResponse()); -/* CacheEvent *reqMem = new CacheEvent(memSidePort, pkt); - reqMem->schedule(time); -*/ - if (memSidePort->transmitList.empty()) { - assert(!memSendEvent->scheduled()); - memSendEvent->schedule(time); - memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr> - (time,pkt)); - return; - } - - // something is on the list and this belongs at the end - if (time >= memSidePort->transmitList.back().first) { - memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr> - (time,pkt)); - return; - } - // Something is on the list and this belongs somewhere else - std::list<std::pair<Tick,PacketPtr> >::iterator i = - memSidePort->transmitList.begin(); - std::list<std::pair<Tick,PacketPtr> >::iterator end = - memSidePort->transmitList.end(); - bool done = false; - - while (i != end && !done) { - if (time < i->first) { - if (i == memSidePort->transmitList.begin()) { - //Inserting at begining, reschedule - memSendEvent->reschedule(time); - } - memSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt)); - done = true; - } - i++; - } - } - - /** - * Notification from master interface that a address range changed. Nothing - * to do for a cache. - */ - void rangeChange() {} + virtual unsigned int drain(Event *de); - void getAddressRanges(AddrRangeList &resp, bool &snoop, bool isCpuSide) - { - if (isCpuSide) - { - bool dummy; - memSidePort->getPeerAddressRanges(resp, dummy); - } - else - { - //This is where snoops get updated - AddrRangeList dummy; - snoop = true; - } - } + virtual bool inCache(Addr addr) = 0; - virtual unsigned int drain(Event *de); + virtual bool inMissQueue(Addr addr) = 0; - void checkDrain() + void incMissCount(PacketPtr pkt) { - if (drainEvent && canDrain()) { - drainEvent->process(); - changeState(SimObject::Drained); - // Clear the drain event - drainEvent = NULL; - } - } + misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; - bool canDrain() - { - if (doMasterRequest() || doSlaveRequest()) { - return false; - } else if (memSidePort && !memSidePort->canDrain()) { - return false; - } else if (cpuSidePort && !cpuSidePort->canDrain()) { - return false; + if (missCount) { + --missCount; + if (missCount == 0) + exitSimLoop("A cache reached the maximum miss count"); } - return true; } - virtual bool inCache(Addr addr) = 0; - - virtual bool inMissQueue(Addr addr) = 0; }; #endif //__BASE_CACHE_HH__ |