Prefetchers can be configured to operate with virtual or physical addreses.
The option can be configured through the "use_virtual_addresses" parameter
of the Prefetcher object.
Change-Id: I4f8c3687988afecc8a91c3c5b2d44cc0580f72aa
Reviewed-on: https://gem5-review.googlesource.com/c/14416
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
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)")
+ use_virtual_addresses = Param.Bool(False,
+ "Use virtual addresses for prefetching")
_events = []
def addEvent(self, newObject):
#include "params/BasePrefetcher.hh"
#include "sim/system.hh"
+BasePrefetcher::PrefetchInfo::PrefetchInfo(PacketPtr pkt, Addr addr)
+ : address(addr), pc(pkt->req->hasPC() ? pkt->req->getPC() : 0),
+ masterId(pkt->req->masterId()), validPC(pkt->req->hasPC()),
+ secure(pkt->isSecure())
+{
+}
+
+BasePrefetcher::PrefetchInfo::PrefetchInfo(PrefetchInfo const &pfi, Addr addr)
+ : address(addr), pc(pfi.pc), masterId(pfi.masterId), validPC(pfi.validPC),
+ secure(pfi.secure)
+{
+}
+
void
BasePrefetcher::PrefetchListener::notify(const PacketPtr &pkt)
{
lBlkSize(floorLog2(blkSize)), onMiss(p->on_miss), onRead(p->on_read),
onWrite(p->on_write), onData(p->on_data), onInst(p->on_inst),
masterId(p->sys->getMasterId(this)), pageBytes(p->sys->getPageBytes()),
- prefetchOnAccess(p->prefetch_on_access)
+ prefetchOnAccess(p->prefetch_on_access),
+ useVirtualAddresses(p->use_virtual_addresses)
{
}
if (pkt->cmd.isSWPrefetch()) return;
if (pkt->req->isCacheMaintenance()) return;
if (pkt->isWrite() && cache != nullptr && cache->coalesce()) return;
- notify(pkt);
+
+ // Verify this access type is observed by prefetcher
+ if (observeAccess(pkt)) {
+ if (useVirtualAddresses && pkt->req->hasVaddr()) {
+ PrefetchInfo pfi(pkt, pkt->req->getVaddr());
+ notify(pkt, pfi);
+ } else if (!useVirtualAddresses && pkt->req->hasPaddr()) {
+ PrefetchInfo pfi(pkt, pkt->req->getPaddr());
+ notify(pkt, pfi);
+ }
+ }
}
void
std::vector<PrefetchListener *> listeners;
protected:
+ /**
+ * Class containing the information needed by the prefetch to train and
+ * generate new prefetch requests.
+ */
+ class PrefetchInfo {
+ /** The address. */
+ Addr address;
+ /** The program counter that generated this address. */
+ Addr pc;
+ /** The requestor ID that generated this address. */
+ MasterID masterId;
+ /** Validity bit for the PC of this address. */
+ bool validPC;
+ /** Whether this address targets the secure memory space. */
+ bool secure;
+
+ public:
+ /**
+ * Obtains the address value of this Prefetcher address.
+ * @return the addres value.
+ */
+ Addr getAddr() const
+ {
+ return address;
+ }
+
+ /**
+ * Returns true if the address targets the secure memory space.
+ * @return true if the address targets the secure memory space.
+ */
+ bool isSecure() const
+ {
+ return secure;
+ }
+
+ /**
+ * Returns the program counter that generated this request.
+ * @return the pc value
+ */
+ Addr getPC() const
+ {
+ assert(hasPC());
+ return pc;
+ }
+
+ /**
+ * Returns true if the associated program counter is valid
+ * @return true if the program counter has a valid value
+ */
+ bool hasPC() const
+ {
+ return validPC;
+ }
+
+ /**
+ * Gets the requestor ID that generated this address
+ * @return the requestor ID that generated this address
+ */
+ MasterID getMasterId() const
+ {
+ return masterId;
+ }
+
+ /**
+ * Check for equality
+ * @param pfi PrefetchInfo to compare against
+ * @return True if this object and the provided one are equal
+ */
+ bool sameAddr(PrefetchInfo const &pfi) const
+ {
+ return this->getAddr() == pfi.getAddr() &&
+ this->isSecure() == pfi.isSecure();
+ }
+
+ /**
+ * Constructs a PrefetchInfo using a PacketPtr.
+ * @param pkt PacketPtr used to generate the PrefetchInfo
+ * @param addr the address value of the new object
+ */
+ PrefetchInfo(PacketPtr pkt, Addr addr);
+
+ /**
+ * Constructs a PrefetchInfo using a new address value and
+ * another PrefetchInfo as a reference.
+ * @param pfi PrefetchInfo used to generate this new object
+ * @param addr the address value of the new object
+ */
+ PrefetchInfo(PrefetchInfo const &pfi, Addr addr);
+ };
+
// PARAMETERS
/** Pointr to the parent cache. */
/** Prefetch on every access, not just misses */
const bool prefetchOnAccess;
+ /** Use Virtual Addresses for prefetching */
+ const bool useVirtualAddresses;
+
/** Determine if this access should be observed */
bool observeAccess(const PacketPtr &pkt) const;
/** Build the address of the i-th block inside the page */
Addr pageIthBlockAddress(Addr page, uint32_t i) const;
-
Stats::Scalar pfIssued;
public:
* Notify prefetcher of cache access (may be any access or just
* misses, depending on cache parameters.)
*/
- virtual void notify(const PacketPtr &pkt) = 0;
+ virtual void notify(const PacketPtr &pkt, const PrefetchInfo &pfi) = 0;
virtual PacketPtr getPacket() = 0;
}
void
-QueuedPrefetcher::notify(const PacketPtr &pkt)
+QueuedPrefetcher::notify(const PacketPtr &pkt, const PrefetchInfo &pfi)
{
- // Verify this access type is observed by prefetcher
- if (observeAccess(pkt)) {
- Addr blk_addr = pkt->getBlockAddr(blkSize);
- bool is_secure = pkt->isSecure();
-
- // Squash queued prefetches if demand miss to same line
- if (queueSquash) {
- auto itr = pfq.begin();
- while (itr != pfq.end()) {
- if (itr->pkt->getAddr() == blk_addr &&
- itr->pkt->isSecure() == is_secure) {
- delete itr->pkt;
- itr = pfq.erase(itr);
- } else {
- ++itr;
- }
+ Addr blk_addr = blockAddress(pfi.getAddr());
+ bool is_secure = pfi.isSecure();
+
+ // Squash queued prefetches if demand miss to same line
+ if (queueSquash) {
+ auto itr = pfq.begin();
+ while (itr != pfq.end()) {
+ if (itr->pfInfo.getAddr() == blk_addr &&
+ itr->pfInfo.isSecure() == is_secure) {
+ delete itr->pkt;
+ itr = pfq.erase(itr);
+ } else {
+ ++itr;
}
}
+ }
- // Calculate prefetches given this access
- std::vector<AddrPriority> addresses;
- calculatePrefetch(pkt, addresses);
+ // Calculate prefetches given this access
+ std::vector<AddrPriority> addresses;
+ calculatePrefetch(pfi, addresses);
- // Queue up generated prefetches
- for (AddrPriority& pf_info : addresses) {
- // Block align prefetch address
- pf_info.first = blockAddress(pf_info.first);
+ // Queue up generated prefetches
+ for (AddrPriority& addr_prio : addresses) {
- pfIdentified++;
- DPRINTF(HWPrefetch, "Found a pf candidate addr: %#x, "
- "inserting into prefetch queue.\n", pf_info.first);
+ // Block align prefetch address
+ addr_prio.first = blockAddress(addr_prio.first);
- // Create and insert the request
- PacketPtr pf_pkt = insert(pf_info, is_secure);
+ PrefetchInfo new_pfi(pfi,addr_prio.first);
- if (pf_pkt != nullptr) {
- if (tagPrefetch && pkt->req->hasPC()) {
- // Tag prefetch packet with accessing pc
- pf_pkt->req->setPC(pkt->req->getPC());
- }
- }
- }
+ pfIdentified++;
+ DPRINTF(HWPrefetch, "Found a pf candidate addr: %#x, "
+ "inserting into prefetch queue.\n", new_pfi.getAddr());
+
+ // Create and insert the request
+ insert(pkt, new_pfi, addr_prio.second);
}
}
return nullptr;
}
- PacketPtr pkt = pfq.begin()->pkt;
+ PacketPtr pkt = pfq.front().pkt;
pfq.pop_front();
pfIssued++;
}
QueuedPrefetcher::const_iterator
-QueuedPrefetcher::inPrefetch(Addr address, bool is_secure) const
+QueuedPrefetcher::inPrefetch(const PrefetchInfo &pfi) const
{
for (const_iterator dp = pfq.begin(); dp != pfq.end(); dp++) {
- if ((*dp).pkt->getAddr() == address &&
- (*dp).pkt->isSecure() == is_secure) return dp;
+ if (dp->pfInfo.sameAddr(pfi)) return dp;
}
return pfq.end();
}
QueuedPrefetcher::iterator
-QueuedPrefetcher::inPrefetch(Addr address, bool is_secure)
+QueuedPrefetcher::inPrefetch(const PrefetchInfo &pfi)
{
for (iterator dp = pfq.begin(); dp != pfq.end(); dp++) {
- if (dp->pkt->getAddr() == address &&
- dp->pkt->isSecure() == is_secure) return dp;
+ if (dp->pfInfo.sameAddr(pfi)) return dp;
}
return pfq.end();
.desc("number of prefetches not generated due to page crossing");
}
-PacketPtr
-QueuedPrefetcher::insert(AddrPriority &pf_info, bool is_secure)
+void
+QueuedPrefetcher::insert(const PacketPtr &pkt, PrefetchInfo &new_pfi,
+ int32_t priority)
{
if (queueFilter) {
- iterator it = inPrefetch(pf_info.first, is_secure);
+ iterator it = inPrefetch(new_pfi);
/* If the address is already in the queue, update priority and leave */
if (it != pfq.end()) {
pfBufferHit++;
- if (it->priority < pf_info.second) {
+ if (it->priority < priority) {
/* Update priority value and position in the queue */
- it->priority = pf_info.second;
+ it->priority = priority;
iterator prev = it;
bool cont = true;
while (cont && prev != pfq.begin()) {
DPRINTF(HWPrefetch, "Prefetch addr already in "
"prefetch queue\n");
}
- return nullptr;
+ return;
+ }
+ }
+
+ Addr target_addr = new_pfi.getAddr();
+ if (useVirtualAddresses) {
+ assert(pkt->req->hasPaddr());
+ //if we trained with virtual addresses, compute the phsysical address
+ if (new_pfi.getAddr() >= pkt->req->getVaddr()) {
+ //positive stride
+ target_addr = pkt->req->getPaddr() +
+ (new_pfi.getAddr() - pkt->req->getVaddr());
+ } else {
+ //negative stride
+ target_addr = pkt->req->getPaddr() -
+ (pkt->req->getVaddr() - new_pfi.getAddr());
}
}
- if (cacheSnoop && (inCache(pf_info.first, is_secure) ||
- inMissQueue(pf_info.first, is_secure))) {
+ if (cacheSnoop && (inCache(target_addr, new_pfi.isSecure()) ||
+ inMissQueue(target_addr, new_pfi.isSecure()))) {
pfInCache++;
DPRINTF(HWPrefetch, "Dropping redundant in "
- "cache/MSHR prefetch addr:%#x\n", pf_info.first);
- return nullptr;
+ "cache/MSHR prefetch addr:%#x\n", target_addr);
+ return;
}
/* Create a prefetch memory request */
RequestPtr pf_req =
- std::make_shared<Request>(pf_info.first, blkSize, 0, masterId);
+ std::make_shared<Request>(target_addr, blkSize, 0, masterId);
- if (is_secure) {
+ if (new_pfi.isSecure()) {
pf_req->setFlags(Request::SECURE);
}
pf_req->taskId(ContextSwitchTaskId::Prefetcher);
PacketPtr pf_pkt = new Packet(pf_req, MemCmd::HardPFReq);
pf_pkt->allocate();
+ if (tagPrefetch && new_pfi.hasPC()) {
+ // Tag prefetch packet with accessing pc
+ pf_pkt->req->setPC(new_pfi.getPC());
+ }
/* Verify prefetch buffer space for request */
if (pfq.size() == queueSize) {
while (cont && prev != pfq.begin()) {
prev--;
/* While at the same level of priority */
- cont = (*prev).priority == (*it).priority;
+ cont = prev->priority == it->priority;
if (cont)
/* update pointer */
it = prev;
}
DPRINTF(HWPrefetch, "Prefetch queue full, removing lowest priority "
- "oldest packet, addr: %#x", it->pkt->getAddr());
+ "oldest packet, addr: %#x", it->pfInfo.getAddr());
delete it->pkt;
pfq.erase(it);
}
Tick pf_time = curTick() + clockPeriod() * latency;
DPRINTF(HWPrefetch, "Prefetch queued. "
"addr:%#x priority: %3d tick:%lld.\n",
- pf_info.first, pf_info.second, pf_time);
+ target_addr, priority, pf_time);
/* Create the packet and find the spot to insert it */
- DeferredPacket dpp(pf_time, pf_pkt, pf_info.second);
+ DeferredPacket dpp(new_pfi, pf_time, pf_pkt, priority);
if (pfq.size() == 0) {
pfq.emplace_back(dpp);
} else {
it++;
pfq.insert(it, dpp);
}
-
- return pf_pkt;
}
{
protected:
struct DeferredPacket {
+ /** Prefetch info corresponding to this packet */
+ PrefetchInfo pfInfo;
+ /** Time when this prefetch becomes ready */
Tick tick;
+ /** The memory packet generated by this prefetch */
PacketPtr pkt;
+ /** The priority of this prefetch */
int32_t priority;
- DeferredPacket(Tick t, PacketPtr p, int32_t pr) : tick(t), pkt(p),
- priority(pr) {}
+
+ /**
+ * Constructor
+ * @param pfi PrefechInfo object associated to this packet
+ * @param t Time when this prefetch becomes ready
+ * @param p PacketPtr with the memory request of the prefetch
+ * @param prio This prefetch priority
+ */
+ DeferredPacket(PrefetchInfo const &pfi, Tick t, PacketPtr p,
+ int32_t prio) : pfInfo(pfi), tick(t), pkt(p),
+ priority(prio) {
+ }
+
bool operator>(const DeferredPacket& that) const
{
return priority > that.priority;
const bool tagPrefetch;
using const_iterator = std::list<DeferredPacket>::const_iterator;
- const_iterator inPrefetch(Addr address, bool is_secure) const;
+ const_iterator inPrefetch(const PrefetchInfo &pfi) const;
using iterator = std::list<DeferredPacket>::iterator;
- iterator inPrefetch(Addr address, bool is_secure);
+ iterator inPrefetch(const PrefetchInfo &pfi);
// STATS
Stats::Scalar pfIdentified;
QueuedPrefetcher(const QueuedPrefetcherParams *p);
virtual ~QueuedPrefetcher();
- void notify(const PacketPtr &pkt) override;
+ void notify(const PacketPtr &pkt, const PrefetchInfo &pfi) override;
- PacketPtr insert(AddrPriority& info, bool is_secure);
+ void insert(const PacketPtr &pkt, PrefetchInfo &new_pfi, int32_t priority);
- virtual void calculatePrefetch(const PacketPtr &pkt,
+ virtual void calculatePrefetch(const PrefetchInfo &pfi,
std::vector<AddrPriority> &addresses) = 0;
PacketPtr getPacket() override;
}
void
-StridePrefetcher::calculatePrefetch(const PacketPtr &pkt,
+StridePrefetcher::calculatePrefetch(const PrefetchInfo &pfi,
std::vector<AddrPriority> &addresses)
{
- if (!pkt->req->hasPC()) {
+ if (!pfi.hasPC()) {
DPRINTF(HWPrefetch, "Ignoring request with no PC.\n");
return;
}
// Get required packet info
- Addr pkt_addr = pkt->getAddr();
- Addr pc = pkt->req->getPC();
- bool is_secure = pkt->isSecure();
- MasterID master_id = useMasterId ? pkt->req->masterId() : 0;
+ Addr pf_addr = pfi.getAddr();
+ Addr pc = pfi.getPC();
+ bool is_secure = pfi.isSecure();
+ MasterID master_id = useMasterId ? pfi.getMasterId() : 0;
// Get corresponding pc table
PCTable* pcTable = findTable(master_id);
if (entry != nullptr) {
// Hit in table
- int new_stride = pkt_addr - entry->lastAddr;
+ int new_stride = pf_addr - entry->lastAddr;
bool stride_match = (new_stride == entry->stride);
// Adjust confidence for stride entry
}
DPRINTF(HWPrefetch, "Hit: PC %x pkt_addr %x (%s) stride %d (%s), "
- "conf %d\n", pc, pkt_addr, is_secure ? "s" : "ns", new_stride,
- stride_match ? "match" : "change",
+ "conf %d\n", pc, pf_addr, is_secure ? "s" : "ns",
+ new_stride, stride_match ? "match" : "change",
entry->confidence);
- entry->lastAddr = pkt_addr;
+ entry->lastAddr = pf_addr;
// Abort prefetch generation if below confidence threshold
if (entry->confidence < threshConf)
prefetch_stride = (new_stride < 0) ? -blkSize : blkSize;
}
- Addr new_addr = pkt_addr + d * prefetch_stride;
- if (samePage(pkt_addr, new_addr)) {
+ Addr new_addr = pf_addr + d * prefetch_stride;
+ if (samePage(pf_addr, new_addr)) {
DPRINTF(HWPrefetch, "Queuing prefetch to %#x.\n", new_addr);
addresses.push_back(AddrPriority(new_addr, 0));
} else {
}
} else {
// Miss in table
- DPRINTF(HWPrefetch, "Miss: PC %x pkt_addr %x (%s)\n", pc, pkt_addr,
+ DPRINTF(HWPrefetch, "Miss: PC %x pkt_addr %x (%s)\n", pc, pf_addr,
is_secure ? "s" : "ns");
StrideEntry* entry = pcTable->findVictim(pc);
// Insert new entry's data
entry->instAddr = pc;
- entry->lastAddr = pkt_addr;
+ entry->lastAddr = pf_addr;
entry->isSecure = is_secure;
entry->confidence = startConf;
replacementPolicy->reset(entry->replacementData);
public:
StridePrefetcher(const StridePrefetcherParams *p);
- void calculatePrefetch(const PacketPtr &pkt,
+ void calculatePrefetch(const PrefetchInfo &pfi,
std::vector<AddrPriority> &addresses) override;
};
}
void
-TaggedPrefetcher::calculatePrefetch(const PacketPtr &pkt,
+TaggedPrefetcher::calculatePrefetch(const PrefetchInfo &pfi,
std::vector<AddrPriority> &addresses)
{
- Addr blkAddr = pkt->getBlockAddr(blkSize);
+ Addr blkAddr = blockAddress(pfi.getAddr());
for (int d = 1; d <= degree; d++) {
Addr newAddr = blkAddr + d*(blkSize);
~TaggedPrefetcher() {}
- void calculatePrefetch(const PacketPtr &pkt,
+ void calculatePrefetch(const PrefetchInfo &pfi,
std::vector<AddrPriority> &addresses) override;
};