2 * Copyright (c) 2014-2015 ARM Limited
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.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Authors: Mitch Hayenga
40 #include "mem/cache/prefetch/queued.hh"
44 #include "base/logging.hh"
45 #include "base/trace.hh"
46 #include "debug/HWPrefetch.hh"
47 #include "mem/request.hh"
48 #include "params/QueuedPrefetcher.hh"
50 QueuedPrefetcher::QueuedPrefetcher(const QueuedPrefetcherParams
*p
)
51 : BasePrefetcher(p
), queueSize(p
->queue_size
), latency(p
->latency
),
52 queueSquash(p
->queue_squash
), queueFilter(p
->queue_filter
),
53 cacheSnoop(p
->cache_snoop
), tagPrefetch(p
->tag_prefetch
)
58 QueuedPrefetcher::~QueuedPrefetcher()
60 // Delete the queued prefetch packets
61 for (DeferredPacket
&p
: pfq
) {
67 QueuedPrefetcher::notify(const PacketPtr
&pkt
, const PrefetchInfo
&pfi
)
69 Addr blk_addr
= blockAddress(pfi
.getAddr());
70 bool is_secure
= pfi
.isSecure();
72 // Squash queued prefetches if demand miss to same line
74 auto itr
= pfq
.begin();
75 while (itr
!= pfq
.end()) {
76 if (itr
->pfInfo
.getAddr() == blk_addr
&&
77 itr
->pfInfo
.isSecure() == is_secure
) {
86 // Calculate prefetches given this access
87 std::vector
<AddrPriority
> addresses
;
88 calculatePrefetch(pfi
, addresses
);
90 // Queue up generated prefetches
91 for (AddrPriority
& addr_prio
: addresses
) {
93 // Block align prefetch address
94 addr_prio
.first
= blockAddress(addr_prio
.first
);
96 PrefetchInfo
new_pfi(pfi
,addr_prio
.first
);
99 DPRINTF(HWPrefetch
, "Found a pf candidate addr: %#x, "
100 "inserting into prefetch queue.\n", new_pfi
.getAddr());
102 // Create and insert the request
103 insert(pkt
, new_pfi
, addr_prio
.second
);
108 QueuedPrefetcher::getPacket()
110 DPRINTF(HWPrefetch
, "Requesting a prefetch to issue.\n");
113 DPRINTF(HWPrefetch
, "No hardware prefetches available.\n");
117 PacketPtr pkt
= pfq
.front().pkt
;
121 assert(pkt
!= nullptr);
122 DPRINTF(HWPrefetch
, "Generating prefetch for %#x.\n", pkt
->getAddr());
126 QueuedPrefetcher::const_iterator
127 QueuedPrefetcher::inPrefetch(const PrefetchInfo
&pfi
) const
129 for (const_iterator dp
= pfq
.begin(); dp
!= pfq
.end(); dp
++) {
130 if (dp
->pfInfo
.sameAddr(pfi
)) return dp
;
136 QueuedPrefetcher::iterator
137 QueuedPrefetcher::inPrefetch(const PrefetchInfo
&pfi
)
139 for (iterator dp
= pfq
.begin(); dp
!= pfq
.end(); dp
++) {
140 if (dp
->pfInfo
.sameAddr(pfi
)) return dp
;
147 QueuedPrefetcher::regStats()
149 BasePrefetcher::regStats();
152 .name(name() + ".pfIdentified")
153 .desc("number of prefetch candidates identified");
156 .name(name() + ".pfBufferHit")
157 .desc("number of redundant prefetches already in prefetch queue");
160 .name(name() + ".pfInCache")
161 .desc("number of redundant prefetches already in cache/mshr dropped");
164 .name(name() + ".pfRemovedFull")
165 .desc("number of prefetches dropped due to prefetch queue size");
168 .name(name() + ".pfSpanPage")
169 .desc("number of prefetches not generated due to page crossing");
173 QueuedPrefetcher::insert(const PacketPtr
&pkt
, PrefetchInfo
&new_pfi
,
177 iterator it
= inPrefetch(new_pfi
);
178 /* If the address is already in the queue, update priority and leave */
179 if (it
!= pfq
.end()) {
181 if (it
->priority
< priority
) {
182 /* Update priority value and position in the queue */
183 it
->priority
= priority
;
186 while (cont
&& prev
!= pfq
.begin()) {
188 /* If the packet has higher priority, swap */
190 std::swap(*it
, *prev
);
194 DPRINTF(HWPrefetch
, "Prefetch addr already in "
195 "prefetch queue, priority updated\n");
197 DPRINTF(HWPrefetch
, "Prefetch addr already in "
204 Addr target_addr
= new_pfi
.getAddr();
205 if (useVirtualAddresses
) {
206 assert(pkt
->req
->hasPaddr());
207 //if we trained with virtual addresses, compute the phsysical address
208 if (new_pfi
.getAddr() >= pkt
->req
->getVaddr()) {
210 target_addr
= pkt
->req
->getPaddr() +
211 (new_pfi
.getAddr() - pkt
->req
->getVaddr());
214 target_addr
= pkt
->req
->getPaddr() -
215 (pkt
->req
->getVaddr() - new_pfi
.getAddr());
219 if (cacheSnoop
&& (inCache(target_addr
, new_pfi
.isSecure()) ||
220 inMissQueue(target_addr
, new_pfi
.isSecure()))) {
222 DPRINTF(HWPrefetch
, "Dropping redundant in "
223 "cache/MSHR prefetch addr:%#x\n", target_addr
);
227 /* Create a prefetch memory request */
229 std::make_shared
<Request
>(target_addr
, blkSize
, 0, masterId
);
231 if (new_pfi
.isSecure()) {
232 pf_req
->setFlags(Request::SECURE
);
234 pf_req
->taskId(ContextSwitchTaskId::Prefetcher
);
235 PacketPtr pf_pkt
= new Packet(pf_req
, MemCmd::HardPFReq
);
237 if (tagPrefetch
&& new_pfi
.hasPC()) {
238 // Tag prefetch packet with accessing pc
239 pf_pkt
->req
->setPC(new_pfi
.getPC());
242 /* Verify prefetch buffer space for request */
243 if (pfq
.size() == queueSize
) {
245 /* Lowest priority packet */
246 iterator it
= pfq
.end();
247 panic_if (it
== pfq
.begin(), "Prefetch queue is both full and empty!");
249 /* Look for oldest in that level of priority */
250 panic_if (it
== pfq
.begin(), "Prefetch queue is full with 1 element!");
253 /* While not at the head of the queue */
254 while (cont
&& prev
!= pfq
.begin()) {
256 /* While at the same level of priority */
257 cont
= prev
->priority
== it
->priority
;
262 DPRINTF(HWPrefetch
, "Prefetch queue full, removing lowest priority "
263 "oldest packet, addr: %#x", it
->pfInfo
.getAddr());
268 Tick pf_time
= curTick() + clockPeriod() * latency
;
269 DPRINTF(HWPrefetch
, "Prefetch queued. "
270 "addr:%#x priority: %3d tick:%lld.\n",
271 target_addr
, priority
, pf_time
);
273 /* Create the packet and find the spot to insert it */
274 DeferredPacket
dpp(new_pfi
, pf_time
, pf_pkt
, priority
);
275 if (pfq
.size() == 0) {
276 pfq
.emplace_back(dpp
);
278 iterator it
= pfq
.end();
281 } while (it
!= pfq
.begin() && dpp
> *it
);
282 /* If we reach the head, we have to see if the new element is new head
284 if (it
== pfq
.begin() && dpp
<= *it
)