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
)
69 // Verify this access type is observed by prefetcher
70 if (observeAccess(pkt
)) {
71 Addr blk_addr
= pkt
->getBlockAddr(blkSize
);
72 bool is_secure
= pkt
->isSecure();
74 // Squash queued prefetches if demand miss to same line
76 auto itr
= pfq
.begin();
77 while (itr
!= pfq
.end()) {
78 if (itr
->pkt
->getAddr() == blk_addr
&&
79 itr
->pkt
->isSecure() == is_secure
) {
88 // Calculate prefetches given this access
89 std::vector
<AddrPriority
> addresses
;
90 calculatePrefetch(pkt
, addresses
);
92 // Queue up generated prefetches
93 for (AddrPriority
& pf_info
: addresses
) {
95 // Block align prefetch address
96 pf_info
.first
&= ~(Addr
)(blkSize
- 1);
99 DPRINTF(HWPrefetch
, "Found a pf candidate addr: %#x, "
100 "inserting into prefetch queue.\n", pf_info
.first
);
102 // Create and insert the request
103 PacketPtr pf_pkt
= insert(pf_info
, is_secure
);
105 if (pf_pkt
!= nullptr) {
106 if (tagPrefetch
&& pkt
->req
->hasPC()) {
107 // Tag prefetch packet with accessing pc
108 pf_pkt
->req
->setPC(pkt
->req
->getPC());
114 return pfq
.empty() ? MaxTick
: pfq
.front().tick
;
118 QueuedPrefetcher::getPacket()
120 DPRINTF(HWPrefetch
, "Requesting a prefetch to issue.\n");
123 DPRINTF(HWPrefetch
, "No hardware prefetches available.\n");
127 PacketPtr pkt
= pfq
.begin()->pkt
;
131 assert(pkt
!= nullptr);
132 DPRINTF(HWPrefetch
, "Generating prefetch for %#x.\n", pkt
->getAddr());
136 std::list
<QueuedPrefetcher::DeferredPacket
>::const_iterator
137 QueuedPrefetcher::inPrefetch(Addr address
, bool is_secure
) const
139 for (const_iterator dp
= pfq
.begin(); dp
!= pfq
.end(); dp
++) {
140 if ((*dp
).pkt
->getAddr() == address
&&
141 (*dp
).pkt
->isSecure() == is_secure
) return dp
;
147 QueuedPrefetcher::iterator
148 QueuedPrefetcher::inPrefetch(Addr address
, bool is_secure
)
150 for (iterator dp
= pfq
.begin(); dp
!= pfq
.end(); dp
++) {
151 if (dp
->pkt
->getAddr() == address
&&
152 dp
->pkt
->isSecure() == is_secure
) return dp
;
159 QueuedPrefetcher::regStats()
161 BasePrefetcher::regStats();
164 .name(name() + ".pfIdentified")
165 .desc("number of prefetch candidates identified");
168 .name(name() + ".pfBufferHit")
169 .desc("number of redundant prefetches already in prefetch queue");
172 .name(name() + ".pfInCache")
173 .desc("number of redundant prefetches already in cache/mshr dropped");
176 .name(name() + ".pfRemovedFull")
177 .desc("number of prefetches dropped due to prefetch queue size");
180 .name(name() + ".pfSpanPage")
181 .desc("number of prefetches not generated due to page crossing");
185 QueuedPrefetcher::insert(AddrPriority
&pf_info
, bool is_secure
)
188 iterator it
= inPrefetch(pf_info
.first
, is_secure
);
189 /* If the address is already in the queue, update priority and leave */
190 if (it
!= pfq
.end()) {
192 if (it
->priority
< pf_info
.second
) {
193 /* Update priority value and position in the queue */
194 it
->priority
= pf_info
.second
;
197 while (cont
&& prev
!= pfq
.begin()) {
199 /* If the packet has higher priority, swap */
201 std::swap(*it
, *prev
);
205 DPRINTF(HWPrefetch
, "Prefetch addr already in "
206 "prefetch queue, priority updated\n");
208 DPRINTF(HWPrefetch
, "Prefetch addr already in "
215 if (cacheSnoop
&& (inCache(pf_info
.first
, is_secure
) ||
216 inMissQueue(pf_info
.first
, is_secure
))) {
218 DPRINTF(HWPrefetch
, "Dropping redundant in "
219 "cache/MSHR prefetch addr:%#x\n", pf_info
.first
);
223 /* Create a prefetch memory request */
225 std::make_shared
<Request
>(pf_info
.first
, blkSize
, 0, masterId
);
228 pf_req
->setFlags(Request::SECURE
);
230 pf_req
->taskId(ContextSwitchTaskId::Prefetcher
);
231 PacketPtr pf_pkt
= new Packet(pf_req
, MemCmd::HardPFReq
);
234 /* Verify prefetch buffer space for request */
235 if (pfq
.size() == queueSize
) {
237 /* Lowest priority packet */
238 iterator it
= pfq
.end();
239 panic_if (it
== pfq
.begin(), "Prefetch queue is both full and empty!");
241 /* Look for oldest in that level of priority */
242 panic_if (it
== pfq
.begin(), "Prefetch queue is full with 1 element!");
245 /* While not at the head of the queue */
246 while (cont
&& prev
!= pfq
.begin()) {
248 /* While at the same level of priority */
249 cont
= (*prev
).priority
== (*it
).priority
;
254 DPRINTF(HWPrefetch
, "Prefetch queue full, removing lowest priority "
255 "oldest packet, addr: %#x", it
->pkt
->getAddr());
260 Tick pf_time
= curTick() + clockPeriod() * latency
;
261 DPRINTF(HWPrefetch
, "Prefetch queued. "
262 "addr:%#x priority: %3d tick:%lld.\n",
263 pf_info
.first
, pf_info
.second
, pf_time
);
265 /* Create the packet and find the spot to insert it */
266 DeferredPacket
dpp(pf_time
, pf_pkt
, pf_info
.second
);
267 if (pfq
.size() == 0) {
268 pfq
.emplace_back(dpp
);
270 iterator it
= pfq
.end();
271 while (it
!= pfq
.begin() && dpp
> *it
)
273 /* If we reach the head, we have to see if the new element is new head
275 if (it
== pfq
.begin() && dpp
<= *it
)