base.cc revision 10052:5bb8e054456b
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 onMissOnly(p->on_miss_only), onReadOnly(p->on_read_only), 64 onPrefetch(p->on_prefetch), system(p->sys), 65 masterId(system->getMasterId(name())) 66{ 67} 68 69void 70BasePrefetcher::setCache(BaseCache *_cache) 71{ 72 cache = _cache; 73 blkSize = cache->getBlockSize(); 74} 75 76void 77BasePrefetcher::regStats() 78{ 79 pfIdentified 80 .name(name() + ".prefetcher.num_hwpf_identified") 81 .desc("number of hwpf identified") 82 ; 83 84 pfMSHRHit 85 .name(name() + ".prefetcher.num_hwpf_already_in_mshr") 86 .desc("number of hwpf that were already in mshr") 87 ; 88 89 pfCacheHit 90 .name(name() + ".prefetcher.num_hwpf_already_in_cache") 91 .desc("number of hwpf that were already in the cache") 92 ; 93 94 pfBufferHit 95 .name(name() + ".prefetcher.num_hwpf_already_in_prefetcher") 96 .desc("number of hwpf that were already in the prefetch queue") 97 ; 98 99 pfRemovedFull 100 .name(name() + ".prefetcher.num_hwpf_evicted") 101 .desc("number of hwpf removed due to no buffer left") 102 ; 103 104 pfRemovedMSHR 105 .name(name() + ".prefetcher.num_hwpf_removed_MSHR_hit") 106 .desc("number of hwpf removed because MSHR allocated") 107 ; 108 109 pfIssued 110 .name(name() + ".prefetcher.num_hwpf_issued") 111 .desc("number of hwpf issued") 112 ; 113 114 pfSpanPage 115 .name(name() + ".prefetcher.num_hwpf_span_page") 116 .desc("number of hwpf spanning a virtual page") 117 ; 118 119 pfSquashed 120 .name(name() + ".prefetcher.num_hwpf_squashed_from_miss") 121 .desc("number of hwpf that got squashed due to a miss " 122 "aborting calculation time") 123 ; 124} 125 126inline bool 127BasePrefetcher::inCache(Addr addr, bool is_secure) 128{ 129 if (cache->inCache(addr, is_secure)) { 130 pfCacheHit++; 131 return true; 132 } 133 return false; 134} 135 136inline bool 137BasePrefetcher::inMissQueue(Addr addr, bool is_secure) 138{ 139 if (cache->inMissQueue(addr, is_secure)) { 140 pfMSHRHit++; 141 return true; 142 } 143 return false; 144} 145 146PacketPtr 147BasePrefetcher::getPacket() 148{ 149 DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n"); 150 151 if (pf.empty()) { 152 DPRINTF(HWPrefetch, "No HW_PF found\n"); 153 return NULL; 154 } 155 156 PacketPtr pkt = pf.begin()->pkt; 157 while (!pf.empty()) { 158 pkt = pf.begin()->pkt; 159 pf.pop_front(); 160 161 Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 162 bool is_secure = pkt->isSecure(); 163 164 if (!inCache(blk_addr, is_secure) && !inMissQueue(blk_addr, is_secure)) 165 // we found a prefetch, return it 166 break; 167 168 DPRINTF(HWPrefetch, "addr 0x%x (%s) in cache, skipping\n", 169 pkt->getAddr(), is_secure ? "s" : "ns"); 170 delete pkt->req; 171 delete pkt; 172 173 if (pf.empty()) { 174 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 175 return NULL; // None left, all were in cache 176 } 177 } 178 179 pfIssued++; 180 assert(pkt != NULL); 181 DPRINTF(HWPrefetch, "returning 0x%x (%s)\n", pkt->getAddr(), 182 pkt->isSecure() ? "s" : "ns"); 183 return pkt; 184} 185 186 187Tick 188BasePrefetcher::notify(PacketPtr &pkt, Tick tick) 189{ 190 // Don't consult the prefetcher if any of the following conditons are true 191 // 1) The request is uncacheable 192 // 2) The request is a fetch, but we are only prefeching data 193 // 3) The request is a cache hit, but we are only training on misses 194 // 4) THe request is a write, but we are only training on reads 195 if (!pkt->req->isUncacheable() && !(pkt->req->isInstFetch() && onlyData) && 196 !(onMissOnly && inCache(pkt->getAddr(), true)) && 197 !(onReadOnly && !pkt->isRead())) { 198 // Calculate the blk address 199 Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); 200 bool is_secure = pkt->isSecure(); 201 202 // Check if miss is in pfq, if so remove it 203 std::list<DeferredPacket>::iterator iter = inPrefetch(blk_addr, 204 is_secure); 205 if (iter != pf.end()) { 206 DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: " 207 "0x%x (%s), removing it\n", blk_addr, 208 is_secure ? "s" : "ns"); 209 pfRemovedMSHR++; 210 delete iter->pkt->req; 211 delete iter->pkt; 212 iter = pf.erase(iter); 213 if (pf.empty()) 214 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 215 } 216 217 // Remove anything in queue with delay older than time 218 // since everything is inserted in time order, start from end 219 // and work until pf.empty() or time is earlier 220 // This is done to emulate Aborting the previous work on a new miss 221 // Needed for serial calculators like GHB 222 if (serialSquash) { 223 iter = pf.end(); 224 if (iter != pf.begin()) 225 iter--; 226 while (!pf.empty() && iter->tick >= tick) { 227 pfSquashed++; 228 DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n", 229 iter->pkt->getAddr()); 230 delete iter->pkt->req; 231 delete iter->pkt; 232 iter = pf.erase(iter); 233 if (iter != pf.begin()) 234 iter--; 235 } 236 if (pf.empty()) 237 cache->deassertMemSideBusRequest(BaseCache::Request_PF); 238 } 239 240 241 std::list<Addr> addresses; 242 std::list<Cycles> delays; 243 calculatePrefetch(pkt, addresses, delays); 244 245 std::list<Addr>::iterator addrIter = addresses.begin(); 246 std::list<Cycles>::iterator delayIter = delays.begin(); 247 for (; addrIter != addresses.end(); ++addrIter, ++delayIter) { 248 Addr addr = *addrIter; 249 250 pfIdentified++; 251 252 DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, " 253 "inserting into prefetch queue with delay %d time %d\n", 254 addr, *delayIter, time); 255 256 // Check if it is already in the pf buffer 257 if (inPrefetch(addr, is_secure) != pf.end()) { 258 pfBufferHit++; 259 DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n"); 260 continue; 261 } 262 263 // create a prefetch memreq 264 Request *prefetchReq = new Request(*addrIter, blkSize, 0, masterId); 265 if (is_secure) 266 prefetchReq->setFlags(Request::SECURE); 267 prefetchReq->taskId(ContextSwitchTaskId::Prefetcher); 268 PacketPtr prefetch = 269 new Packet(prefetchReq, MemCmd::HardPFReq); 270 prefetch->allocate(); 271 prefetch->req->setThreadContext(pkt->req->contextId(), 272 pkt->req->threadId()); 273 274 // Tag orefetch reqeuests with corresponding PC to train lower 275 // cache-level prefetchers 276 if (onPrefetch && pkt->req->hasPC()) 277 prefetch->req->setPC(pkt->req->getPC()); 278 279 // We just remove the head if we are full 280 if (pf.size() == size) { 281 pfRemovedFull++; 282 PacketPtr old_pkt = pf.begin()->pkt; 283 DPRINTF(HWPrefetch, "Prefetch queue full, " 284 "removing oldest 0x%x\n", old_pkt->getAddr()); 285 delete old_pkt->req; 286 delete old_pkt; 287 pf.pop_front(); 288 } 289 290 pf.push_back(DeferredPacket(tick + clockPeriod() * *delayIter, 291 prefetch)); 292 } 293 } 294 295 return pf.empty() ? 0 : pf.front().tick; 296} 297 298std::list<BasePrefetcher::DeferredPacket>::iterator 299BasePrefetcher::inPrefetch(Addr address, bool is_secure) 300{ 301 // Guaranteed to only be one match, we always check before inserting 302 std::list<DeferredPacket>::iterator iter; 303 for (iter = pf.begin(); iter != pf.end(); iter++) { 304 if (((*iter).pkt->getAddr() & ~(Addr)(blkSize-1)) == address && 305 (*iter).pkt->isSecure() == is_secure) { 306 return iter; 307 } 308 } 309 return pf.end(); 310} 311 312bool 313BasePrefetcher::samePage(Addr a, Addr b) 314{ 315 return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize); 316} 317 318 319