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 <odanrc@yahoo.com.br>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
This commit is contained in:
Javier Bueno
2018-11-09 16:02:04 +01:00
committed by Javier Bueno Hedo
parent e8e92a12af
commit 8590243fef
7 changed files with 161 additions and 47 deletions

59
src/mem/cache/base.cc vendored
View File

@@ -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;
// notify before anything else as later handleTimingReqHit might turn
// the packet in a response
ppHit->notify(pkt);
// Don't notify on SWPrefetch
if (!pkt->cmd.isSWPrefetch()) {
assert(!pkt->req->isCacheMaintenance());
next_pf_time = prefetcher->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<PacketPtr>(this->getProbeManager(), "Hit");
ppMiss = new ProbePointArg<PacketPtr>(this->getProbeManager(), "Miss");
}
///////////////
//
// CpuSidePort

22
src/mem/cache/base.hh vendored
View File

@@ -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<PacketPtr> *ppHit;
/** To probe when a cache miss occurs */
ProbePointArg<PacketPtr> *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;
};
/**

View File

@@ -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"

View File

@@ -51,16 +51,24 @@
#include <cassert>
#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));
}

View File

@@ -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<PacketPtr>
{
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<PrefetchListener *> 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__

View File

@@ -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

View File

@@ -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