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