From 38f87dab68c809edf4cd95650c833fe82e4b800b Mon Sep 17 00:00:00 2001 From: Javier Bueno Date: Sun, 18 Nov 2018 00:50:08 +0100 Subject: [PATCH] mem-cache: virtual address support for prefetchers 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 Reviewed-by: Daniel Carvalho Reviewed-by: Nikos Nikoleris --- src/mem/cache/prefetch/Prefetcher.py | 2 + src/mem/cache/prefetch/base.cc | 28 +++++- src/mem/cache/prefetch/base.hh | 96 +++++++++++++++++++- src/mem/cache/prefetch/queued.cc | 131 ++++++++++++++------------- src/mem/cache/prefetch/queued.hh | 30 ++++-- src/mem/cache/prefetch/stride.cc | 28 +++--- src/mem/cache/prefetch/stride.hh | 2 +- src/mem/cache/prefetch/tagged.cc | 4 +- src/mem/cache/prefetch/tagged.hh | 2 +- 9 files changed, 233 insertions(+), 90 deletions(-) diff --git a/src/mem/cache/prefetch/Prefetcher.py b/src/mem/cache/prefetch/Prefetcher.py index bae235d84..df547ed42 100644 --- a/src/mem/cache/prefetch/Prefetcher.py +++ b/src/mem/cache/prefetch/Prefetcher.py @@ -76,6 +76,8 @@ class BasePrefetcher(ClockedObject): 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): diff --git a/src/mem/cache/prefetch/base.cc b/src/mem/cache/prefetch/base.cc index 53260ae0d..e58d4f3d5 100644 --- a/src/mem/cache/prefetch/base.cc +++ b/src/mem/cache/prefetch/base.cc @@ -56,6 +56,19 @@ #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) { @@ -67,7 +80,8 @@ BasePrefetcher::BasePrefetcher(const BasePrefetcherParams *p) 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) { } @@ -175,7 +189,17 @@ BasePrefetcher::probeNotify(const PacketPtr &pkt) 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 diff --git a/src/mem/cache/prefetch/base.hh b/src/mem/cache/prefetch/base.hh index 813d1b9a4..63b0e1bed 100644 --- a/src/mem/cache/prefetch/base.hh +++ b/src/mem/cache/prefetch/base.hh @@ -78,6 +78,96 @@ class BasePrefetcher : public ClockedObject std::vector 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. */ @@ -112,6 +202,9 @@ class BasePrefetcher : public ClockedObject /** 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; @@ -134,7 +227,6 @@ class BasePrefetcher : public ClockedObject /** Build the address of the i-th block inside the page */ Addr pageIthBlockAddress(Addr page, uint32_t i) const; - Stats::Scalar pfIssued; public: @@ -149,7 +241,7 @@ class BasePrefetcher : public ClockedObject * 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; diff --git a/src/mem/cache/prefetch/queued.cc b/src/mem/cache/prefetch/queued.cc index ba4c940c1..f48ea185d 100644 --- a/src/mem/cache/prefetch/queued.cc +++ b/src/mem/cache/prefetch/queued.cc @@ -64,50 +64,43 @@ QueuedPrefetcher::~QueuedPrefetcher() } 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 addresses; - calculatePrefetch(pkt, addresses); + // Calculate prefetches given this access + std::vector 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); } } @@ -121,7 +114,7 @@ QueuedPrefetcher::getPacket() return nullptr; } - PacketPtr pkt = pfq.begin()->pkt; + PacketPtr pkt = pfq.front().pkt; pfq.pop_front(); pfIssued++; @@ -131,22 +124,20 @@ QueuedPrefetcher::getPacket() } 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(); @@ -178,17 +169,18 @@ QueuedPrefetcher::regStats() .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()) { @@ -205,28 +197,47 @@ QueuedPrefetcher::insert(AddrPriority &pf_info, bool is_secure) 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(pf_info.first, blkSize, 0, masterId); + std::make_shared(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) { @@ -243,13 +254,13 @@ QueuedPrefetcher::insert(AddrPriority &pf_info, bool is_secure) 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); } @@ -257,10 +268,10 @@ QueuedPrefetcher::insert(AddrPriority &pf_info, bool is_secure) 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 { @@ -274,6 +285,4 @@ QueuedPrefetcher::insert(AddrPriority &pf_info, bool is_secure) it++; pfq.insert(it, dpp); } - - return pf_pkt; } diff --git a/src/mem/cache/prefetch/queued.hh b/src/mem/cache/prefetch/queued.hh index 774e6ede8..1c63977b4 100644 --- a/src/mem/cache/prefetch/queued.hh +++ b/src/mem/cache/prefetch/queued.hh @@ -55,11 +55,27 @@ class QueuedPrefetcher : public BasePrefetcher { 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; @@ -98,9 +114,9 @@ class QueuedPrefetcher : public BasePrefetcher const bool tagPrefetch; using const_iterator = std::list::const_iterator; - const_iterator inPrefetch(Addr address, bool is_secure) const; + const_iterator inPrefetch(const PrefetchInfo &pfi) const; using iterator = std::list::iterator; - iterator inPrefetch(Addr address, bool is_secure); + iterator inPrefetch(const PrefetchInfo &pfi); // STATS Stats::Scalar pfIdentified; @@ -113,11 +129,11 @@ class QueuedPrefetcher : public BasePrefetcher 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 &addresses) = 0; PacketPtr getPacket() override; diff --git a/src/mem/cache/prefetch/stride.cc b/src/mem/cache/prefetch/stride.cc index 44849cd57..5d009014e 100644 --- a/src/mem/cache/prefetch/stride.cc +++ b/src/mem/cache/prefetch/stride.cc @@ -138,19 +138,19 @@ StridePrefetcher::PCTable::~PCTable() } void -StridePrefetcher::calculatePrefetch(const PacketPtr &pkt, +StridePrefetcher::calculatePrefetch(const PrefetchInfo &pfi, std::vector &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); @@ -160,7 +160,7 @@ StridePrefetcher::calculatePrefetch(const PacketPtr &pkt, 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 @@ -176,11 +176,11 @@ StridePrefetcher::calculatePrefetch(const PacketPtr &pkt, } 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) @@ -194,8 +194,8 @@ StridePrefetcher::calculatePrefetch(const PacketPtr &pkt, 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 { @@ -207,7 +207,7 @@ StridePrefetcher::calculatePrefetch(const PacketPtr &pkt, } } 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); @@ -218,7 +218,7 @@ StridePrefetcher::calculatePrefetch(const PacketPtr &pkt, // 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); diff --git a/src/mem/cache/prefetch/stride.hh b/src/mem/cache/prefetch/stride.hh index aa0228705..0ae277d0e 100644 --- a/src/mem/cache/prefetch/stride.hh +++ b/src/mem/cache/prefetch/stride.hh @@ -172,7 +172,7 @@ class StridePrefetcher : public QueuedPrefetcher public: StridePrefetcher(const StridePrefetcherParams *p); - void calculatePrefetch(const PacketPtr &pkt, + void calculatePrefetch(const PrefetchInfo &pfi, std::vector &addresses) override; }; diff --git a/src/mem/cache/prefetch/tagged.cc b/src/mem/cache/prefetch/tagged.cc index 7561633da..a360cc639 100644 --- a/src/mem/cache/prefetch/tagged.cc +++ b/src/mem/cache/prefetch/tagged.cc @@ -44,10 +44,10 @@ TaggedPrefetcher::TaggedPrefetcher(const TaggedPrefetcherParams *p) } void -TaggedPrefetcher::calculatePrefetch(const PacketPtr &pkt, +TaggedPrefetcher::calculatePrefetch(const PrefetchInfo &pfi, std::vector &addresses) { - Addr blkAddr = pkt->getBlockAddr(blkSize); + Addr blkAddr = blockAddress(pfi.getAddr()); for (int d = 1; d <= degree; d++) { Addr newAddr = blkAddr + d*(blkSize); diff --git a/src/mem/cache/prefetch/tagged.hh b/src/mem/cache/prefetch/tagged.hh index 8dd8b77b4..ff551972b 100644 --- a/src/mem/cache/prefetch/tagged.hh +++ b/src/mem/cache/prefetch/tagged.hh @@ -51,7 +51,7 @@ class TaggedPrefetcher : public QueuedPrefetcher ~TaggedPrefetcher() {} - void calculatePrefetch(const PacketPtr &pkt, + void calculatePrefetch(const PrefetchInfo &pfi, std::vector &addresses) override; }; -- 2.30.2