base.cc revision 6105
12810SN/A/* 22810SN/A * Copyright (c) 2005 The Regents of The University of Michigan 32810SN/A * All rights reserved. 42810SN/A * 52810SN/A * Redistribution and use in source and binary forms, with or without 62810SN/A * modification, are permitted provided that the following conditions are 72810SN/A * met: redistributions of source code must retain the above copyright 82810SN/A * notice, this list of conditions and the following disclaimer; 92810SN/A * redistributions in binary form must reproduce the above copyright 102810SN/A * notice, this list of conditions and the following disclaimer in the 112810SN/A * documentation and/or other materials provided with the distribution; 122810SN/A * neither the name of the copyright holders nor the names of its 132810SN/A * contributors may be used to endorse or promote products derived from 142810SN/A * this software without specific prior written permission. 152810SN/A * 162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810SN/A * 282810SN/A * Authors: Ron Dreslinski 292810SN/A */ 302810SN/A 312810SN/A/** 322810SN/A * @file 332810SN/A * Hardware Prefetcher Definition. 342810SN/A */ 352810SN/A 365875Ssteve.reinhardt@amd.com#include "arch/isa_traits.hh" 372810SN/A#include "base/trace.hh" 385338Sstever@gmail.com#include "mem/cache/base.hh" 395338Sstever@gmail.com#include "mem/cache/prefetch/base.hh" 402814SN/A#include "mem/request.hh" 412810SN/A#include <list> 422810SN/A 435034SN/ABasePrefetcher::BasePrefetcher(const BaseCacheParams *p) 445034SN/A : size(p->prefetcher_size), pageStop(!p->prefetch_past_page), 455034SN/A serialSquash(p->prefetch_serial_squash), 465034SN/A cacheCheckPush(p->prefetch_cache_check_push), 475875Ssteve.reinhardt@amd.com onlyData(p->prefetch_data_accesses_only) 482810SN/A{ 492810SN/A} 502810SN/A 512810SN/Avoid 522810SN/ABasePrefetcher::setCache(BaseCache *_cache) 532810SN/A{ 542810SN/A cache = _cache; 552810SN/A blkSize = cache->getBlockSize(); 565875Ssteve.reinhardt@amd.com _name = cache->name() + "-pf"; 572810SN/A} 582810SN/A 592810SN/Avoid 602810SN/ABasePrefetcher::regStats(const std::string &name) 612810SN/A{ 622810SN/A pfIdentified 632810SN/A .name(name + ".prefetcher.num_hwpf_identified") 642810SN/A .desc("number of hwpf identified") 652810SN/A ; 662810SN/A 672810SN/A pfMSHRHit 682810SN/A .name(name + ".prefetcher.num_hwpf_already_in_mshr") 692810SN/A .desc("number of hwpf that were already in mshr") 702810SN/A ; 712810SN/A 722810SN/A pfCacheHit 732810SN/A .name(name + ".prefetcher.num_hwpf_already_in_cache") 742810SN/A .desc("number of hwpf that were already in the cache") 752810SN/A ; 762810SN/A 772810SN/A pfBufferHit 782810SN/A .name(name + ".prefetcher.num_hwpf_already_in_prefetcher") 792810SN/A .desc("number of hwpf that were already in the prefetch queue") 802810SN/A ; 812810SN/A 822810SN/A pfRemovedFull 832810SN/A .name(name + ".prefetcher.num_hwpf_evicted") 842810SN/A .desc("number of hwpf removed due to no buffer left") 852810SN/A ; 862810SN/A 872810SN/A pfRemovedMSHR 882810SN/A .name(name + ".prefetcher.num_hwpf_removed_MSHR_hit") 892810SN/A .desc("number of hwpf removed because MSHR allocated") 902810SN/A ; 912810SN/A 922810SN/A pfIssued 932810SN/A .name(name + ".prefetcher.num_hwpf_issued") 942810SN/A .desc("number of hwpf issued") 952810SN/A ; 962810SN/A 972810SN/A pfSpanPage 982810SN/A .name(name + ".prefetcher.num_hwpf_span_page") 992810SN/A .desc("number of hwpf spanning a virtual page") 1002810SN/A ; 1012810SN/A 1022810SN/A pfSquashed 1032810SN/A .name(name + ".prefetcher.num_hwpf_squashed_from_miss") 1045875Ssteve.reinhardt@amd.com .desc("number of hwpf that got squashed due to a miss " 1055875Ssteve.reinhardt@amd.com "aborting calculation time") 1062810SN/A ; 1072810SN/A} 1082810SN/A 1093861SN/Ainline bool 1103861SN/ABasePrefetcher::inCache(Addr addr) 1113861SN/A{ 1123861SN/A if (cache->inCache(addr)) { 1133861SN/A pfCacheHit++; 1143861SN/A return true; 1153861SN/A } 1163861SN/A return false; 1173861SN/A} 1183861SN/A 1193861SN/Ainline bool 1203861SN/ABasePrefetcher::inMissQueue(Addr addr) 1213861SN/A{ 1223861SN/A if (cache->inMissQueue(addr)) { 1233861SN/A pfMSHRHit++; 1243861SN/A return true; 1253861SN/A } 1263861SN/A return false; 1273861SN/A} 1283861SN/A 1293349SN/APacketPtr 1302810SN/ABasePrefetcher::getPacket() 1312810SN/A{ 1325875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n"); 1332810SN/A 1342810SN/A if (pf.empty()) { 1355875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "No HW_PF found\n"); 1362810SN/A return NULL; 1372810SN/A } 1382810SN/A 1393349SN/A PacketPtr pkt; 1405875Ssteve.reinhardt@amd.com bool keep_trying = false; 1412810SN/A do { 1422810SN/A pkt = *pf.begin(); 1432810SN/A pf.pop_front(); 1442810SN/A if (!cacheCheckPush) { 1455875Ssteve.reinhardt@amd.com keep_trying = cache->inCache(pkt->getAddr()); 1462810SN/A } 1475875Ssteve.reinhardt@amd.com 1485875Ssteve.reinhardt@amd.com if (keep_trying) { 1495875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n", 1505875Ssteve.reinhardt@amd.com pkt->getAddr()); 1515875Ssteve.reinhardt@amd.com delete pkt->req; 1525875Ssteve.reinhardt@amd.com delete pkt; 1535875Ssteve.reinhardt@amd.com } 1545875Ssteve.reinhardt@amd.com 1552810SN/A if (pf.empty()) { 1564628SN/A cache->deassertMemSideBusRequest(BaseCache::Request_PF); 1575875Ssteve.reinhardt@amd.com if (keep_trying) { 1585875Ssteve.reinhardt@amd.com return NULL; // None left, all were in cache 1595875Ssteve.reinhardt@amd.com } 1602810SN/A } 1615875Ssteve.reinhardt@amd.com } while (keep_trying); 1622810SN/A 1632810SN/A pfIssued++; 1645875Ssteve.reinhardt@amd.com assert(pkt != NULL); 1655875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "returning 0x%x\n", pkt->getAddr()); 1662810SN/A return pkt; 1672810SN/A} 1682810SN/A 1695875Ssteve.reinhardt@amd.com 1705875Ssteve.reinhardt@amd.comTick 1715875Ssteve.reinhardt@amd.comBasePrefetcher::notify(PacketPtr &pkt, Tick time) 1722810SN/A{ 1736105Ssteve.reinhardt@amd.com if (!pkt->req->isUncacheable() && !(pkt->req->isInstFetch() && onlyData)) { 1745875Ssteve.reinhardt@amd.com // Calculate the blk address 1755875Ssteve.reinhardt@amd.com Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 1762810SN/A 1775875Ssteve.reinhardt@amd.com // Check if miss is in pfq, if so remove it 1785875Ssteve.reinhardt@amd.com std::list<PacketPtr>::iterator iter = inPrefetch(blk_addr); 1792810SN/A if (iter != pf.end()) { 1805875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: " 1815875Ssteve.reinhardt@amd.com "0x%x, removing it\n", blk_addr); 1822810SN/A pfRemovedMSHR++; 1835875Ssteve.reinhardt@amd.com delete (*iter)->req; 1845875Ssteve.reinhardt@amd.com delete (*iter); 1852810SN/A pf.erase(iter); 1862810SN/A if (pf.empty()) 1874628SN/A cache->deassertMemSideBusRequest(BaseCache::Request_PF); 1882810SN/A } 1892810SN/A 1905875Ssteve.reinhardt@amd.com // Remove anything in queue with delay older than time 1915875Ssteve.reinhardt@amd.com // since everything is inserted in time order, start from end 1925875Ssteve.reinhardt@amd.com // and work until pf.empty() or time is earlier 1935875Ssteve.reinhardt@amd.com // This is done to emulate Aborting the previous work on a new miss 1945875Ssteve.reinhardt@amd.com // Needed for serial calculators like GHB 1952810SN/A if (serialSquash) { 1962810SN/A iter = pf.end(); 1972810SN/A iter--; 1982810SN/A while (!pf.empty() && ((*iter)->time >= time)) { 1992810SN/A pfSquashed++; 2005875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n", 2015875Ssteve.reinhardt@amd.com (*iter)->getAddr()); 2025875Ssteve.reinhardt@amd.com delete (*iter)->req; 2035875Ssteve.reinhardt@amd.com delete (*iter); 2045875Ssteve.reinhardt@amd.com pf.erase(iter); 2052810SN/A iter--; 2062810SN/A } 2072810SN/A if (pf.empty()) 2084628SN/A cache->deassertMemSideBusRequest(BaseCache::Request_PF); 2092810SN/A } 2102810SN/A 2112810SN/A 2122810SN/A std::list<Addr> addresses; 2132810SN/A std::list<Tick> delays; 2142810SN/A calculatePrefetch(pkt, addresses, delays); 2152810SN/A 2165875Ssteve.reinhardt@amd.com std::list<Addr>::iterator addrIter = addresses.begin(); 2175875Ssteve.reinhardt@amd.com std::list<Tick>::iterator delayIter = delays.begin(); 2185875Ssteve.reinhardt@amd.com for (; addrIter != addresses.end(); ++addrIter, ++delayIter) { 2195875Ssteve.reinhardt@amd.com Addr addr = *addrIter; 2205875Ssteve.reinhardt@amd.com 2212810SN/A pfIdentified++; 2225875Ssteve.reinhardt@amd.com 2235875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, " 2245875Ssteve.reinhardt@amd.com "inserting into prefetch queue with delay %d time %d\n", 2255875Ssteve.reinhardt@amd.com addr, *delayIter, time); 2265875Ssteve.reinhardt@amd.com 2275875Ssteve.reinhardt@amd.com // Check if it is already in the cache 2285875Ssteve.reinhardt@amd.com if (cacheCheckPush && cache->inCache(addr)) { 2295875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Prefetch addr already in cache\n"); 2305875Ssteve.reinhardt@amd.com continue; 2315875Ssteve.reinhardt@amd.com } 2325875Ssteve.reinhardt@amd.com 2335875Ssteve.reinhardt@amd.com // Check if it is already in the miss_queue 2345875Ssteve.reinhardt@amd.com if (cache->inMissQueue(addr)) { 2355875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Prefetch addr already in miss queue\n"); 2365875Ssteve.reinhardt@amd.com continue; 2375875Ssteve.reinhardt@amd.com } 2385875Ssteve.reinhardt@amd.com 2395875Ssteve.reinhardt@amd.com // Check if it is already in the pf buffer 2405875Ssteve.reinhardt@amd.com if (inPrefetch(addr) != pf.end()) { 2415875Ssteve.reinhardt@amd.com pfBufferHit++; 2425875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n"); 2435875Ssteve.reinhardt@amd.com continue; 2445875Ssteve.reinhardt@amd.com } 2455875Ssteve.reinhardt@amd.com 2465875Ssteve.reinhardt@amd.com // create a prefetch memreq 2475875Ssteve.reinhardt@amd.com Request *prefetchReq = new Request(*addrIter, blkSize, 0); 2485875Ssteve.reinhardt@amd.com PacketPtr prefetch = 2495875Ssteve.reinhardt@amd.com new Packet(prefetchReq, MemCmd::HardPFReq, Packet::Broadcast); 2502825SN/A prefetch->allocate(); 2515714Shsul@eecs.umich.edu prefetch->req->setThreadContext(pkt->req->contextId(), 2525714Shsul@eecs.umich.edu pkt->req->threadId()); 2532814SN/A 2545875Ssteve.reinhardt@amd.com prefetch->time = time + (*delayIter); // @todo ADD LATENCY HERE 2552810SN/A 2565875Ssteve.reinhardt@amd.com // We just remove the head if we are full 2575875Ssteve.reinhardt@amd.com if (pf.size() == size) { 2582810SN/A pfRemovedFull++; 2595875Ssteve.reinhardt@amd.com PacketPtr old_pkt = *pf.begin(); 2605875Ssteve.reinhardt@amd.com DPRINTF(HWPrefetch, "Prefetch queue full, " 2615875Ssteve.reinhardt@amd.com "removing oldest 0x%x\n", old_pkt->getAddr()); 2625875Ssteve.reinhardt@amd.com delete old_pkt->req; 2635875Ssteve.reinhardt@amd.com delete old_pkt; 2642810SN/A pf.pop_front(); 2652810SN/A } 2662810SN/A 2672810SN/A pf.push_back(prefetch); 2682810SN/A } 2692810SN/A } 2705875Ssteve.reinhardt@amd.com 2715875Ssteve.reinhardt@amd.com return pf.empty() ? 0 : pf.front()->time; 2722810SN/A} 2732810SN/A 2743349SN/Astd::list<PacketPtr>::iterator 2752810SN/ABasePrefetcher::inPrefetch(Addr address) 2762810SN/A{ 2775875Ssteve.reinhardt@amd.com // Guaranteed to only be one match, we always check before inserting 2783349SN/A std::list<PacketPtr>::iterator iter; 2795875Ssteve.reinhardt@amd.com for (iter = pf.begin(); iter != pf.end(); iter++) { 2802814SN/A if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) { 2812810SN/A return iter; 2822810SN/A } 2832810SN/A } 2842810SN/A return pf.end(); 2852810SN/A} 2862810SN/A 2875875Ssteve.reinhardt@amd.combool 2885875Ssteve.reinhardt@amd.comBasePrefetcher::samePage(Addr a, Addr b) 2895875Ssteve.reinhardt@amd.com{ 2905875Ssteve.reinhardt@amd.com return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize); 2915875Ssteve.reinhardt@amd.com} 292