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.
29 #include "mem/cache/prefetch/pif.hh"
33 #include "debug/HWPrefetch.hh"
34 #include "mem/cache/prefetch/associative_set_impl.hh"
35 #include "params/PIFPrefetcher.hh"
37 namespace Prefetcher
{
39 PIF::PIF(const PIFPrefetcherParams
&p
)
41 precSize(p
.prec_spatial_region_bits
),
42 succSize(p
.succ_spatial_region_bits
),
43 maxCompactorEntries(p
.compactor_entries
),
44 historyBuffer(p
.history_buffer_size
),
45 index(p
.index_assoc
, p
.index_entries
, p
.index_indexing_policy
,
46 p
.index_replacement_policy
),
47 streamAddressBuffer(p
.stream_address_buffer_entries
),
52 PIF::CompactorEntry::CompactorEntry(Addr addr
,
53 unsigned int prec_size
, unsigned int succ_size
)
56 prec
.resize(prec_size
, false);
57 succ
.resize(succ_size
, false);
61 PIF::CompactorEntry::distanceFromTrigger(Addr target
,
62 unsigned int log_blk_size
) const
64 const Addr target_blk
= target
>> log_blk_size
;
65 const Addr trigger_blk
= trigger
>> log_blk_size
;
67 return target_blk
> trigger_blk
?
68 target_blk
- trigger_blk
: trigger_blk
- target_blk
;
72 PIF::CompactorEntry::inSameSpatialRegion(Addr pc
,
73 unsigned int log_blk_size
, bool update
)
75 Addr blk_distance
= distanceFromTrigger(pc
, log_blk_size
);
77 bool hit
= (pc
> trigger
) ?
78 (succ
.size() > blk_distance
) : (prec
.size() > blk_distance
);
81 succ
[blk_distance
] = true;
82 } else if (pc
< trigger
) {
83 prec
[blk_distance
] = true;
90 PIF::CompactorEntry::hasAddress(Addr target
,
91 unsigned int log_blk_size
) const
93 Addr blk_distance
= distanceFromTrigger(target
, log_blk_size
);
95 if (target
> trigger
) {
96 hit
= blk_distance
< succ
.size() && succ
[blk_distance
];
97 } else if (target
< trigger
) {
98 hit
= blk_distance
< prec
.size() && prec
[blk_distance
];
106 PIF::CompactorEntry::getPredictedAddresses(unsigned int log_blk_size
,
107 std::vector
<AddrPriority
> &addresses
) const
109 // Calculate the addresses of the instruction blocks that are encoded
110 // by the bit vector and issue prefetch requests for these addresses.
111 // Predictions are made by traversing the bit vector from left to right
112 // as this typically predicts the accesses in the order they will be
113 // issued in the core.
114 const Addr trigger_blk
= trigger
>> log_blk_size
;
115 for (int i
= prec
.size()-1; i
>= 0; i
--) {
116 // Address from the preceding blocks to issue a prefetch
118 const Addr prec_addr
= (trigger_blk
- (i
+1)) << log_blk_size
;
119 addresses
.push_back(AddrPriority(prec_addr
, 0));
122 for (int i
= 0; i
< succ
.size(); i
++) {
123 // Address from the succeding blocks to issue a prefetch
125 const Addr succ_addr
= (trigger_blk
+ (i
+1)) << log_blk_size
;
126 addresses
.push_back(AddrPriority(succ_addr
, 0));
132 PIF::notifyRetiredInst(const Addr pc
)
134 // First access to the prefetcher
135 if (temporalCompactor
.size() == 0) {
136 spatialCompactor
= CompactorEntry(pc
, precSize
, succSize
);
137 temporalCompactor
.push_back(spatialCompactor
);
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 'iterator' table to point to the new entry
173 historyBuffer
.push_back(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
->historyIt
=
186 historyBuffer
.getIterator(historyBuffer
.tail());
188 // Reset the spatial compactor fields with the new address
189 spatialCompactor
= CompactorEntry(pc
, precSize
, succSize
);
196 PIF::calculatePrefetch(const PrefetchInfo
&pfi
,
197 std::vector
<AddrPriority
> &addresses
)
203 const Addr pc
= pfi
.getPC();
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(pc
, lBlkSize
)) {
210 sabEntry
->getPredictedAddresses(lBlkSize
, addresses
);
216 // Check if a valid entry in the 'index' table is found and allocate a new
217 // active prediction stream
218 IndexEntry
*idx_entry
= index
.findEntry(pc
, /* unused */ false);
220 if (idx_entry
!= nullptr) {
221 index
.accessEntry(idx_entry
);
222 // Trigger address from the 'index' table and index to the history
224 auto entry
= idx_entry
->historyIt
;
226 // Track the block in the Stream Address Buffer
227 streamAddressBuffer
.push_back(entry
);
229 entry
->getPredictedAddresses(lBlkSize
, addresses
);
234 PIF::PrefetchListenerPC::notify(const Addr
& pc
)
236 parent
.notifyRetiredInst(pc
);
240 PIF::addEventProbeRetiredInsts(SimObject
*obj
, const char *name
)
242 ProbeManager
*pm(obj
->getProbeManager());
243 listenersPC
.push_back(new PrefetchListenerPC(*this, pm
, name
));
246 } // namespace Prefetcher
249 PIFPrefetcherParams::create() const
251 return new Prefetcher::PIF(*this);