1/* 2 * Copyright (c) 2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ron Dreslinski 29 */ 30 31/** 32 * @file 33 * Hardware Prefetcher Definition. 34 */ 35 36#include <list> 37 38#include "arch/isa_traits.hh" 39#include "base/trace.hh" 40#include "config/the_isa.hh" 41#include "debug/HWPrefetch.hh" 42#include "mem/cache/prefetch/base.hh" 43#include "mem/cache/base.hh" 44#include "mem/request.hh"
| 1/* 2 * Copyright (c) 2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ron Dreslinski 29 */ 30 31/** 32 * @file 33 * Hardware Prefetcher Definition. 34 */ 35 36#include <list> 37 38#include "arch/isa_traits.hh" 39#include "base/trace.hh" 40#include "config/the_isa.hh" 41#include "debug/HWPrefetch.hh" 42#include "mem/cache/prefetch/base.hh" 43#include "mem/cache/base.hh" 44#include "mem/request.hh"
|
| 45#include "sim/system.hh"
|
45 46BasePrefetcher::BasePrefetcher(const Params *p) 47 : SimObject(p), size(p->size), latency(p->latency), degree(p->degree),
| 46 47BasePrefetcher::BasePrefetcher(const Params *p) 48 : SimObject(p), size(p->size), latency(p->latency), degree(p->degree),
|
48 useContextId(p->use_cpu_id), pageStop(!p->cross_pages), 49 serialSquash(p->serial_squash), onlyData(p->data_accesses_only)
| 49 useMasterId(p->use_master_id), pageStop(!p->cross_pages), 50 serialSquash(p->serial_squash), onlyData(p->data_accesses_only), 51 system(p->sys), masterId(system->getMasterId(name()))
|
50{ 51} 52 53void 54BasePrefetcher::setCache(BaseCache *_cache) 55{ 56 cache = _cache; 57 blkSize = cache->getBlockSize(); 58} 59 60void 61BasePrefetcher::regStats() 62{ 63 pfIdentified 64 .name(name() + ".prefetcher.num_hwpf_identified") 65 .desc("number of hwpf identified") 66 ; 67 68 pfMSHRHit 69 .name(name() + ".prefetcher.num_hwpf_already_in_mshr") 70 .desc("number of hwpf that were already in mshr") 71 ; 72 73 pfCacheHit 74 .name(name() + ".prefetcher.num_hwpf_already_in_cache") 75 .desc("number of hwpf that were already in the cache") 76 ; 77 78 pfBufferHit 79 .name(name() + ".prefetcher.num_hwpf_already_in_prefetcher") 80 .desc("number of hwpf that were already in the prefetch queue") 81 ; 82 83 pfRemovedFull 84 .name(name() + ".prefetcher.num_hwpf_evicted") 85 .desc("number of hwpf removed due to no buffer left") 86 ; 87 88 pfRemovedMSHR 89 .name(name() + ".prefetcher.num_hwpf_removed_MSHR_hit") 90 .desc("number of hwpf removed because MSHR allocated") 91 ; 92 93 pfIssued 94 .name(name() + ".prefetcher.num_hwpf_issued") 95 .desc("number of hwpf issued") 96 ; 97 98 pfSpanPage 99 .name(name() + ".prefetcher.num_hwpf_span_page") 100 .desc("number of hwpf spanning a virtual page") 101 ; 102 103 pfSquashed 104 .name(name() + ".prefetcher.num_hwpf_squashed_from_miss") 105 .desc("number of hwpf that got squashed due to a miss " 106 "aborting calculation time") 107 ; 108} 109 110inline bool 111BasePrefetcher::inCache(Addr addr) 112{ 113 if (cache->inCache(addr)) { 114 pfCacheHit++; 115 return true; 116 } 117 return false; 118} 119 120inline bool 121BasePrefetcher::inMissQueue(Addr addr) 122{ 123 if (cache->inMissQueue(addr)) { 124 pfMSHRHit++; 125 return true; 126 } 127 return false; 128} 129 130PacketPtr 131BasePrefetcher::getPacket() 132{ 133 DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n"); 134 135 if (pf.empty()) { 136 DPRINTF(HWPrefetch, "No HW_PF found\n"); 137 return NULL; 138 } 139 140 PacketPtr pkt = *pf.begin(); 141 while (!pf.empty()) { 142 pkt = *pf.begin(); 143 pf.pop_front(); 144 145 Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 146 147 if (!inCache(blk_addr) && !inMissQueue(blk_addr)) 148 // we found a prefetch, return it 149 break; 150 151 DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n", pkt->getAddr()); 152 delete pkt->req; 153 delete pkt; 154 155 if (pf.empty()) { 156 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 157 return NULL; // None left, all were in cache 158 } 159 } 160 161 pfIssued++; 162 assert(pkt != NULL); 163 DPRINTF(HWPrefetch, "returning 0x%x\n", pkt->getAddr()); 164 return pkt; 165} 166 167 168Tick 169BasePrefetcher::notify(PacketPtr &pkt, Tick time) 170{ 171 if (!pkt->req->isUncacheable() && !(pkt->req->isInstFetch() && onlyData)) { 172 // Calculate the blk address 173 Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 174 175 // Check if miss is in pfq, if so remove it 176 std::list<PacketPtr>::iterator iter = inPrefetch(blk_addr); 177 if (iter != pf.end()) { 178 DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: " 179 "0x%x, removing it\n", blk_addr); 180 pfRemovedMSHR++; 181 delete (*iter)->req; 182 delete (*iter); 183 pf.erase(iter); 184 if (pf.empty()) 185 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 186 } 187 188 // Remove anything in queue with delay older than time 189 // since everything is inserted in time order, start from end 190 // and work until pf.empty() or time is earlier 191 // This is done to emulate Aborting the previous work on a new miss 192 // Needed for serial calculators like GHB 193 if (serialSquash) { 194 iter = pf.end(); 195 iter--; 196 while (!pf.empty() && ((*iter)->time >= time)) { 197 pfSquashed++; 198 DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n", 199 (*iter)->getAddr()); 200 delete (*iter)->req; 201 delete (*iter); 202 pf.erase(iter); 203 iter--; 204 } 205 if (pf.empty()) 206 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 207 } 208 209 210 std::list<Addr> addresses; 211 std::list<Tick> delays; 212 calculatePrefetch(pkt, addresses, delays); 213 214 std::list<Addr>::iterator addrIter = addresses.begin(); 215 std::list<Tick>::iterator delayIter = delays.begin(); 216 for (; addrIter != addresses.end(); ++addrIter, ++delayIter) { 217 Addr addr = *addrIter; 218 219 pfIdentified++; 220 221 DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, " 222 "inserting into prefetch queue with delay %d time %d\n", 223 addr, *delayIter, time); 224 225 // Check if it is already in the pf buffer 226 if (inPrefetch(addr) != pf.end()) { 227 pfBufferHit++; 228 DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n"); 229 continue; 230 } 231 232 // create a prefetch memreq
| 52{ 53} 54 55void 56BasePrefetcher::setCache(BaseCache *_cache) 57{ 58 cache = _cache; 59 blkSize = cache->getBlockSize(); 60} 61 62void 63BasePrefetcher::regStats() 64{ 65 pfIdentified 66 .name(name() + ".prefetcher.num_hwpf_identified") 67 .desc("number of hwpf identified") 68 ; 69 70 pfMSHRHit 71 .name(name() + ".prefetcher.num_hwpf_already_in_mshr") 72 .desc("number of hwpf that were already in mshr") 73 ; 74 75 pfCacheHit 76 .name(name() + ".prefetcher.num_hwpf_already_in_cache") 77 .desc("number of hwpf that were already in the cache") 78 ; 79 80 pfBufferHit 81 .name(name() + ".prefetcher.num_hwpf_already_in_prefetcher") 82 .desc("number of hwpf that were already in the prefetch queue") 83 ; 84 85 pfRemovedFull 86 .name(name() + ".prefetcher.num_hwpf_evicted") 87 .desc("number of hwpf removed due to no buffer left") 88 ; 89 90 pfRemovedMSHR 91 .name(name() + ".prefetcher.num_hwpf_removed_MSHR_hit") 92 .desc("number of hwpf removed because MSHR allocated") 93 ; 94 95 pfIssued 96 .name(name() + ".prefetcher.num_hwpf_issued") 97 .desc("number of hwpf issued") 98 ; 99 100 pfSpanPage 101 .name(name() + ".prefetcher.num_hwpf_span_page") 102 .desc("number of hwpf spanning a virtual page") 103 ; 104 105 pfSquashed 106 .name(name() + ".prefetcher.num_hwpf_squashed_from_miss") 107 .desc("number of hwpf that got squashed due to a miss " 108 "aborting calculation time") 109 ; 110} 111 112inline bool 113BasePrefetcher::inCache(Addr addr) 114{ 115 if (cache->inCache(addr)) { 116 pfCacheHit++; 117 return true; 118 } 119 return false; 120} 121 122inline bool 123BasePrefetcher::inMissQueue(Addr addr) 124{ 125 if (cache->inMissQueue(addr)) { 126 pfMSHRHit++; 127 return true; 128 } 129 return false; 130} 131 132PacketPtr 133BasePrefetcher::getPacket() 134{ 135 DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n"); 136 137 if (pf.empty()) { 138 DPRINTF(HWPrefetch, "No HW_PF found\n"); 139 return NULL; 140 } 141 142 PacketPtr pkt = *pf.begin(); 143 while (!pf.empty()) { 144 pkt = *pf.begin(); 145 pf.pop_front(); 146 147 Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 148 149 if (!inCache(blk_addr) && !inMissQueue(blk_addr)) 150 // we found a prefetch, return it 151 break; 152 153 DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n", pkt->getAddr()); 154 delete pkt->req; 155 delete pkt; 156 157 if (pf.empty()) { 158 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 159 return NULL; // None left, all were in cache 160 } 161 } 162 163 pfIssued++; 164 assert(pkt != NULL); 165 DPRINTF(HWPrefetch, "returning 0x%x\n", pkt->getAddr()); 166 return pkt; 167} 168 169 170Tick 171BasePrefetcher::notify(PacketPtr &pkt, Tick time) 172{ 173 if (!pkt->req->isUncacheable() && !(pkt->req->isInstFetch() && onlyData)) { 174 // Calculate the blk address 175 Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 176 177 // Check if miss is in pfq, if so remove it 178 std::list<PacketPtr>::iterator iter = inPrefetch(blk_addr); 179 if (iter != pf.end()) { 180 DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: " 181 "0x%x, removing it\n", blk_addr); 182 pfRemovedMSHR++; 183 delete (*iter)->req; 184 delete (*iter); 185 pf.erase(iter); 186 if (pf.empty()) 187 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 188 } 189 190 // Remove anything in queue with delay older than time 191 // since everything is inserted in time order, start from end 192 // and work until pf.empty() or time is earlier 193 // This is done to emulate Aborting the previous work on a new miss 194 // Needed for serial calculators like GHB 195 if (serialSquash) { 196 iter = pf.end(); 197 iter--; 198 while (!pf.empty() && ((*iter)->time >= time)) { 199 pfSquashed++; 200 DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n", 201 (*iter)->getAddr()); 202 delete (*iter)->req; 203 delete (*iter); 204 pf.erase(iter); 205 iter--; 206 } 207 if (pf.empty()) 208 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 209 } 210 211 212 std::list<Addr> addresses; 213 std::list<Tick> delays; 214 calculatePrefetch(pkt, addresses, delays); 215 216 std::list<Addr>::iterator addrIter = addresses.begin(); 217 std::list<Tick>::iterator delayIter = delays.begin(); 218 for (; addrIter != addresses.end(); ++addrIter, ++delayIter) { 219 Addr addr = *addrIter; 220 221 pfIdentified++; 222 223 DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, " 224 "inserting into prefetch queue with delay %d time %d\n", 225 addr, *delayIter, time); 226 227 // Check if it is already in the pf buffer 228 if (inPrefetch(addr) != pf.end()) { 229 pfBufferHit++; 230 DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n"); 231 continue; 232 } 233 234 // create a prefetch memreq
|
233 Request *prefetchReq = new Request(*addrIter, blkSize, 0);
| 235 Request *prefetchReq = new Request(*addrIter, blkSize, 0, masterId);
|
234 PacketPtr prefetch = 235 new Packet(prefetchReq, MemCmd::HardPFReq, Packet::Broadcast); 236 prefetch->allocate(); 237 prefetch->req->setThreadContext(pkt->req->contextId(), 238 pkt->req->threadId()); 239 240 prefetch->time = time + (*delayIter); // @todo ADD LATENCY HERE 241 242 // We just remove the head if we are full 243 if (pf.size() == size) { 244 pfRemovedFull++; 245 PacketPtr old_pkt = *pf.begin(); 246 DPRINTF(HWPrefetch, "Prefetch queue full, " 247 "removing oldest 0x%x\n", old_pkt->getAddr()); 248 delete old_pkt->req; 249 delete old_pkt; 250 pf.pop_front(); 251 } 252 253 pf.push_back(prefetch); 254 } 255 } 256 257 return pf.empty() ? 0 : pf.front()->time; 258} 259 260std::list<PacketPtr>::iterator 261BasePrefetcher::inPrefetch(Addr address) 262{ 263 // Guaranteed to only be one match, we always check before inserting 264 std::list<PacketPtr>::iterator iter; 265 for (iter = pf.begin(); iter != pf.end(); iter++) { 266 if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) { 267 return iter; 268 } 269 } 270 return pf.end(); 271} 272 273bool 274BasePrefetcher::samePage(Addr a, Addr b) 275{ 276 return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize); 277} 278 279
| 236 PacketPtr prefetch = 237 new Packet(prefetchReq, MemCmd::HardPFReq, Packet::Broadcast); 238 prefetch->allocate(); 239 prefetch->req->setThreadContext(pkt->req->contextId(), 240 pkt->req->threadId()); 241 242 prefetch->time = time + (*delayIter); // @todo ADD LATENCY HERE 243 244 // We just remove the head if we are full 245 if (pf.size() == size) { 246 pfRemovedFull++; 247 PacketPtr old_pkt = *pf.begin(); 248 DPRINTF(HWPrefetch, "Prefetch queue full, " 249 "removing oldest 0x%x\n", old_pkt->getAddr()); 250 delete old_pkt->req; 251 delete old_pkt; 252 pf.pop_front(); 253 } 254 255 pf.push_back(prefetch); 256 } 257 } 258 259 return pf.empty() ? 0 : pf.front()->time; 260} 261 262std::list<PacketPtr>::iterator 263BasePrefetcher::inPrefetch(Addr address) 264{ 265 // Guaranteed to only be one match, we always check before inserting 266 std::list<PacketPtr>::iterator iter; 267 for (iter = pf.begin(); iter != pf.end(); iter++) { 268 if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) { 269 return iter; 270 } 271 } 272 return pf.end(); 273} 274 275bool 276BasePrefetcher::samePage(Addr a, Addr b) 277{ 278 return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize); 279} 280 281
|