From 8590243fef2e4ccaefde3af767496dec44c6eb33 Mon Sep 17 00:00:00 2001 From: Javier Bueno Date: Fri, 9 Nov 2018 16:02:04 +0100 Subject: mem-cache: implement a probe-based interface The HW Prefetcher of a cache can now listen events from their associated CPUs and from its own cache. Change-Id: I28aecd8faf8ed44be94464d84485bd1cea2efae3 Reviewed-on: https://gem5-review.googlesource.com/c/14155 Reviewed-by: Daniel Carvalho Reviewed-by: Nikos Nikoleris Maintainer: Nikos Nikoleris --- src/mem/cache/base.cc | 61 +++++++++++++++--------------------- src/mem/cache/base.hh | 22 ++++++++++--- src/mem/cache/prefetch/Prefetcher.py | 36 +++++++++++++++++++++ src/mem/cache/prefetch/base.cc | 47 +++++++++++++++++++++++++-- src/mem/cache/prefetch/base.hh | 38 ++++++++++++++++++++-- src/mem/cache/prefetch/queued.cc | 4 +-- src/mem/cache/prefetch/queued.hh | 2 +- 7 files changed, 162 insertions(+), 48 deletions(-) diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index ec0383dea..4ca8152e9 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -83,7 +83,6 @@ BaseCache::BaseCache(const BaseCacheParams *p, unsigned blk_size) writeBuffer("write buffer", p->write_buffers, p->mshrs), // see below tags(p->tags), prefetcher(p->prefetcher), - prefetchOnAccess(p->prefetch_on_access), writeAllocator(p->write_allocator), writebackClean(p->writeback_clean), tempBlockWriteback(nullptr), @@ -368,50 +367,29 @@ BaseCache::recvTimingReq(PacketPtr pkt) Tick request_time = clockEdge(lat) + pkt->headerDelay; // Here we reset the timing of the packet. pkt->headerDelay = pkt->payloadDelay = 0; - // track time of availability of next prefetch, if any - Tick next_pf_time = MaxTick; if (satisfied) { - // if need to notify the prefetcher we have to do it before - // anything else as later handleTimingReqHit might turn the - // packet in a response - if (prefetcher && - (prefetchOnAccess || (blk && blk->wasPrefetched()))) { - if (blk) - blk->status &= ~BlkHWPrefetched; - - // Don't notify on SWPrefetch - if (!pkt->cmd.isSWPrefetch()) { - assert(!pkt->req->isCacheMaintenance()); - next_pf_time = prefetcher->notify(pkt); - } + // notify before anything else as later handleTimingReqHit might turn + // the packet in a response + ppHit->notify(pkt); + + if (prefetcher && blk && blk->wasPrefetched()) { + blk->status &= ~BlkHWPrefetched; } handleTimingReqHit(pkt, blk, request_time); } else { handleTimingReqMiss(pkt, blk, forward_time, request_time); - // We should call the prefetcher reguardless if the request is - // satisfied or not, reguardless if the request is in the MSHR - // or not. The request could be a ReadReq hit, but still not - // satisfied (potentially because of a prior write to the same - // cache line. So, even when not satisfied, there is an MSHR - // already allocated for this, we need to let the prefetcher - // know about the request - - // Don't notify prefetcher on SWPrefetch, cache maintenance - // operations or for writes that we are coaslescing. - if (prefetcher && pkt && - !pkt->cmd.isSWPrefetch() && - !pkt->req->isCacheMaintenance() && - !(writeAllocator && writeAllocator->coalesce() && - pkt->isWrite())) { - next_pf_time = prefetcher->notify(pkt); - } + ppMiss->notify(pkt); } - if (next_pf_time != MaxTick) { - schedMemSideSendEvent(next_pf_time); + if (prefetcher) { + // track time of availability of next prefetch, if any + Tick next_pf_time = prefetcher->nextPrefetchReadyTime(); + if (next_pf_time != MaxTick) { + schedMemSideSendEvent(next_pf_time); + } } } @@ -1407,6 +1385,12 @@ BaseCache::isDirty() const return tags->anyBlk([](CacheBlk &blk) { return blk.isDirty(); }); } +bool +BaseCache::coalesce() const +{ + return writeAllocator && writeAllocator->coalesce(); +} + void BaseCache::writebackVisitor(CacheBlk &blk) { @@ -2210,6 +2194,13 @@ BaseCache::regStats() ; } +void +BaseCache::regProbePoints() +{ + ppHit = new ProbePointArg(this->getProbeManager(), "Hit"); + ppMiss = new ProbePointArg(this->getProbeManager(), "Miss"); +} + /////////////// // // CpuSidePort diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh index 52b0fdbcd..ad5ff3bc4 100644 --- a/src/mem/cache/base.hh +++ b/src/mem/cache/base.hh @@ -75,6 +75,7 @@ #include "mem/request.hh" #include "params/WriteAllocator.hh" #include "sim/eventq.hh" +#include "sim/probe/probe.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" #include "sim/system.hh" @@ -324,10 +325,11 @@ class BaseCache : public MemObject /** Prefetcher */ BasePrefetcher *prefetcher; - /** - * Notify the prefetcher on every access, not just misses. - */ - const bool prefetchOnAccess; + /** To probe when a cache hit occurs */ + ProbePointArg *ppHit; + + /** To probe when a cache miss occurs */ + ProbePointArg *ppMiss; /** * The writeAllocator drive optimizations for streaming writes. @@ -989,6 +991,9 @@ class BaseCache : public MemObject */ void regStats() override; + /** Registers probes. */ + void regProbePoints() override; + public: BaseCache(const BaseCacheParams *p, unsigned blk_size); ~BaseCache(); @@ -1135,6 +1140,14 @@ class BaseCache : public MemObject } + /** + * Checks if the cache is coalescing writes + * + * @return True if the cache is coalescing writes + */ + bool coalesce() const; + + /** * Cache block visitor that writes back dirty cache blocks using * functional writes. @@ -1175,7 +1188,6 @@ class BaseCache : public MemObject */ void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; - }; /** diff --git a/src/mem/cache/prefetch/Prefetcher.py b/src/mem/cache/prefetch/Prefetcher.py index 320755d75..316a6d0ba 100644 --- a/src/mem/cache/prefetch/Prefetcher.py +++ b/src/mem/cache/prefetch/Prefetcher.py @@ -40,13 +40,29 @@ # Mitch Hayenga from ClockedObject import ClockedObject +from m5.SimObject import * from m5.params import * from m5.proxy import * +class HWPProbeEvent(object): + def __init__(self, prefetcher, obj, *listOfNames): + self.obj = obj + self.prefetcher = prefetcher + self.names = listOfNames + + def register(self): + if self.obj: + for name in self.names: + self.prefetcher.getCCObject().addEventProbe( + self.obj.getCCObject(), name) + class BasePrefetcher(ClockedObject): type = 'BasePrefetcher' abstract = True cxx_header = "mem/cache/prefetch/base.hh" + cxx_exports = [ + PyBindMethod("addEventProbe"), + ] sys = Param.System(Parent.any, "System this prefetcher belongs to") on_miss = Param.Bool(False, "Only notify prefetcher on misses") @@ -54,6 +70,26 @@ class BasePrefetcher(ClockedObject): on_write = Param.Bool(True, "Notify prefetcher on writes") on_data = Param.Bool(True, "Notify prefetcher on data accesses") on_inst = Param.Bool(True, "Notify prefetcher on instruction accesses") + prefetch_on_access = Param.Bool(Parent.prefetch_on_access, + "Notify the hardware prefetcher on every access (not just misses)") + + _events = [] + def addEvent(self, newObject): + self._events.append(newObject) + + # Override the normal SimObject::regProbeListeners method and + # register deferred event handlers. + def regProbeListeners(self): + for event in self._events: + event.register() + self.getCCObject().regProbeListeners() + + def listenFromProbe(self, simObj, *probeNames): + if not isinstance(simObj, SimObject): + raise TypeError("argument must be of SimObject type") + if len(probeNames) <= 0: + raise TypeError("probeNames must have at least one element") + self.addEvent(HWPProbeEvent(self, simObj, *probeNames)) class QueuedPrefetcher(BasePrefetcher): type = "QueuedPrefetcher" diff --git a/src/mem/cache/prefetch/base.cc b/src/mem/cache/prefetch/base.cc index 22a12ba5f..41c02ac72 100644 --- a/src/mem/cache/prefetch/base.cc +++ b/src/mem/cache/prefetch/base.cc @@ -51,16 +51,24 @@ #include #include "base/intmath.hh" +#include "cpu/base.hh" #include "mem/cache/base.hh" #include "params/BasePrefetcher.hh" #include "sim/system.hh" +void +BasePrefetcher::PrefetchListener::notify(const PacketPtr &pkt) +{ + parent.probeNotify(pkt); +} + BasePrefetcher::BasePrefetcher(const BasePrefetcherParams *p) - : ClockedObject(p), cache(nullptr), blkSize(0), lBlkSize(0), + : ClockedObject(p), listeners(), cache(nullptr), blkSize(0), lBlkSize(0), system(p->sys), onMiss(p->on_miss), onRead(p->on_read), onWrite(p->on_write), onData(p->on_data), onInst(p->on_inst), masterId(system->getMasterId(this)), - pageBytes(system->getPageBytes()) + pageBytes(system->getPageBytes()), + prefetchOnAccess(p->prefetch_on_access) { } @@ -163,3 +171,38 @@ BasePrefetcher::pageIthBlockAddress(Addr page, uint32_t blockIndex) const { return page + (blockIndex << lBlkSize); } + +void +BasePrefetcher::probeNotify(const PacketPtr &pkt) +{ + // Don't notify prefetcher on SWPrefetch, cache maintenance + // operations or for writes that we are coaslescing. + if (pkt->cmd.isSWPrefetch()) return; + if (pkt->req->isCacheMaintenance()) return; + if (pkt->isWrite() && cache != nullptr && cache->coalesce()) return; + notify(pkt); +} + +void +BasePrefetcher::regProbeListeners() +{ + /** + * If no probes were added by the configuration scripts, connect to the + * parent cache using the probe "Miss". Also connect to "Hit", if the + * cache is configured to prefetch on accesses. + */ + if (listeners.empty() && cache != nullptr) { + ProbeManager *pm(cache->getProbeManager()); + listeners.push_back(new PrefetchListener(*this, pm, "Miss")); + if (prefetchOnAccess) { + listeners.push_back(new PrefetchListener(*this, pm, "Hit")); + } + } +} + +void +BasePrefetcher::addEventProbe(SimObject *obj, const char *name) +{ + ProbeManager *pm(obj->getProbeManager()); + listeners.push_back(new PrefetchListener(*this, pm, name)); +} diff --git a/src/mem/cache/prefetch/base.hh b/src/mem/cache/prefetch/base.hh index cc54ab1b8..394c85c94 100644 --- a/src/mem/cache/prefetch/base.hh +++ b/src/mem/cache/prefetch/base.hh @@ -56,6 +56,7 @@ #include "mem/packet.hh" #include "mem/request.hh" #include "sim/clocked_object.hh" +#include "sim/probe/probe.hh" class BaseCache; struct BasePrefetcherParams; @@ -63,6 +64,19 @@ class System; class BasePrefetcher : public ClockedObject { + class PrefetchListener : public ProbeListenerArgBase + { + public: + PrefetchListener(BasePrefetcher &_parent, ProbeManager *pm, + const std::string &name) + : ProbeListenerArgBase(pm, name), + parent(_parent) {} + void notify(const PacketPtr &pkt) override; + protected: + BasePrefetcher &parent; + }; + + std::vector listeners; protected: // PARAMETERS @@ -99,6 +113,9 @@ class BasePrefetcher : public ClockedObject const Addr pageBytes; + /** Prefetch on every access, not just misses */ + const bool prefetchOnAccess; + /** Determine if this access should be observed */ bool observeAccess(const PacketPtr &pkt) const; @@ -135,14 +152,31 @@ class BasePrefetcher : public ClockedObject /** * Notify prefetcher of cache access (may be any access or just * misses, depending on cache parameters.) - * @retval Time of next prefetch availability, or MaxTick if none. */ - virtual Tick notify(const PacketPtr &pkt) = 0; + virtual void notify(const PacketPtr &pkt) = 0; virtual PacketPtr getPacket() = 0; virtual Tick nextPrefetchReadyTime() const = 0; virtual void regStats(); + + /** + * Register probe points for this object. + */ + void regProbeListeners() override; + + /** + * Process a notification event from the ProbeListener. + * @param pkt The memory request causing the event + */ + void probeNotify(const PacketPtr &pkt); + + /** + * Add a SimObject and a probe name to listen events from + * @param obj The SimObject pointer to listen from + * @param name The probe name + */ + void addEventProbe(SimObject *obj, const char *name); }; #endif //__MEM_CACHE_PREFETCH_BASE_HH__ diff --git a/src/mem/cache/prefetch/queued.cc b/src/mem/cache/prefetch/queued.cc index 3c5647ae3..f9a036d45 100644 --- a/src/mem/cache/prefetch/queued.cc +++ b/src/mem/cache/prefetch/queued.cc @@ -63,7 +63,7 @@ QueuedPrefetcher::~QueuedPrefetcher() } } -Tick +void QueuedPrefetcher::notify(const PacketPtr &pkt) { // Verify this access type is observed by prefetcher @@ -110,8 +110,6 @@ QueuedPrefetcher::notify(const PacketPtr &pkt) } } } - - return pfq.empty() ? MaxTick : pfq.front().tick; } PacketPtr diff --git a/src/mem/cache/prefetch/queued.hh b/src/mem/cache/prefetch/queued.hh index bb38377c1..811818fdc 100644 --- a/src/mem/cache/prefetch/queued.hh +++ b/src/mem/cache/prefetch/queued.hh @@ -115,7 +115,7 @@ class QueuedPrefetcher : public BasePrefetcher QueuedPrefetcher(const QueuedPrefetcherParams *p); virtual ~QueuedPrefetcher(); - Tick notify(const PacketPtr &pkt); + void notify(const PacketPtr &pkt) override; PacketPtr insert(AddrPriority& info, bool is_secure); // Note: This should really be pure virtual, but doesnt go well with params -- cgit v1.2.3