2 * Copyright (c) 2019 Metempsy Technology Consulting
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.
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.
28 * Authors: Ivan Pizarro
31 #include "mem/cache/prefetch/pif.hh"
35 #include "debug/HWPrefetch.hh"
36 #include "mem/cache/prefetch/associative_set_impl.hh"
37 #include "params/PIFPrefetcher.hh"
39 PIFPrefetcher::PIFPrefetcher(const PIFPrefetcherParams
*p
)
40 : QueuedPrefetcher(p
),
41 precSize(p
->prec_spatial_region_bits
),
42 succSize(p
->succ_spatial_region_bits
),
43 maxCompactorEntries(p
->compactor_entries
),
44 maxStreamAddressBufferEntries(p
->stream_address_buffer_entries
),
45 historyBuffer(p
->history_buffer_size
),
47 index(p
->index_assoc
, p
->index_entries
, p
->index_indexing_policy
,
48 p
->index_replacement_policy
),
49 streamAddressBuffer(), listenersPC()
53 PIFPrefetcher::CompactorEntry::CompactorEntry(Addr addr
,
54 unsigned int prec_size
, unsigned int succ_size
)
57 prec
.resize(prec_size
, false);
58 succ
.resize(succ_size
, false);
62 PIFPrefetcher::CompactorEntry::distanceFromTrigger(Addr target
,
63 unsigned int log_blk_size
) const
65 const Addr target_blk
= target
>> log_blk_size
;
66 const Addr trigger_blk
= trigger
>> log_blk_size
;
68 return target_blk
> trigger_blk
?
69 target_blk
- trigger_blk
: trigger_blk
- target_blk
;
73 PIFPrefetcher::CompactorEntry::inSameSpatialRegion(Addr pc
,
74 unsigned int log_blk_size
, bool update
)
76 Addr blk_distance
= distanceFromTrigger(pc
, log_blk_size
);
78 bool hit
= (pc
> trigger
) ?
79 (succ
.size() >= blk_distance
) : (prec
.size() >= blk_distance
);
82 succ
[blk_distance
- 1] = true;
83 } else if (pc
< trigger
) {
84 prec
[blk_distance
- 1] = true;
91 PIFPrefetcher::CompactorEntry::hasAddress(Addr target
,
92 unsigned int log_blk_size
) const
94 Addr blk_distance
= distanceFromTrigger(target
, log_blk_size
);
96 if (target
> trigger
) {
97 hit
= blk_distance
<= succ
.size() && succ
[blk_distance
- 1];
98 } else if (target
< trigger
) {
99 hit
= blk_distance
<= prec
.size() && succ
[blk_distance
- 1];
107 PIFPrefetcher::CompactorEntry::getPredictedAddresses(unsigned int log_blk_size
,
108 std::vector
<AddrPriority
> &addresses
) const
110 // Calculate the addresses of the instruction blocks that are encoded
111 // by the bit vector and issue prefetch requests for these addresses.
112 // Predictions are made by traversing the bit vector from left to right
113 // as this typically predicts the accesses in the order they will be
114 // issued in the core.
115 const Addr trigger_blk
= trigger
>> log_blk_size
;
116 for (int i
= prec
.size()-1; i
>= 0; i
--) {
117 // Address from the preceding blocks to issue a prefetch
119 const Addr prec_addr
= (trigger_blk
- (i
+1)) << log_blk_size
;
120 addresses
.push_back(AddrPriority(prec_addr
, 0));
123 for (int i
= 0; i
< succ
.size(); i
++) {
124 // Address from the succeding blocks to issue a prefetch
126 const Addr succ_addr
= (trigger_blk
+ (i
+1)) << log_blk_size
;
127 addresses
.push_back(AddrPriority(succ_addr
, 0));
133 PIFPrefetcher::notifyRetiredInst(const Addr pc
)
135 // First access to the prefetcher
136 if (temporalCompactor
.size() == 0) {
137 spatialCompactor
= CompactorEntry(pc
, precSize
, succSize
);
139 // If the PC of the instruction retired is in the same spatial region
140 // than the last trigger address, update the bit vectors based on the
141 // distance between them
142 if (spatialCompactor
.inSameSpatialRegion(pc
, lBlkSize
, true)) {
143 // If the PC of the instruction retired is outside the latest spatial
144 // region, check if it matches in any of the regions in the temporal
145 // compactor and update it to the MRU position
147 bool is_in_temporal_compactor
= false;
149 // Check if the PC is in the temporal compactor
150 for (auto it
= temporalCompactor
.begin();
151 it
!= temporalCompactor
.end(); it
++)
153 if (it
->inSameSpatialRegion(pc
, lBlkSize
, false)) {
154 spatialCompactor
= (*it
);
155 temporalCompactor
.erase(it
);
156 is_in_temporal_compactor
= true;
161 if (temporalCompactor
.size() == maxCompactorEntries
) {
162 temporalCompactor
.pop_front(); // Discard the LRU entry
165 temporalCompactor
.push_back(spatialCompactor
);
167 // If the compactor entry is neither the spatial or can't be
168 // found in the temporal compactor, reset the spatial compactor
169 // updating the trigger address and resetting the vector bits
170 if (!is_in_temporal_compactor
) {
171 // Insert the spatial entry into the history buffer and update
172 // the 'index' table to point to the new entry
173 historyBuffer
[historyBufferTail
] = spatialCompactor
;
175 IndexEntry
*idx_entry
=
176 index
.findEntry(spatialCompactor
.trigger
, false);
177 if (idx_entry
!= nullptr) {
178 index
.accessEntry(idx_entry
);
180 idx_entry
= index
.findVictim(spatialCompactor
.trigger
);
181 assert(idx_entry
!= nullptr);
182 index
.insertEntry(spatialCompactor
.trigger
, false,
185 idx_entry
->historyIndex
= historyBufferTail
;
188 if (historyBufferTail
== historyBuffer
.size()) {
189 historyBufferTail
= 0;
192 // Reset the spatial compactor fields with the new address
193 spatialCompactor
= CompactorEntry(pc
, precSize
, succSize
);
200 PIFPrefetcher::calculatePrefetch(const PrefetchInfo
&pfi
,
201 std::vector
<AddrPriority
> &addresses
)
203 const Addr addr
= pfi
.getAddr();
205 // First check if the access has been prefetched, this is done by
206 // comparing the access against the active Stream Address Buffers
207 for (auto &sabEntry
: streamAddressBuffer
) {
208 if (sabEntry
->hasAddress(addr
, lBlkSize
)) {
209 // Advance to the next entry (first check if we have reached the
210 // end of the history buffer)
211 if (sabEntry
== &(historyBuffer
[historyBuffer
.size() - 1])) {
212 sabEntry
= &(historyBuffer
[0]);
216 sabEntry
->getPredictedAddresses(lBlkSize
, addresses
);
222 // Check if a valid entry in the 'index' table is found and allocate a new
223 // active prediction stream
224 IndexEntry
*idx_entry
= index
.findEntry(addr
, /* unused */ false);
226 if (idx_entry
!= nullptr) {
227 index
.accessEntry(idx_entry
);
228 // Trigger address from the 'index' table and index to the history
230 const unsigned int hb_entry
= idx_entry
->historyIndex
;
231 CompactorEntry
*entry
= &historyBuffer
[hb_entry
];
233 // Track the block in the Stream Address Buffer
234 if (streamAddressBuffer
.size() == maxStreamAddressBufferEntries
) {
235 streamAddressBuffer
.pop_front();
237 streamAddressBuffer
.push_back(entry
);
239 entry
->getPredictedAddresses(lBlkSize
, addresses
);
244 PIFPrefetcher::PrefetchListenerPC::notify(const Addr
& pc
)
246 parent
.notifyRetiredInst(pc
);
250 PIFPrefetcher::addEventProbeRetiredInsts(SimObject
*obj
, const char *name
)
252 ProbeManager
*pm(obj
->getProbeManager());
253 listenersPC
.push_back(new PrefetchListenerPC(*this, pm
, name
));
257 PIFPrefetcherParams::create()
259 return new PIFPrefetcher(this);