base.cc revision 8229:78bf55f23338
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 "mem/cache/prefetch/base.hh"
42#include "mem/cache/base.hh"
43#include "mem/request.hh"
44
45BasePrefetcher::BasePrefetcher(const BaseCacheParams *p)
46    : size(p->prefetcher_size), pageStop(!p->prefetch_past_page),
47      serialSquash(p->prefetch_serial_squash),
48      onlyData(p->prefetch_data_accesses_only)
49{
50}
51
52void
53BasePrefetcher::setCache(BaseCache *_cache)
54{
55    cache = _cache;
56    blkSize = cache->getBlockSize();
57    _name = cache->name() + "-pf";
58}
59
60void
61BasePrefetcher::regStats(const std::string &name)
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;
141    bool keep_trying = false;
142    do {
143        pkt = *pf.begin();
144        pf.pop_front();
145
146        if (keep_trying) {
147            DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n",
148                    pkt->getAddr());
149            delete pkt->req;
150            delete pkt;
151        }
152
153        if (pf.empty()) {
154            cache->deassertMemSideBusRequest(BaseCache::Request_PF);
155            if (keep_trying) {
156                return NULL; // None left, all were in cache
157            }
158        }
159    } while (keep_trying);
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
233            Request *prefetchReq = new Request(*addrIter, blkSize, 0);
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