X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fcache%2Fprefetch%2Fbase.cc;h=b3a43cc582ecea5744316889241d9381ac3559a2;hb=e0de180ee4eb3316d2dd0d20320f2a1b310101bc;hp=12028ac525f7440b9d8b6cc5250b1b8279cf743b;hpb=eddac53ff60c579eff28134bde84783fe36d6214;p=gem5.git diff --git a/src/mem/cache/prefetch/base.cc b/src/mem/cache/prefetch/base.cc index 12028ac52..b3a43cc58 100644 --- a/src/mem/cache/prefetch/base.cc +++ b/src/mem/cache/prefetch/base.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013-2014 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2005 The Regents of The University of Michigan * All rights reserved. * @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Ron Dreslinski + * Mitch Hayenga */ /** @@ -33,246 +46,218 @@ * Hardware Prefetcher Definition. */ -#include - -#include "arch/isa_traits.hh" -#include "base/trace.hh" -#include "config/the_isa.hh" -#include "debug/HWPrefetch.hh" #include "mem/cache/prefetch/base.hh" + +#include + +#include "base/intmath.hh" +#include "cpu/base.hh" #include "mem/cache/base.hh" -#include "mem/request.hh" +#include "params/BasePrefetcher.hh" +#include "sim/system.hh" + +BasePrefetcher::PrefetchInfo::PrefetchInfo(PacketPtr pkt, Addr addr, bool miss) + : address(addr), pc(pkt->req->hasPC() ? pkt->req->getPC() : 0), + masterId(pkt->req->masterId()), validPC(pkt->req->hasPC()), + secure(pkt->isSecure()), size(pkt->req->getSize()), write(pkt->isWrite()), + paddress(pkt->req->getPaddr()), cacheMiss(miss) +{ + unsigned int req_size = pkt->req->getSize(); + if (!write && miss) { + data = nullptr; + } else { + data = new uint8_t[req_size]; + Addr offset = pkt->req->getPaddr() - pkt->getAddr(); + std::memcpy(data, &(pkt->getConstPtr()[offset]), req_size); + } +} -BasePrefetcher::BasePrefetcher(const BaseCacheParams *p) - : size(p->prefetcher_size), pageStop(!p->prefetch_past_page), - serialSquash(p->prefetch_serial_squash), - onlyData(p->prefetch_data_accesses_only) +BasePrefetcher::PrefetchInfo::PrefetchInfo(PrefetchInfo const &pfi, Addr addr) + : address(addr), pc(pfi.pc), masterId(pfi.masterId), validPC(pfi.validPC), + secure(pfi.secure), size(pfi.size), write(pfi.write), + paddress(pfi.paddress), cacheMiss(pfi.cacheMiss), data(nullptr) +{ +} + +void +BasePrefetcher::PrefetchListener::notify(const PacketPtr &pkt) +{ + if (isFill) { + parent.notifyFill(pkt); + } else { + parent.probeNotify(pkt, miss); + } +} + +BasePrefetcher::BasePrefetcher(const BasePrefetcherParams *p) + : ClockedObject(p), listeners(), cache(nullptr), blkSize(p->block_size), + 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), + useVirtualAddresses(p->use_virtual_addresses), issuedPrefetches(0), + usefulPrefetches(0), tlb(nullptr) { } void BasePrefetcher::setCache(BaseCache *_cache) { + assert(!cache); cache = _cache; + + // If the cache has a different block size from the system's, save it blkSize = cache->getBlockSize(); - _name = cache->name() + "-pf"; + lBlkSize = floorLog2(blkSize); } void -BasePrefetcher::regStats(const std::string &name) +BasePrefetcher::regStats() { - pfIdentified - .name(name + ".prefetcher.num_hwpf_identified") - .desc("number of hwpf identified") - ; - - pfMSHRHit - .name(name + ".prefetcher.num_hwpf_already_in_mshr") - .desc("number of hwpf that were already in mshr") - ; - - pfCacheHit - .name(name + ".prefetcher.num_hwpf_already_in_cache") - .desc("number of hwpf that were already in the cache") - ; - - pfBufferHit - .name(name + ".prefetcher.num_hwpf_already_in_prefetcher") - .desc("number of hwpf that were already in the prefetch queue") - ; - - pfRemovedFull - .name(name + ".prefetcher.num_hwpf_evicted") - .desc("number of hwpf removed due to no buffer left") - ; - - pfRemovedMSHR - .name(name + ".prefetcher.num_hwpf_removed_MSHR_hit") - .desc("number of hwpf removed because MSHR allocated") - ; + ClockedObject::regStats(); pfIssued - .name(name + ".prefetcher.num_hwpf_issued") + .name(name() + ".num_hwpf_issued") .desc("number of hwpf issued") ; - pfSpanPage - .name(name + ".prefetcher.num_hwpf_span_page") - .desc("number of hwpf spanning a virtual page") - ; - - pfSquashed - .name(name + ".prefetcher.num_hwpf_squashed_from_miss") - .desc("number of hwpf that got squashed due to a miss " - "aborting calculation time") - ; } -inline bool -BasePrefetcher::inCache(Addr addr) +bool +BasePrefetcher::observeAccess(const PacketPtr &pkt, bool miss) const { - if (cache->inCache(addr)) { - pfCacheHit++; - return true; + bool fetch = pkt->req->isInstFetch(); + bool read = pkt->isRead(); + bool inv = pkt->isInvalidate(); + + if (pkt->req->isUncacheable()) return false; + if (fetch && !onInst) return false; + if (!fetch && !onData) return false; + if (!fetch && read && !onRead) return false; + if (!fetch && !read && !onWrite) return false; + if (!fetch && !read && inv) return false; + if (pkt->cmd == MemCmd::CleanEvict) return false; + + if (onMiss) { + return miss; } - return false; + + return true; +} + +bool +BasePrefetcher::inCache(Addr addr, bool is_secure) const +{ + return cache->inCache(addr, is_secure); } -inline bool -BasePrefetcher::inMissQueue(Addr addr) +bool +BasePrefetcher::inMissQueue(Addr addr, bool is_secure) const { - if (cache->inMissQueue(addr)) { - pfMSHRHit++; - return true; - } - return false; + return cache->inMissQueue(addr, is_secure); } -PacketPtr -BasePrefetcher::getPacket() +bool +BasePrefetcher::hasBeenPrefetched(Addr addr, bool is_secure) const { - DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n"); + return cache->hasBeenPrefetched(addr, is_secure); +} - if (pf.empty()) { - DPRINTF(HWPrefetch, "No HW_PF found\n"); - return NULL; - } +bool +BasePrefetcher::samePage(Addr a, Addr b) const +{ + return roundDown(a, pageBytes) == roundDown(b, pageBytes); +} - PacketPtr pkt; - bool keep_trying = false; - do { - pkt = *pf.begin(); - pf.pop_front(); - - if (keep_trying) { - DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n", - pkt->getAddr()); - delete pkt->req; - delete pkt; - } +Addr +BasePrefetcher::blockAddress(Addr a) const +{ + return a & ~((Addr)blkSize-1); +} - if (pf.empty()) { - cache->deassertMemSideBusRequest(BaseCache::Request_PF); - if (keep_trying) { - return NULL; // None left, all were in cache - } - } - } while (keep_trying); +Addr +BasePrefetcher::blockIndex(Addr a) const +{ + return a >> lBlkSize; +} - pfIssued++; - assert(pkt != NULL); - DPRINTF(HWPrefetch, "returning 0x%x\n", pkt->getAddr()); - return pkt; +Addr +BasePrefetcher::pageAddress(Addr a) const +{ + return roundDown(a, pageBytes); } +Addr +BasePrefetcher::pageOffset(Addr a) const +{ + return a & (pageBytes - 1); +} -Tick -BasePrefetcher::notify(PacketPtr &pkt, Tick time) +Addr +BasePrefetcher::pageIthBlockAddress(Addr page, uint32_t blockIndex) const { - if (!pkt->req->isUncacheable() && !(pkt->req->isInstFetch() && onlyData)) { - // Calculate the blk address - Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); - - // Check if miss is in pfq, if so remove it - std::list::iterator iter = inPrefetch(blk_addr); - if (iter != pf.end()) { - DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: " - "0x%x, removing it\n", blk_addr); - pfRemovedMSHR++; - delete (*iter)->req; - delete (*iter); - pf.erase(iter); - if (pf.empty()) - cache->deassertMemSideBusRequest(BaseCache::Request_PF); - } + return page + (blockIndex << lBlkSize); +} - // Remove anything in queue with delay older than time - // since everything is inserted in time order, start from end - // and work until pf.empty() or time is earlier - // This is done to emulate Aborting the previous work on a new miss - // Needed for serial calculators like GHB - if (serialSquash) { - iter = pf.end(); - iter--; - while (!pf.empty() && ((*iter)->time >= time)) { - pfSquashed++; - DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n", - (*iter)->getAddr()); - delete (*iter)->req; - delete (*iter); - pf.erase(iter); - iter--; - } - if (pf.empty()) - cache->deassertMemSideBusRequest(BaseCache::Request_PF); - } +void +BasePrefetcher::probeNotify(const PacketPtr &pkt, bool miss) +{ + // 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; + if (!pkt->req->hasPaddr()) { + panic("Request must have a physical address"); + } + if (hasBeenPrefetched(pkt->getAddr(), pkt->isSecure())) { + usefulPrefetches += 1; + } - std::list addresses; - std::list delays; - calculatePrefetch(pkt, addresses, delays); - - std::list::iterator addrIter = addresses.begin(); - std::list::iterator delayIter = delays.begin(); - for (; addrIter != addresses.end(); ++addrIter, ++delayIter) { - Addr addr = *addrIter; - - pfIdentified++; - - DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, " - "inserting into prefetch queue with delay %d time %d\n", - addr, *delayIter, time); - - // Check if it is already in the pf buffer - if (inPrefetch(addr) != pf.end()) { - pfBufferHit++; - DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n"); - continue; - } - - // create a prefetch memreq - Request *prefetchReq = new Request(*addrIter, blkSize, 0); - PacketPtr prefetch = - new Packet(prefetchReq, MemCmd::HardPFReq, Packet::Broadcast); - prefetch->allocate(); - prefetch->req->setThreadContext(pkt->req->contextId(), - pkt->req->threadId()); - - prefetch->time = time + (*delayIter); // @todo ADD LATENCY HERE - - // We just remove the head if we are full - if (pf.size() == size) { - pfRemovedFull++; - PacketPtr old_pkt = *pf.begin(); - DPRINTF(HWPrefetch, "Prefetch queue full, " - "removing oldest 0x%x\n", old_pkt->getAddr()); - delete old_pkt->req; - delete old_pkt; - pf.pop_front(); - } - - pf.push_back(prefetch); + // Verify this access type is observed by prefetcher + if (observeAccess(pkt, miss)) { + if (useVirtualAddresses && pkt->req->hasVaddr()) { + PrefetchInfo pfi(pkt, pkt->req->getVaddr(), miss); + notify(pkt, pfi); + } else if (!useVirtualAddresses) { + PrefetchInfo pfi(pkt, pkt->req->getPaddr(), miss); + notify(pkt, pfi); } } - - return pf.empty() ? 0 : pf.front()->time; } -std::list::iterator -BasePrefetcher::inPrefetch(Addr address) +void +BasePrefetcher::regProbeListeners() { - // Guaranteed to only be one match, we always check before inserting - std::list::iterator iter; - for (iter = pf.begin(); iter != pf.end(); iter++) { - if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) { - return iter; + /** + * 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", false, + true)); + listeners.push_back(new PrefetchListener(*this, pm, "Fill", true, + false)); + if (prefetchOnAccess) { + listeners.push_back(new PrefetchListener(*this, pm, "Hit", false, + false)); } } - return pf.end(); } -bool -BasePrefetcher::samePage(Addr a, Addr b) +void +BasePrefetcher::addEventProbe(SimObject *obj, const char *name) +{ + ProbeManager *pm(obj->getProbeManager()); + listeners.push_back(new PrefetchListener(*this, pm, name)); +} + +void +BasePrefetcher::addTLB(BaseTLB *t) { - return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize); + fatal_if(tlb != nullptr, "Only one TLB can be registered"); + tlb = t; }